/* gtkcellrenderertextpixbuf.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
 * 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 <stdlib.h>
#include "gtkcellrenderertextpixbuf.h"

#ifndef _
#define _(x) x
#endif

enum {
  PROP_ZERO,
  PROP_PIXBUF_POS,
  PROP_PIXBUF,
  PROP_PIXBUF_XALIGN,
  PROP_PIXBUF_YALIGN,
  PROP_PIXBUF_XPAD,
  PROP_PIXBUF_YPAD
};


static void gtk_cell_renderer_text_pixbuf_get_param  (GObject                        *object,
						      guint                           param_id,
						      GValue                         *value,
						      GParamSpec                     *pspec,
						      const gchar                    *trailer);
static void gtk_cell_renderer_text_pixbuf_set_param  (GObject                        *object,
						      guint                           param_id,
						      GValue                         *value,
						      GParamSpec                     *pspec,
						      const gchar                    *trailer);
static void gtk_cell_renderer_text_pixbuf_init       (GtkCellRendererTextPixbuf      *celltextpixbuf);
static void gtk_cell_renderer_text_pixbuf_class_init (GtkCellRendererTextPixbufClass *class);
static void gtk_cell_renderer_text_pixbuf_get_size   (GtkCellRenderer                *cell,
						      GtkWidget                      *view,
						      gint                           *width,
						      gint                           *height);
static void gtk_cell_renderer_text_pixbuf_render     (GtkCellRenderer                *cell,
						      GdkWindow                      *window,
						      GtkWidget                      *view,
						      GdkRectangle                   *background_area,
						      GdkRectangle                   *cell_area,
						      GdkRectangle                   *expose_area,
						      guint                           flags);


static GtkCellRendererTextClass *parent_class = NULL;


GtkType
gtk_cell_renderer_text_pixbuf_get_type (void)
{
  static GtkType cell_text_pixbuf_type = 0;

  if (!cell_text_pixbuf_type)
    {
      static const GTypeInfo cell_text_pixbuf_info =
      {
        sizeof (GtkCellRendererTextPixbufClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_cell_renderer_text_pixbuf_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkCellRendererTextPixbuf),
	0,              /* n_preallocs */
        (GInstanceInitFunc) gtk_cell_renderer_text_pixbuf_init,
      };

      cell_text_pixbuf_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "GtkCellRendererTextPixbuf", &cell_text_pixbuf_info, 0);
    }

  return cell_text_pixbuf_type;
}

static void
gtk_cell_renderer_text_pixbuf_init (GtkCellRendererTextPixbuf *celltextpixbuf)
{
  celltextpixbuf->pixbuf = GTK_CELL_RENDERER_PIXBUF (gtk_cell_renderer_pixbuf_new ());
  celltextpixbuf->pixbuf_pos = GTK_POS_LEFT;
}

static void
gtk_cell_renderer_text_pixbuf_class_init (GtkCellRendererTextPixbufClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);

  parent_class = g_type_class_peek_parent (class);

  object_class->get_param = gtk_cell_renderer_text_pixbuf_get_param;
  object_class->set_param = gtk_cell_renderer_text_pixbuf_set_param;

  cell_class->get_size = gtk_cell_renderer_text_pixbuf_get_size;
  cell_class->render = gtk_cell_renderer_text_pixbuf_render;

  g_object_class_install_param (object_class,
 				PROP_PIXBUF_POS,
				g_param_spec_int ("pixbufpos",
						  _("Pixbuf location"),
						  _("The relative location of the pixbuf to the text."),
						  GTK_POS_LEFT,
						  GTK_POS_BOTTOM,
						  GTK_POS_LEFT,
						  G_PARAM_READABLE |
						  G_PARAM_WRITABLE));

  g_object_class_install_param (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_param (object_class,
				PROP_PIXBUF_XALIGN,
				g_param_spec_float ("pixbuf xalign",
						    _("pixbuf xalign"),
						    _("The x-align of the pixbuf."),
						    0.0,
						    1.0,
						    0.0,
						    G_PARAM_READABLE |
						    G_PARAM_WRITABLE));

  g_object_class_install_param (object_class,
				PROP_PIXBUF_YALIGN,
				g_param_spec_float ("pixbuf yalign",
						    _("pixbuf yalign"),
						    _("The y-align of the pixbuf."),
						    0.0,
						    1.0,
						    0.5,
						    G_PARAM_READABLE |
						    G_PARAM_WRITABLE));

  g_object_class_install_param (object_class,
				PROP_PIXBUF_XPAD,
				g_param_spec_uint ("pixbuf xpad",
						   _("pixbuf xpad"),
						   _("The xpad of the pixbuf."),
						   0,
						   100,
						   2,
						   G_PARAM_READABLE |
						   G_PARAM_WRITABLE));

  g_object_class_install_param (object_class,
				PROP_PIXBUF_YPAD,
				g_param_spec_uint ("pixbuf ypad",
						   _("pixbuf ypad"),
						   _("The ypad of the pixbuf."),
						   0,
						   100,
						   2,
						   G_PARAM_READABLE |
						   G_PARAM_WRITABLE));
}

