/*
 * Copyright (c) 2011 Red Hat, Inc.
 * Copyright (c) 2012 Igalia, S.L.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Based on gd-toggle-pixbuf-renderer by Cosimo Cecchi <cosimoc@redhat.com>
 *
 */

#include "config.h"

#include "ephy-removable-pixbuf-renderer.h"
#include "ephy-widgets-type-builtins.h"

G_DEFINE_TYPE (EphyRemovablePixbufRenderer, ephy_removable_pixbuf_renderer, GD_TYPE_TOGGLE_PIXBUF_RENDERER);

enum {
  DELETE_CLICKED,
  LAST_SIGNAL
};

enum {
  PROP_0 = 0,
  PROP_RENDER_POLICY
};

static guint signals[LAST_SIGNAL] = { 0 };

struct _EphyRemovablePixbufRendererPrivate {
  EphyRemovablePixbufRenderPolicy policy;
  GdkPixbuf *close_icon;
};

static void
get_icon_rectangle (GtkWidget *widget,
		    GtkCellRenderer *cell,
		    const GdkRectangle *cell_area,
		    GdkPixbuf *icon,
		    GdkRectangle *rectangle)
{
  GtkTextDirection direction;
  gint x_offset, y_offset, xpad, ypad;
  gint icon_size;
  gint w = 0, h = 0;
  GdkPixbuf *pixbuf;

  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
  direction = gtk_widget_get_direction (widget);
  icon_size = gdk_pixbuf_get_width (icon);

  g_object_get (cell, "pixbuf", &pixbuf, NULL);
  if (pixbuf) {
    w = gdk_pixbuf_get_width (pixbuf);
    h = gdk_pixbuf_get_height (pixbuf);
    g_object_unref (pixbuf);
  }

  x_offset = (cell_area->width - w)/2 + 10;
  y_offset = (cell_area->height - h)/2 + 9;

  if (direction == GTK_TEXT_DIR_RTL)
    x_offset += xpad;
  else
    x_offset = cell_area->width - icon_size - xpad - x_offset;

  rectangle->x = cell_area->x + x_offset;
  rectangle->y = cell_area->y + ypad + y_offset;
  rectangle->width = rectangle->height = icon_size;
}

static void
ephy_removable_pixbuf_renderer_render (GtkCellRenderer      *cell,
				       cairo_t              *cr,
				       GtkWidget            *widget,
				       const GdkRectangle   *background_area,
				       const GdkRectangle   *cell_area,
				       GtkCellRendererState  flags)
{
  GtkStyleContext *context;
  EphyRemovablePixbufRenderer *self = EPHY_REMOVABLE_PIXBUF_RENDERER (cell);
  GdkRectangle icon_area;

  GTK_CELL_RENDERER_CLASS (ephy_removable_pixbuf_renderer_parent_class)->render
    (cell, cr, widget,
     background_area, cell_area, flags);

  if (self->priv->policy ==  EPHY_REMOVABLE_PIXBUF_RENDER_NEVER ||
      (self->priv->policy == EPHY_REMOVABLE_PIXBUF_RENDER_PRELIT && !(flags & GTK_CELL_RENDERER_PRELIT)))
    return;

  get_icon_rectangle (widget, cell, cell_area, self->priv->close_icon, &icon_area);
  context = gtk_widget_get_style_context (widget);
  gtk_render_icon (context, cr, self->priv->close_icon, icon_area.x, icon_area.y);
}

static gboolean
ephy_removable_pixbuf_renderer_activate (GtkCellRenderer      *cell,
					 GdkEvent             *event,
					 GtkWidget            *widget,
					 const gchar          *path,
					 const GdkRectangle   *background_area,
					 const GdkRectangle   *cell_area,
					 GtkCellRendererState  flags)
{
  GdkRectangle icon_area;
  GdkEventButton *ev = (GdkEventButton *) gtk_get_current_event();
  EphyRemovablePixbufRendererPrivate *priv = EPHY_REMOVABLE_PIXBUF_RENDERER (cell)->priv;

  if (priv->policy ==  EPHY_REMOVABLE_PIXBUF_RENDER_NEVER)
    return FALSE;

  get_icon_rectangle (widget, cell, cell_area, priv->close_icon, &icon_area);
  if (icon_area.x <= ev->x && ev->x <= icon_area.x + icon_area.width &&
      icon_area.y <= ev->y && ev->y <= icon_area.y + icon_area.height) {
    g_signal_emit (cell, signals [DELETE_CLICKED], 0, path);
    return TRUE;
  }

  return FALSE;
}

