aboutsummaryrefslogblamecommitdiffstats
path: root/libgnomecanvas/gnome-canvas-pixbuf.c
blob: 017ee26622638a730db9f5f2e4249427045d3436 (plain) (tree)


























                                                                    


                                                     
                                  

                            
  



                         
                   

  
                                                                  








                                                                  
                                                                                                      
                                                                                   
                                                                               




                                                                         
                                                              
                                                                                            
 
                                                                              


 




                                                              


                                               

                                                    








                                                                              
 
                                                          

                                                        

                                                        

                                                                            





                                                               
                                       
 


                                                                                   



                                                
                                                     


                               
                                       




                                                           
                                           


                                                          


                                          

         

                                                                                             












                                                               
                                       
                          









                                                           
                                                    
                                             


                                                              
                                                             

                 


                                                        













                                                                            
                                       








                                                           
                                                         

                      









                                                                            




                                                                             
                                               

                              
                                       

                              








                                                                











                                                                      







                                               
                                                  
                                                      
                                       

                               
                                       



                                         
                                                                               
                                                                                                      
 
                                   

                                                                      
                                     

                                                                      



 


                                                                       
                                                                  

                               
                                       

                              






                                         







                                                             
 
                           

 


                                              
                        



                                                 
                                   

                               
                                       


                          




                                         
                          
                            
 

               


                                                            
                            

                                               
                            





                                                    
                            
            
                            





                                               




                                                  

                               
                                       








                                            



                                                   
 
/* GNOME libraries - GdkPixbuf item for the GNOME canvas
 *
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Author: Federico Mena-Quintero <federico@gimp.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <config.h>
#include <math.h>
#include <libgnomecanvas/gnome-canvas.h>
#include <libgnomecanvas/gnome-canvas-util.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "gnome-canvas-pixbuf.h"

/* Private part of the GnomeCanvasPixbuf structure */
struct _GnomeCanvasPixbufPrivate {
    /* Our gdk-pixbuf */
    GdkPixbuf *pixbuf;
};

/* Object argument IDs */
enum {
    PROP_0,
    PROP_PIXBUF
};

static void gnome_canvas_pixbuf_destroy (GnomeCanvasItem *object);
static void gnome_canvas_pixbuf_set_property (GObject *object,
                          guint param_id,
                          const GValue *value,
                          GParamSpec *pspec);
static void gnome_canvas_pixbuf_get_property (GObject *object,
                          guint param_id,
                          GValue *value,
                          GParamSpec *pspec);

static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, const cairo_matrix_t *i2c, gint flags);
static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
                      gint x, gint y, gint width, gint height);
static GnomeCanvasItem *gnome_canvas_pixbuf_point (GnomeCanvasItem *item,
                                                   gdouble x,
                                                   gdouble y,
                                                   gint cx,
                                                   gint cy);
static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
                    gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2);

G_DEFINE_TYPE (GnomeCanvasPixbuf, gnome_canvas_pixbuf, GNOME_TYPE_CANVAS_ITEM)



/* Class initialization function for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class)
{
        GObjectClass *gobject_class;
    GnomeCanvasItemClass *item_class;

        gobject_class = (GObjectClass *) class;
    item_class = (GnomeCanvasItemClass *) class;

    gobject_class->set_property = gnome_canvas_pixbuf_set_property;
    gobject_class->get_property = gnome_canvas_pixbuf_get_property;

        g_object_class_install_property
                (gobject_class,
                 PROP_PIXBUF,
                 g_param_spec_object ("pixbuf", NULL, NULL,
                                      GDK_TYPE_PIXBUF,
                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));

    item_class->destroy = gnome_canvas_pixbuf_destroy;
    item_class->update = gnome_canvas_pixbuf_update;
    item_class->draw = gnome_canvas_pixbuf_draw;
    item_class->point = gnome_canvas_pixbuf_point;
    item_class->bounds = gnome_canvas_pixbuf_bounds;

        g_type_class_add_private (class, sizeof (GnomeCanvasPixbufPrivate));
}

/* Object initialization function for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp)
{
    GnomeCanvasPixbufPrivate *priv;

    priv = gcp->priv =  G_TYPE_INSTANCE_GET_PRIVATE (gcp,
                                                         GNOME_TYPE_CANVAS_PIXBUF,
                                                         GnomeCanvasPixbufPrivate);
}

/* Destroy handler for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_destroy (GnomeCanvasItem *object)
{
    GnomeCanvasItem *item;
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;

    g_return_if_fail (object != NULL);
    g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));

    item = GNOME_CANVAS_ITEM (object);
    gcp = GNOME_CANVAS_PIXBUF (object);
    priv = gcp->priv;

    /* remember, destroy can be run multiple times! */
        if (priv->pixbuf) {
            g_object_unref (priv->pixbuf);
            priv->pixbuf = NULL;
    }

    if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->destroy)
        GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->destroy (object);
}