static void
gtk_cell_renderer_text_pixbuf_get_param (GObject     *object,
					 guint        param_id,
					 GValue      *value,
					 GParamSpec  *pspec,
					 const gchar *trailer)
{
  GtkCellRendererTextPixbuf *celltextpixbuf = GTK_CELL_RENDERER_TEXT_PIXBUF (object);

  switch (param_id)
    {
    case PROP_PIXBUF_POS:
      g_value_set_int (value, celltextpixbuf->pixbuf_pos);
      break;
    case PROP_PIXBUF:
      g_object_get_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "pixbuf",
			  value);
      break;
    case PROP_PIXBUF_XALIGN:
      g_object_get_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "xalign",
			  value);
      break;
    case PROP_PIXBUF_YALIGN:
      g_object_get_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "yalign",
			  value);
      break;
    case PROP_PIXBUF_XPAD:
      g_object_get_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "xpad",
			  value);
      break;
    case PROP_PIXBUF_YPAD:
      g_object_get_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "ypad",
			  value);
      break;
    default:
      break;
    }
}


static void
gtk_cell_renderer_text_pixbuf_set_param (GObject     *object,
					 guint        param_id,
					 GValue      *value,
					 GParamSpec  *pspec,
					 const gchar *trailer)
{
  GtkCellRendererTextPixbuf *celltextpixbuf = GTK_CELL_RENDERER_TEXT_PIXBUF (object);

  switch (param_id)
    {
    case PROP_PIXBUF:
      g_object_set_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "pixbuf",
			  value);
      break;
    case PROP_PIXBUF_POS:
      celltextpixbuf->pixbuf_pos = g_value_get_int (value);
      break;
    case PROP_PIXBUF_XALIGN:
      g_object_set_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "xalign",
			  value);
      break;
    case PROP_PIXBUF_YALIGN:
      g_object_set_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "yalign",
			  value);
      break;
    case PROP_PIXBUF_XPAD:
      g_object_set_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "xpad",
			  value);
      break;
    case PROP_PIXBUF_YPAD:
      g_object_set_param (G_OBJECT (celltextpixbuf->pixbuf),
			  "ypad",
			  value);
      break;
    default:
      break;
    }
}

GtkCellRenderer *
gtk_cell_renderer_text_pixbuf_new (void)
{
  return GTK_CELL_RENDERER (gtk_type_new (gtk_cell_renderer_text_pixbuf_get_type ()));
}

typedef void (* CellSizeFunc) (GtkCellRenderer    *cell,
			       GtkWidget          *widget,
			       gint               *width,
			       gint               *height);
typedef void (* CellRenderFunc) (GtkCellRenderer *cell,
				 GdkWindow       *window,
				 GtkWidget       *widget,
				 GdkRectangle    *background_area,
				 GdkRectangle    *cell_area,
				 GdkRectangle    *expose_area,
				 guint            flags);

