/*
 * Copyright (c) 2004 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "sgtk-cell-renderer-pixbuf.h"

/*** type definitions ********************************************************/

enum {
  PROP_0,
  PROP_STOCK_ID_OPEN,
  PROP_STOCK_SIZE_OPEN,
  PROP_STOCK_DETAIL_OPEN,
  PROP_STOCK_ID_CLOSED,
  PROP_STOCK_SIZE_CLOSED,
  PROP_STOCK_DETAIL_CLOSED
};

struct _sGtkCellRendererPixbufPrivate
{
  gboolean	open_set;
  char		*stock_id_open;
  GtkIconSize	stock_size_open;
  char		*stock_detail_open;

  gboolean	closed_set;
  char		*stock_id_closed;
  GtkIconSize	stock_size_closed;
  char		*stock_detail_closed;
};

/*** variable declarations ***************************************************/

static GObjectClass *parent_class = NULL;

/*** function declarations ***************************************************/

static void sgtk_cell_renderer_pixbuf_class_init (sGtkCellRendererPixbufClass *class);
static void sgtk_cell_renderer_pixbuf_init (sGtkCellRendererPixbuf *cell);
static void sgtk_cell_renderer_pixbuf_finalize (GObject *object);
static void sgtk_cell_renderer_pixbuf_set_property (GObject *object,
						    unsigned int prop_id,
						    const GValue *value,
						    GParamSpec *pspec);
static void sgtk_cell_renderer_pixbuf_get_property (GObject *object,
						    unsigned int prop_id,
						    GValue *value,
						    GParamSpec *pspec);

static void sgtk_cell_renderer_pixbuf_set_pixbuf (sGtkCellRendererPixbuf *cell,
						  GtkWidget *widget,
						  const char *prop,
						  const char *stock_id,
						  GtkIconSize size,
						  const char *detail);
static void sgtk_cell_renderer_pixbuf_set_pixbufs (sGtkCellRendererPixbuf *cell,
						   GtkWidget *widget);

static void sgtk_cell_renderer_pixbuf_get_size (GtkCellRenderer *cell,
						GtkWidget *widget,
						GdkRectangle *cell_area,
						int *x_offset,
						int *y_offset,
						int *width,
						int *height);
static void sgtk_cell_renderer_pixbuf_render (GtkCellRenderer *cell,
					      GdkWindow *window,
					      GtkWidget *widget,
					      GdkRectangle *background_area,
					      GdkRectangle *cell_area,
					      GdkRectangle *expose_area,
					      GtkCellRendererState flags);

/*** implementation **********************************************************/

GType
sgtk_cell_renderer_pixbuf_get_type (void)
{
  static GType type = 0;
  
  if (! type)
    {
      static const GTypeInfo info = {
	sizeof(sGtkCellRendererPixbufClass),
	NULL,
	NULL,
	(GClassInitFunc) sgtk_cell_renderer_pixbuf_class_init,
	NULL,
	NULL,
	sizeof(sGtkCellRendererPixbuf),
	0,
	(GInstanceInitFunc) sgtk_cell_renderer_pixbuf_init
      };
      
      type = g_type_register_static(GTK_TYPE_CELL_RENDERER_PIXBUF,
				    "sGtkCellRendererPixbuf",
				    &info,
				    0);
    }

  return type;
}

