/* This is -*- C -*- */
/* $Id: guppi-legend-item.c,v 1.17 2001/10/18 21:47:15 jody Exp $ */

/*
 * guppi-legend-item.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org> and
 * Havoc Pennington <hp@pobox.com>.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include <guppi-useful.h>
#include <guppi-raster-text.h>
#include "guppi-legend-item.h"
#include "guppi-legend-view.h"
#include "guppi-legend-state.h"
#include "guppi-legend-tool.h"

static GtkObjectClass *parent_class = NULL;

enum {
  CLICKED_BOX,
  LAST_SIGNAL
};

guint leg_signals[LAST_SIGNAL] = { 0 };

static void
guppi_legend_item_finalize (GtkObject * obj)
{
  GuppiLegendItem *item = GUPPI_LEGEND_ITEM (obj);
  GList *iter;

  if (item->labels) {
    iter = item->labels;
    while (iter != NULL) {
      guppi_unref (iter->data);
      iter = g_list_next (iter);
    }
    g_list_free (item->labels);
    item->labels = NULL;
  }

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/***************************************************************************/

static void
update (GuppiCanvasItem * gci, double aff[6], ArtSVP * clip_path, gint flags)
{
  GuppiLegendState *state;
  GuppiLegendItem *item;
  GnomeFont *font;
  GList *new_labels = NULL;
  GList *iter;
  double sc;
  gint i, i0, i1;

  item = GUPPI_LEGEND_ITEM (gci);
  state = GUPPI_LEGEND_STATE (guppi_canvas_item_state (gci));
  sc = guppi_canvas_item_scale (gci);

  guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
			   "label_font", &font,
			   NULL);

  /* Rasterize our labels, re-using old rasterizations when possible. */
  guppi_legend_state_entry_bounds (state, &i0, &i1);
  for (i = i0; i <= i1; ++i) {
    GuppiRasterText *rt = NULL;
    const gchar *text = guppi_legend_state_entry_text (state, i);

    iter = item->labels;
    while (iter != NULL && rt == NULL) {
      if (iter->data) {
	GuppiRasterText *rt2 = GUPPI_RASTER_TEXT (iter->data);
	char *tmp = guppi_raster_text_text (rt2);
	if (text != NULL && tmp != NULL && strcmp (text, tmp) == 0) {
	  rt = rt2;
	  iter->data = NULL;
	}
	g_free (tmp);
      }
      iter = g_list_next (iter);
    }

    if (rt == NULL) {
      rt = guppi_raster_text_new (NULL);
      guppi_raster_text_set_text (rt, text);

    }

    guppi_raster_text_set_scale (rt, sc);

    new_labels = g_list_append (new_labels, rt);
  }

  /* Clean up old labels */
  iter = item->labels;
  while (iter != NULL) {
    guppi_unref (iter->data);
    iter = g_list_next (iter);
  }
  g_list_free (item->labels);

  item->labels = new_labels;

  guppi_unref (font);
}

static void
render (GuppiCanvasItem * gci, GnomeCanvasBuf * buf)
{
  GuppiLegendItem *item;
  GuppiLegendState *state;
  double sc;
  gint i, i0, i1, N;
  gint x0, y0, x1, y1;
  double edge_margin, edge_thickness, label_offset, swatch_width, swatch_height;
  double px_margin, px_label_offset, px_box_width, px_box_height, px_box_edge;
  guint32 label_color, box_color, box_edge_color;
  GList *iter;
  double box_y_step, box_x0, box_y0, box_x1, box_y1, lab_x, lab_y;
  guint r, g, b, a;

  item = GUPPI_LEGEND_ITEM (gci);
  state = GUPPI_LEGEND_STATE (guppi_canvas_item_state (gci));

  sc = guppi_canvas_item_scale (gci);
  guppi_canvas_item_get_bbox_c (gci, &x0, &y0, &x1, &y1);

  guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
			   "edge_margin", &edge_margin,
			   "edge_thickness", &edge_thickness,
			   "label_offset", &label_offset,
			   "label_color", &label_color,
			   "swatch_width", &swatch_width,
			   "swatch_height", &swatch_height,
			   "edge_color", &box_edge_color,
			   NULL);

  px_margin = guppi_pt2px (edge_margin * sc);
  px_label_offset = guppi_x_pt2px (label_offset * sc);
  px_box_width = guppi_x_pt2px (swatch_width * sc);
  px_box_height = guppi_y_pt2px (swatch_height * sc);
  px_box_edge = guppi_pt2px (edge_thickness * sc);

  guppi_legend_state_entry_bounds (state, &i0, &i1);
  N = i1 - i0 + 1;
  
  box_y_step = N > 1 ? (y1 - y0 - 2 * px_margin - px_box_height) / (N - 1) : 0;
  UINT_TO_RGBA (label_color, &r, &g, &b, &a);

  iter = item->labels;
  for (i = i0; i <= i1; ++i) {
    GuppiAlphaTemplate *label_template;
    double box_y_center;

    box_y_center = y0 + px_margin + px_box_height / 2 + (i-i0) * box_y_step;
    box_y0 = box_y_center - px_box_height / 2;
    box_y1 = box_y_center + px_box_height / 2;
    box_x0 = x0 + px_margin;
    box_x1 = box_x0 + px_box_width;

    box_color = guppi_legend_state_entry_color (state, i);

    guppi_paint_soft_box (buf, box_x0, box_y0, box_x1, box_y1,
			  box_edge_color);
    guppi_paint_soft_box (buf, box_x0 + px_box_edge, box_y0 + px_box_edge,
			  box_x1 - px_box_edge, box_y1 - px_box_edge,
			  box_color);

    label_template =
      guppi_raster_text_template (GUPPI_RASTER_TEXT (iter->data));
    lab_x = box_x1 + px_label_offset;
    if (label_template)
      lab_y = box_y_center - label_template->height / 2;

    if (label_template)
      guppi_alpha_template_print (label_template,
				  (gint) rint (lab_x), (gint) rint (lab_y),
				  r, g, b, a, buf);

    iter = g_list_next (iter);
  }

}


