/* $Id$
 * 
 * Copyright 2004 Jasper Huijsmans (jasper@xfce.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.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <math.h>

#include <gtk/gtkimage.h>

#include "xfce_scaled_image.h"

#define DEBUGGING 0


/* Forward declarations */

static void xfce_scaled_image_class_init (XfceScaledImageClass * class);

static void xfce_scaled_image_init (XfceScaledImage * image);

static void xfce_scaled_image_finalize (GObject * object);

static void xfce_scaled_image_size_allocate (GtkWidget * widget,
					     GtkAllocation * allocation);

static gboolean xfce_scaled_image_scale (XfceScaledImage * image);


/* Local data */

static GtkWidgetClass *parent_class = NULL;

GtkType
xfce_scaled_image_get_type (void)
{
    static GtkType scaled_image_type = 0;

    if (!scaled_image_type)
    {
	static const GTypeInfo scaled_image_info = {
	    sizeof (XfceScaledImageClass),
	    NULL,		/* base_init */
	    NULL,		/* base_finalize */
	    (GClassInitFunc) xfce_scaled_image_class_init,
	    NULL,		/* class_finalize */
	    NULL,		/* class_data */
	    sizeof (XfceScaledImage),
	    0,			/* n_preallocs */
	    (GInstanceInitFunc) xfce_scaled_image_init,
	    NULL		/* value_table */
	};

	scaled_image_type =
	    g_type_register_static (GTK_TYPE_IMAGE, "XfceScaledImage",
				    &scaled_image_info, 0);
    }

    return scaled_image_type;
}

static void
xfce_scaled_image_class_init (XfceScaledImageClass * class)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
    GtkObjectClass *object_class;
    GtkWidgetClass *widget_class;

    object_class = (GtkObjectClass *) class;
    widget_class = (GtkWidgetClass *) class;
    gobject_class = G_OBJECT_CLASS (class);

    parent_class = gtk_type_class (gtk_image_get_type ());

    widget_class->size_allocate = xfce_scaled_image_size_allocate;

    gobject_class->finalize = xfce_scaled_image_finalize;

    gtk_rc_parse_string ("\n" 
                         "   style \"scaled-image-style\"\n" 
                         "   {\n"
                         "      xthickness=0\n"
                         "      ythickness=0\n" 
                         "   }\n" "\n"
                         "   widget \"*.scaled-image\" style \"scaled-image-style\"\n"
                         "\n");
}

static void
xfce_scaled_image_init (XfceScaledImage * image)
{
    image->width = image->height = -1;
    image->pb = NULL;
}

GtkWidget *
xfce_scaled_image_new (void)
{
    GtkWidget *widget = 
        GTK_WIDGET (g_object_new (xfce_scaled_image_get_type (), NULL));

    gtk_widget_set_name (widget, "scaled-image");
    
    return widget;
}

GtkWidget *
xfce_scaled_image_new_from_pixbuf (GdkPixbuf * pixbuf)
{
    GtkWidget *image;

    image = xfce_scaled_image_new ();
    xfce_scaled_image_set_from_pixbuf (XFCE_SCALED_IMAGE (image), pixbuf);

    return image;
}

void
xfce_scaled_image_set_from_pixbuf (XfceScaledImage * image, GdkPixbuf * pixbuf)
{
    g_return_if_fail (image != NULL);
    g_return_if_fail (XFCE_IS_SCALED_IMAGE (image));

    if (image->pb)
	g_object_unref (image->pb);


    image->pb = pixbuf;
    
    if (image->pb) 
        g_object_ref (image->pb);

    if (image->width > 1)
    {
	xfce_scaled_image_scale (image);
    }
    else
    {
	gtk_image_set_from_pixbuf (GTK_IMAGE (image), image->pb);
    }
}

static void
xfce_scaled_image_finalize (GObject * object)
{
    XfceScaledImage *image;

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

    image = XFCE_SCALED_IMAGE (object);

    if (image->pb)
    {
	g_object_unref (image->pb);
	image->pb = NULL;
    }

    G_OBJECT_CLASS (parent_class)->finalize (object);
}

static gboolean
_image_needs_scaling (XfceScaledImage *image)
{
    GtkAllocation *allocation = &(GTK_WIDGET (image)->allocation);

    /* use two pixel margin to reduce rescaling */
    if (image->width <= allocation->width 
        && image->height <= allocation->height
        && image->width > allocation->width - 2
        && image->height > allocation->height - 2)
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

static void
xfce_scaled_image_size_allocate (GtkWidget * widget, 
				 GtkAllocation * allocation)
{
    XfceScaledImage *image;

    g_return_if_fail (widget != NULL);
    g_return_if_fail (XFCE_IS_SCALED_IMAGE (widget));
    g_return_if_fail (allocation != NULL);

    image = XFCE_SCALED_IMAGE (widget);

    widget->allocation = *allocation;

    if (_image_needs_scaling (image))
    {
	image->width = allocation->width;
	image->height = allocation->height;

	xfce_scaled_image_scale (image);
    }
    
    GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);

#if DEBUGGING
    g_print (" ** xfce_scaled_image.c: allocated size: %d x %d\n",
	     widget->allocation.width,
	     widget->allocation.height);
#endif
}

/* returns TRUE when image is set, FALSE otherwise */
static gboolean
xfce_scaled_image_scale (XfceScaledImage * image)
{
    GdkPixbuf *tmp;
    double wratio, hratio;
    int w, h, pw, ph;

    if (!image->pb)
       return FALSE;
       
    g_return_val_if_fail (GDK_IS_PIXBUF (image->pb), FALSE);

    pw = gdk_pixbuf_get_width (image->pb);
    ph = gdk_pixbuf_get_height (image->pb);

    w = image->width <= 1 ? pw : image->width;
    h = image->height <= 1 ? ph : image->height;

    if (w >= pw && h >= ph)
    {
#if DEBUGGING
	g_print (" ** xfce_scaled_image.c: don't scale: %d x %d\n", pw, ph);
#endif
	/* don't scale up -> ugly icons */ 
	gtk_image_set_from_pixbuf (GTK_IMAGE (image), image->pb);
    }
    else
    {
	wratio = (double) pw / w;
	hratio = (double) ph / h;

	if (wratio > hratio)
	    h = rint ((double) ph / wratio);
	else if (hratio > wratio)
	    w = rint ((double) pw / hratio);

#if DEBUGGING
	g_print (" ** xfce_scaled_image.c: scale image: %d x %d\n", w, h);
#endif
	tmp = gdk_pixbuf_scale_simple (image->pb, w, h,
				       GDK_INTERP_BILINEAR);
	
	gtk_image_set_from_pixbuf (GTK_IMAGE (image), tmp);
	
	g_object_unref (tmp);
    }

    return TRUE;
}