static void
sgtk_cell_renderer_pixbuf_class_init (sGtkCellRendererPixbufClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);

  parent_class = g_type_class_peek_parent(class);

  g_type_class_add_private(class, sizeof(sGtkCellRendererPixbufPrivate));

  object_class->finalize = sgtk_cell_renderer_pixbuf_finalize;
  object_class->set_property = sgtk_cell_renderer_pixbuf_set_property;
  object_class->get_property = sgtk_cell_renderer_pixbuf_get_property;

  cell_class->get_size = sgtk_cell_renderer_pixbuf_get_size;
  cell_class->render = sgtk_cell_renderer_pixbuf_render;

  g_object_class_install_property(object_class,
				  PROP_STOCK_ID_OPEN,
				  g_param_spec_string("stock-id-open",
						      NULL,
						      NULL,
						      NULL,
						      G_PARAM_READWRITE));
  g_object_class_install_property(object_class,
				  PROP_STOCK_SIZE_OPEN,
				  g_param_spec_enum("stock-size-open",
						    NULL,
						    NULL,
						    GTK_TYPE_ICON_SIZE,
						    GTK_ICON_SIZE_MENU,
						    G_PARAM_READWRITE));
  g_object_class_install_property(object_class,
				  PROP_STOCK_DETAIL_OPEN,
				  g_param_spec_string("stock-detail-open",
						      NULL,
						      NULL,
						      NULL,
						      G_PARAM_READWRITE));
  g_object_class_install_property(object_class,
				  PROP_STOCK_ID_CLOSED,
				  g_param_spec_string("stock-id-closed",
						      NULL,
						      NULL,
						      NULL,
						      G_PARAM_READWRITE));
  g_object_class_install_property(object_class,
				  PROP_STOCK_SIZE_CLOSED,
				  g_param_spec_enum("stock-size-closed",
						    NULL,
						    NULL,
						    GTK_TYPE_ICON_SIZE,
						    GTK_ICON_SIZE_MENU,
						    G_PARAM_READWRITE));
  g_object_class_install_property(object_class,
				  PROP_STOCK_DETAIL_CLOSED,
				  g_param_spec_string("stock-detail-closed",
						      NULL,
						      NULL,
						      NULL,
						      G_PARAM_READWRITE));
}

static void
sgtk_cell_renderer_pixbuf_init (sGtkCellRendererPixbuf *cell)
{
  cell->priv = G_TYPE_INSTANCE_GET_PRIVATE(cell, SGTK_TYPE_CELL_RENDERER_PIXBUF, sGtkCellRendererPixbufPrivate);
  cell->priv->stock_size_open = GTK_ICON_SIZE_MENU;
  cell->priv->stock_size_closed = GTK_ICON_SIZE_MENU;
}

static void
sgtk_cell_renderer_pixbuf_finalize (GObject *object)
{
  sGtkCellRendererPixbuf *cell = SGTK_CELL_RENDERER_PIXBUF(object);

  g_free(cell->priv->stock_id_open);
  g_free(cell->priv->stock_detail_open);
  g_free(cell->priv->stock_id_closed);
  g_free(cell->priv->stock_detail_closed);

  parent_class->finalize(object);
}