/***************************************************************************/

static gboolean
double_click (GuppiCanvasItem * gci,
	      guint button, guint state, double pt_x, double pt_y)
{
  gint box;
  gint c_x, c_y;

  guppi_canvas_item_pt2c (gci, pt_x, pt_y, &c_x, &c_y);

  if (guppi_legend_item_in_box (GUPPI_LEGEND_ITEM (gci), c_x, c_y, &box)) {
    gtk_signal_emit (GTK_OBJECT (gci), leg_signals[CLICKED_BOX],
		     box, button, state);
    return TRUE;
  }
  return FALSE;
}

static void
guppi_marshal_NONE__INT_UINT_UINT (GtkObject * obj,
				   GtkSignalFunc func,
				   gpointer func_data, GtkArg * args)
{
  ((void (*)(GtkObject *,
	     gint, guint, guint,
	     gpointer)) func) (obj,
			       GTK_VALUE_INT (args[0]),
			       GTK_VALUE_UINT (args[1]),
			       GTK_VALUE_UINT (args[2]), func_data);
}

static void
guppi_legend_item_class_init (GuppiLegendItemClass * klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiCanvasItemClass *gci_class = GUPPI_CANVAS_ITEM_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_CANVAS_ITEM);

  object_class->finalize = guppi_legend_item_finalize;

  gci_class->guppi_update = update;
  gci_class->guppi_render = render;
  gci_class->double_click = double_click;

  leg_signals[CLICKED_BOX] =
    gtk_signal_new ("clicked_box",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GuppiLegendItemClass, clicked_box),
		    guppi_marshal_NONE__INT_UINT_UINT,
		    GTK_TYPE_NONE, 3,
		    GTK_TYPE_INT, GTK_TYPE_UINT, GTK_TYPE_UINT);

  gtk_object_class_add_signals (object_class, leg_signals, LAST_SIGNAL);

}

static void
guppi_legend_item_init (GuppiLegendItem * obj)
{

}

GtkType guppi_legend_item_get_type (void)
{
  static GtkType guppi_legend_item_type = 0;
  if (!guppi_legend_item_type) {
    static const GtkTypeInfo guppi_legend_item_info = {
      "GuppiLegendItem",
      sizeof (GuppiLegendItem),
      sizeof (GuppiLegendItemClass),
      (GtkClassInitFunc) guppi_legend_item_class_init,
      (GtkObjectInitFunc) guppi_legend_item_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_legend_item_type =
      gtk_type_unique (GUPPI_TYPE_CANVAS_ITEM, &guppi_legend_item_info);
  }
  return guppi_legend_item_type;
}

/***************************************************************************/

gboolean
guppi_legend_item_in_box (GuppiLegendItem * item, gint x, gint y, gint * box)
{
  GuppiCanvasItem *gci;
  GuppiLegendState *state;
  gint x0, y0, x1, y1, i, i0, i1, N;
  double edge_margin, label_offset, swatch_width, swatch_height;
  double px_margin, px_label_offset, px_box_width, px_box_height, sc;
  double box_y_step, box_x0, box_x1, box_y0, box_y1;

  g_return_val_if_fail (item != NULL, FALSE);
  g_return_val_if_fail (GUPPI_IS_LEGEND_ITEM (item), FALSE);
  g_return_val_if_fail (box != NULL, FALSE);

  gci = GUPPI_CANVAS_ITEM (item);
  state = GUPPI_LEGEND_STATE (guppi_canvas_item_state (gci));

  guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
			   "edge_margin", &edge_margin,
			   "label_offset", &label_offset,
			   "swatch_width", &swatch_width,
			   "swatch_height", &swatch_height,
			   NULL);

  /* *Very* Hacky: a lot of code cut&paste from above. */

  sc = guppi_canvas_item_scale (gci);

  guppi_canvas_item_get_bbox_c (gci, &x0, &y0, &x1, &y1);

  px_margin = guppi_pt2px (edge_margin * sc);
  px_label_offset = guppi_x_pt2px (label_offset * sc);
  px_box_width = guppi_x_pt2px (swatch_width * sc);
  px_box_height = guppi_y_pt2px (swatch_height * sc);

  guppi_legend_state_entry_bounds (state, &i0, &i1);
  N =  i1 - i0 + 1;

  box_y_step =
    N > 1 ? (y1 - y0 - 2 * px_margin - px_box_height) / (N - 1) : 0;

  for (i = i0; i <= i1; ++i) {
    double box_y_center;

    box_y_center = y0 + px_margin + px_box_height / 2 + (i-i0) * box_y_step;
    box_y0 = box_y_center - px_box_height / 2;
    box_y1 = box_y_center + px_box_height / 2;
    box_x0 = x0 + px_margin;
    box_x1 = box_x0 + px_box_width;

    if (box_x0 <= x && x <= box_x1 && box_y0 <= y && y <= box_y1) {
      *box = i;
      return TRUE;
    }
  }

  return FALSE;
}


/* $Id: guppi-legend-item.c,v 1.17 2001/10/18 21:47:15 jody Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1