/* Set_property handler for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_set_property (GObject            *object,
                  guint               param_id,
                  const GValue       *value,
                  GParamSpec         *pspec)
{
    GnomeCanvasItem *item;
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;
    GdkPixbuf *pixbuf;

    g_return_if_fail (object != NULL);
    g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));

    item = GNOME_CANVAS_ITEM (object);
    gcp = GNOME_CANVAS_PIXBUF (object);
    priv = gcp->priv;

    switch (param_id) {
    case PROP_PIXBUF:
        pixbuf = g_value_get_object (value);
        if (pixbuf != priv->pixbuf) {
            if (priv->pixbuf)
                g_object_unref (priv->pixbuf);

            priv->pixbuf = g_object_ref (pixbuf);
        }

        gnome_canvas_item_request_update (item);
        break;

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

/* Get_property handler for the pixbuf canvasi item */
static void
gnome_canvas_pixbuf_get_property (GObject            *object,
                  guint               param_id,
                  GValue             *value,
                  GParamSpec         *pspec)
{
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;

    g_return_if_fail (object != NULL);
    g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));

    gcp = GNOME_CANVAS_PIXBUF (object);
    priv = gcp->priv;

    switch (param_id) {
    case PROP_PIXBUF:
        g_value_set_object (value, priv->pixbuf);
        break;

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



/* Bounds and utilities */

/* Recomputes the bounding box of a pixbuf canvas item.  The horizontal and
 * vertical dimensions may be specified in units or pixels, separately, so we
 * have to compute the components individually for each dimension.
 */
static void
recompute_bounding_box (GnomeCanvasPixbuf *gcp)
{
    GnomeCanvasItem *item;
    GnomeCanvasPixbufPrivate *priv;
    cairo_matrix_t i2c;
        double x1, x2, y1, y2;

    item = GNOME_CANVAS_ITEM (gcp);
    priv = gcp->priv;

    if (!priv->pixbuf) {
        item->x1 = item->y1 = item->x2 = item->y2 = 0.0;
        return;
    }

    x1 = 0.0;
    x2 = gdk_pixbuf_get_width (priv->pixbuf);
    y1 = 0.0;
    y2 = gdk_pixbuf_get_height (priv->pixbuf);

    gnome_canvas_item_i2c_matrix (item, &i2c);
    gnome_canvas_matrix_transform_rect (&i2c, &x1, &y1, &x2, &y2);

    item->x1 = floor (x1);
    item->y1 = floor (y1);
    item->x2 = ceil (x2);
    item->y2 = ceil (y2);
}



/* Update sequence */

/* Update handler for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_update (GnomeCanvasItem *item,
                            const cairo_matrix_t *i2c,
                            gint flags)
{
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;

    gcp = GNOME_CANVAS_PIXBUF (item);
    priv = gcp->priv;

    if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->update)
        GNOME_CANVAS_ITEM_CLASS (gnome_canvas_pixbuf_parent_class)->update (item, i2c, flags);

    /* ordinary update logic */
        gnome_canvas_request_redraw (
        item->canvas, item->x1, item->y1, item->x2, item->y2);
        recompute_bounding_box (gcp);
        gnome_canvas_request_redraw (
        item->canvas, item->x1, item->y1, item->x2, item->y2);
}



/* Draw handler for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
              gint x, gint y, gint width, gint height)
{
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;
        cairo_matrix_t matrix;
        cairo_t *cr;

    gcp = GNOME_CANVAS_PIXBUF (item);
    priv = gcp->priv;

    if (!priv->pixbuf)
        return;

        cr = gdk_cairo_create (drawable);
        gnome_canvas_item_i2c_matrix (item, &matrix);
        if (cairo_matrix_invert (&matrix))
                return;
        cairo_transform (cr, &matrix);
        
        gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, 0, 0);
        cairo_paint (cr);

        cairo_destroy (cr);
}



/* Point handler for the pixbuf canvas item */
static GnomeCanvasItem *
gnome_canvas_pixbuf_point (GnomeCanvasItem *item,
                           gdouble x,
                           gdouble y,
                           gint cx,
                           gint cy)
{
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;
        GdkPixbuf *pixbuf;
        int px, py;
        guchar *src;

    gcp = GNOME_CANVAS_PIXBUF (item);
    priv = gcp->priv;
    pixbuf = priv->pixbuf;

    if (!priv->pixbuf)
        return NULL;

        px = x;
        py = y;

    if (px < 0 || px >= gdk_pixbuf_get_width (pixbuf) ||
        py < 0 || py >= gdk_pixbuf_get_height (pixbuf))
        return NULL;

    if (!gdk_pixbuf_get_has_alpha (pixbuf))
        return item;

    src = gdk_pixbuf_get_pixels (pixbuf) +
        py * gdk_pixbuf_get_rowstride (pixbuf) +
        px * gdk_pixbuf_get_n_channels (pixbuf);

    if (src[3] < 128)
        return NULL;
    else
        return item;
}



/* Bounds handler for the pixbuf canvas item */
static void
gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
                            gdouble *x1,
                            gdouble *y1,
                            gdouble *x2,
                            gdouble *y2)
{
    GnomeCanvasPixbuf *gcp;
    GnomeCanvasPixbufPrivate *priv;

    gcp = GNOME_CANVAS_PIXBUF (item);
    priv = gcp->priv;

    if (!priv->pixbuf) {
        *x1 = *y1 = *x2 = *y2 = 0.0;
        return;
    }

    *x1 = 0;
    *y1 = 0;
    *x2 = gdk_pixbuf_get_width (priv->pixbuf);
    *y2 = gdk_pixbuf_get_height (priv->pixbuf);
}