static void
gtk_cell_renderer_text_pixbuf_get_size (GtkCellRenderer *cell,
					GtkWidget       *widget,
					gint            *width,
					gint            *height)
{
  GtkCellRendererTextPixbuf *celltextpixbuf = (GtkCellRendererTextPixbuf *)cell;
  gint pixbuf_width;
  gint pixbuf_height;
  gint text_width;
  gint text_height;

  (* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell, widget, &text_width, &text_height);
  (* GTK_CELL_RENDERER_CLASS (G_OBJECT_GET_CLASS (celltextpixbuf->pixbuf))->get_size) (GTK_CELL_RENDERER (celltextpixbuf->pixbuf),
										       widget,
										       &pixbuf_width,
										       &pixbuf_height);
  if (celltextpixbuf->pixbuf_pos == GTK_POS_LEFT ||
      celltextpixbuf->pixbuf_pos == GTK_POS_RIGHT)
    {
      *width = pixbuf_width + text_width;
      *height = MAX (pixbuf_height, text_height);
    }
  else
    {
      *width = MAX (pixbuf_width, text_width);
      *height = pixbuf_height + text_height;
    }
}

static void
gtk_cell_renderer_text_pixbuf_render (GtkCellRenderer *cell,
				      GdkWindow       *window,
				      GtkWidget       *widget,
				      GdkRectangle    *background_area,
				      GdkRectangle    *cell_area,
				      GdkRectangle    *expose_area,
				      guint            flags)

{
  GtkCellRendererTextPixbuf *celltextpixbuf = (GtkCellRendererTextPixbuf *) cell;
  CellSizeFunc size_func1, size_func2;
  CellRenderFunc render_func1, render_func2;
  GtkCellRenderer *cell1, *cell2;
  gint tmp_width;
  gint tmp_height;
  GdkRectangle real_cell_area;

  if (celltextpixbuf->pixbuf_pos == GTK_POS_LEFT ||
      celltextpixbuf->pixbuf_pos == GTK_POS_TOP)
    {
      size_func1 = GTK_CELL_RENDERER_CLASS (G_OBJECT_GET_CLASS (celltextpixbuf->pixbuf))->get_size;
      render_func1 = GTK_CELL_RENDERER_CLASS (G_OBJECT_GET_CLASS (celltextpixbuf->pixbuf))->render;
      cell1 = GTK_CELL_RENDERER (celltextpixbuf->pixbuf);

      size_func2 = GTK_CELL_RENDERER_CLASS (parent_class)->get_size;
      render_func2 = GTK_CELL_RENDERER_CLASS (parent_class)->render;
      cell2 = cell;
    }
  else
    {
      size_func1 = GTK_CELL_RENDERER_CLASS (parent_class)->get_size;
      render_func1 = GTK_CELL_RENDERER_CLASS (parent_class)->render;
      cell1 = cell;

      size_func2 = GTK_CELL_RENDERER_CLASS (G_OBJECT_GET_CLASS (celltextpixbuf->pixbuf))->get_size;
      render_func2 = GTK_CELL_RENDERER_CLASS (G_OBJECT_GET_CLASS (celltextpixbuf->pixbuf))->render;
      cell2 = GTK_CELL_RENDERER (celltextpixbuf->pixbuf);
    }

  (size_func1) (cell1, widget, &tmp_width, &tmp_height);

  real_cell_area.x = cell_area->x;
  real_cell_area.y = cell_area->y;

  if (celltextpixbuf->pixbuf_pos == GTK_POS_LEFT ||
      celltextpixbuf->pixbuf_pos == GTK_POS_RIGHT)
    {
      real_cell_area.width = MIN (tmp_width, cell_area->width);
      real_cell_area.height = cell_area->height;
    }
  else
    {
      real_cell_area.height = MIN (tmp_height, cell_area->height);
      real_cell_area.width = cell_area->width;
    }

  (render_func1) (cell1,
		  window,
		  widget,
		  background_area,
		  &real_cell_area,
		  expose_area,
		  flags);

  if (celltextpixbuf->pixbuf_pos == GTK_POS_LEFT ||
      celltextpixbuf->pixbuf_pos == GTK_POS_RIGHT)
    {
      real_cell_area.x = real_cell_area.x + real_cell_area.width;
      real_cell_area.width = cell_area->width - real_cell_area.width;
    }
  else
    {
      real_cell_area.y = real_cell_area.y + real_cell_area.height;
      real_cell_area.height = cell_area->height - real_cell_area.height;
    }

  (render_func2 ) (cell2,
		   window,
		   widget,
		   background_area,
		   &real_cell_area,
		   expose_area,
		   flags);
}