static void
sgtk_cell_renderer_pixbuf_set_property (GObject *object,
					unsigned int prop_id,
					const GValue *value,
					GParamSpec *pspec)
{
  sGtkCellRendererPixbuf *cell = SGTK_CELL_RENDERER_PIXBUF(object);

  switch (prop_id)
    {
    case PROP_STOCK_ID_OPEN:
      g_free(cell->priv->stock_id_open);
      cell->priv->stock_id_open = g_value_dup_string(value);
      cell->priv->open_set = FALSE;
      break;

    case PROP_STOCK_SIZE_OPEN:
      cell->priv->stock_size_open = g_value_get_enum(value);
      cell->priv->open_set = FALSE;
      break;

    case PROP_STOCK_DETAIL_OPEN:
      g_free(cell->priv->stock_detail_open);
      cell->priv->stock_detail_open = g_value_dup_string(value);
      cell->priv->open_set = FALSE;
      break;

    case PROP_STOCK_ID_CLOSED:
      g_free(cell->priv->stock_id_closed);
      cell->priv->stock_id_closed = g_value_dup_string(value);
      cell->priv->closed_set = FALSE;
      break;

    case PROP_STOCK_SIZE_CLOSED:
      cell->priv->stock_size_closed = g_value_get_enum(value);
      cell->priv->closed_set = FALSE;
      break;

    case PROP_STOCK_DETAIL_CLOSED:
      g_free(cell->priv->stock_detail_closed);
      cell->priv->stock_detail_closed = g_value_dup_string(value);
      cell->priv->closed_set = FALSE;
      break;

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

static void
sgtk_cell_renderer_pixbuf_get_property (GObject *object,
					unsigned int prop_id,
					GValue *value,
					GParamSpec *pspec)
{
  sGtkCellRendererPixbuf *cell = SGTK_CELL_RENDERER_PIXBUF(object);

  switch (prop_id)
    {
    case PROP_STOCK_ID_OPEN:
      g_value_set_string(value, cell->priv->stock_id_open);
      break;

    case PROP_STOCK_SIZE_OPEN:
      g_value_set_enum(value, cell->priv->stock_size_open);
      break;

    case PROP_STOCK_DETAIL_OPEN:
      g_value_set_string(value, cell->priv->stock_detail_open);
      break;

    case PROP_STOCK_ID_CLOSED:
      g_value_set_string(value, cell->priv->stock_id_closed);
      break;

    case PROP_STOCK_SIZE_CLOSED:
      g_value_set_enum(value, cell->priv->stock_size_closed);
      break;

    case PROP_STOCK_DETAIL_CLOSED:
      g_value_set_string(value, cell->priv->stock_detail_closed);
      break;

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

static void
sgtk_cell_renderer_pixbuf_set_pixbuf (sGtkCellRendererPixbuf *cell,
				      GtkWidget *widget,
				      const char *prop,
				      const char *stock_id,
				      GtkIconSize size,
				      const char *detail)
{
  GdkPixbuf *pixbuf;

  g_return_if_fail(SGTK_IS_CELL_RENDERER_PIXBUF(cell));
  g_return_if_fail(GTK_IS_WIDGET(widget));
  g_return_if_fail(prop != NULL);
  g_return_if_fail(stock_id != NULL);

  pixbuf = gtk_widget_render_icon(widget, stock_id, size, detail);
  g_object_set(G_OBJECT(cell), prop, pixbuf, NULL);
  g_object_unref(pixbuf);
}

static void
sgtk_cell_renderer_pixbuf_set_pixbufs (sGtkCellRendererPixbuf *cell,
				       GtkWidget *widget)
{
  g_return_if_fail(SGTK_IS_CELL_RENDERER_PIXBUF(cell));
  g_return_if_fail(GTK_IS_WIDGET(widget));

  if (! cell->priv->open_set && cell->priv->stock_id_open)
    {
      sgtk_cell_renderer_pixbuf_set_pixbuf(cell,
					   widget,
					   "pixbuf-expander-open",
					   cell->priv->stock_id_open,
					   cell->priv->stock_size_open,
					   cell->priv->stock_detail_open);
      cell->priv->open_set = TRUE;
    }
  if (! cell->priv->closed_set && cell->priv->stock_id_closed)
    {
      sgtk_cell_renderer_pixbuf_set_pixbuf(cell,
					   widget,
					   "pixbuf-expander-closed",
					   cell->priv->stock_id_closed,
					   cell->priv->stock_size_closed,
					   cell->priv->stock_detail_closed);
      cell->priv->closed_set = TRUE;
    }
}

static void
sgtk_cell_renderer_pixbuf_get_size (GtkCellRenderer *cell,
				    GtkWidget *widget,
				    GdkRectangle *cell_area,
				    int *x_offset,
				    int *y_offset,
				    int *width,
				    int *height)
{
  sgtk_cell_renderer_pixbuf_set_pixbufs(SGTK_CELL_RENDERER_PIXBUF(cell), widget);

  GTK_CELL_RENDERER_CLASS(parent_class)->get_size(cell,
						  widget,
						  cell_area,
						  x_offset,
						  y_offset,
						  width,
						  height);
}

static void
sgtk_cell_renderer_pixbuf_render (GtkCellRenderer *cell,
				  GdkWindow *window,
				  GtkWidget *widget,
				  GdkRectangle *background_area,
				  GdkRectangle *cell_area,
				  GdkRectangle *expose_area,
				  GtkCellRendererState flags)
{
  sgtk_cell_renderer_pixbuf_set_pixbufs(SGTK_CELL_RENDERER_PIXBUF(cell), widget);

  GTK_CELL_RENDERER_CLASS(parent_class)->render(cell,
						window,
						widget,
						background_area,
						cell_area,
						expose_area,
						flags);
}

GtkCellRenderer *
sgtk_cell_renderer_pixbuf_new (void)
{
  return g_object_new(SGTK_TYPE_CELL_RENDERER_PIXBUF, NULL);
}