static void
ephy_removable_pixbuf_renderer_get_property (GObject    *object,
					     guint       property_id,
					     GValue     *value,
					     GParamSpec *pspec)
{
  EphyRemovablePixbufRenderer *self = EPHY_REMOVABLE_PIXBUF_RENDERER (object);

  switch (property_id)
    {
    case PROP_RENDER_POLICY:
      g_value_set_enum (value, self->priv->policy);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
ephy_removable_pixbuf_renderer_set_property (GObject    *object,
					     guint       property_id,
					     const GValue *value,
					     GParamSpec *pspec)
{
  EphyRemovablePixbufRenderer *self = EPHY_REMOVABLE_PIXBUF_RENDERER (object);

  switch (property_id)
    {
    case PROP_RENDER_POLICY:
      self->priv->policy = g_value_get_enum (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
ephy_removable_pixbuf_renderer_dispose (GObject     *object)
{
  EphyRemovablePixbufRendererPrivate *priv = EPHY_REMOVABLE_PIXBUF_RENDERER (object)->priv;

  if (priv->close_icon)
    g_clear_object (&priv->close_icon);

  G_OBJECT_CLASS (ephy_removable_pixbuf_renderer_parent_class)->dispose (object);
}

static void
ephy_removable_pixbuf_renderer_class_init (EphyRemovablePixbufRendererClass *klass)
{
  GObjectClass *oclass = G_OBJECT_CLASS (klass);
  GtkCellRendererClass *crclass = GTK_CELL_RENDERER_CLASS (klass);

  crclass->render = ephy_removable_pixbuf_renderer_render;
  crclass->activate = ephy_removable_pixbuf_renderer_activate;
  oclass->get_property = ephy_removable_pixbuf_renderer_get_property;
  oclass->set_property = ephy_removable_pixbuf_renderer_set_property;
  oclass->dispose = ephy_removable_pixbuf_renderer_dispose;

  g_object_class_install_property (oclass,
				   PROP_RENDER_POLICY,
				   g_param_spec_enum ("render-policy",
						      "Render policy",
						      "The rendering policy for the close icon in the renderer",
						      EPHY_TYPE_REMOVABLE_PIXBUF_RENDER_POLICY,
						      EPHY_REMOVABLE_PIXBUF_RENDER_PRELIT,
						      G_PARAM_CONSTRUCT |
						      G_PARAM_READWRITE |
						      G_PARAM_STATIC_STRINGS));

  signals[DELETE_CLICKED] =
    g_signal_new ("delete-clicked",
		  G_OBJECT_CLASS_TYPE (oclass),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL, NULL,
		  G_TYPE_NONE, 1,
		  G_TYPE_STRING);

  g_type_class_add_private (klass, sizeof (EphyRemovablePixbufRendererPrivate));
}

static void
ephy_removable_pixbuf_renderer_init (EphyRemovablePixbufRenderer *self)
{
  GtkIconTheme *icon_theme;
  GError *error = NULL;

  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EPHY_TYPE_REMOVABLE_PIXBUF_RENDERER,
                                            EphyRemovablePixbufRendererPrivate);
  g_object_set (self, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
  icon_theme = gtk_icon_theme_get_default ();
  self->priv->close_icon = gtk_icon_theme_load_icon (icon_theme,
						     "window-close-symbolic",
						     24, 0, &error);

  if (error != NULL) {
      self->priv->close_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 24, 24);
      gdk_pixbuf_fill (self->priv->close_icon, 0);
      g_warning ("%s(): %s", G_STRFUNC, error->message);
      g_error_free (error);
    }
}

GtkCellRenderer *
ephy_removable_pixbuf_renderer_new (void)
{
  return g_object_new (EPHY_TYPE_REMOVABLE_PIXBUF_RENDERER, NULL);
}
