/* $Id: guppi-pie-tool.c,v 1.13 2001/08/26 03:04:35 trow Exp $ */

/*
 * guppi-pie-tool.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org>.
 *
 * 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 <gdk/gdkkeysyms.h>

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <math.h>
#include <guppi-memory.h>
#include <guppi-metrics.h>
#include "guppi-pie-tool.h"
#include "guppi-pie-state.h"
#include "guppi-pie-view.h"
#include "guppi-pie-item.h"

static void
explode_all_first_cb (GuppiPlotTool *tool, GuppiCanvasItem *gci)
{
  guppi_element_state_get (guppi_canvas_item_state (gci),
			   "base_offset", &tool->arg1,
			   NULL);
}

static void
explode_all_cb (GuppiPlotTool *tool, GuppiCanvasItem *gci)
{
  gint cx0, cy0, cx1, cy1;
  double cx, cy, dx, dy;
  double ux, uy;
  double r, t;

  guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
  cx = (cx0 + cx1) / 2.0;
  cy = (cy0 + cy1) / 2.0;

  ux = tool->raw_start_x - cx;
  uy = tool->raw_start_y - cy;
  r = sqrt (ux * ux + uy * uy);
  ux /= r;
  uy /= r;


  dx = tool->raw_x - tool->raw_start_x;
  dy = tool->raw_y - tool->raw_start_y;
  t = (dx * ux + dy * uy);

  t = (guppi_x_px2pt (t) + guppi_y_px2pt (t)) / 2;

  guppi_element_state_set (guppi_canvas_item_state (gci),
			   "base_offset", tool->arg1 + t,
			   NULL);
}

GuppiPlotTool *
guppi_pie_tool_new_explode_all (void)
{
  GuppiPlotTool *tool;

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup (_("Explode All"));
  tool->supported_type = GUPPI_TYPE_PIE_ITEM;

  tool->cursor = gdk_cursor_new (GDK_FLEUR);
  tool->tracks_motion = TRUE;
  tool->repeating = FALSE;
  tool->first = explode_all_first_cb;
  tool->middle = explode_all_cb;

  return tool;
}

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

static void
pick_slice (GuppiPlotTool *tool, GuppiCanvasItem *gci)
{
  gint slice;

  if (tool->int_arg1)
    return;

  if (guppi_pie_item_in_slice (GUPPI_PIE_ITEM (gci),
			       tool->raw_x, tool->raw_y, &slice)) {
    GuppiPieState *state = GUPPI_PIE_STATE (guppi_canvas_item_state (gci));

    tool->int_arg1 = 1;
    tool->int_arg2 = slice;
    tool->arg1 = guppi_pie_state_slice_offset (state, slice);
  }
}

static void
explode_slice_first_cb (GuppiPlotTool * tool, GuppiCanvasItem * gci)
{
  tool->int_arg1 = 0;
  pick_slice (tool, gci);
}

static void
explode_slice_cb (GuppiPlotTool * tool, GuppiCanvasItem * gci)
{
  GuppiPieState *state = GUPPI_PIE_STATE (guppi_canvas_item_state (gci));
  gint cx0, cy0, cx1, cy1;
  double cx, cy, dx, dy;
  double ux, uy;
  double r, t;

  if (tool->int_arg1 == 0) {
    pick_slice (tool, gci);
    return;
  }

  guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
  cx = (cx0 + cx1) / 2.0;
  cy = (cy0 + cy1) / 2.0;

  ux = tool->raw_start_x - cx;
  uy = tool->raw_start_y - cy;
  r = sqrt (ux * ux + uy * uy);
  ux /= r;
  uy /= r;


  dx = tool->raw_x - tool->raw_start_x;
  dy = tool->raw_y - tool->raw_start_y;
  t = (dx * ux + dy * uy);

  t = (guppi_x_px2pt (t) + guppi_y_px2pt (t)) / 2;

  guppi_pie_state_set_slice_offset (state, tool->int_arg2, tool->arg1 + t);
  guppi_element_state_changed (GUPPI_ELEMENT_STATE (state));
}

GuppiPlotTool *
guppi_pie_tool_new_explode_slice (void)
{
  GuppiPlotTool *tool;

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup (_("Explode Slice"));
  tool->supported_type = GUPPI_TYPE_PIE_ITEM;

  tool->cursor = gdk_cursor_new (GDK_FLEUR);
  tool->tracks_motion = TRUE;
  tool->repeating = FALSE;
  tool->first = explode_slice_first_cb;
  tool->middle = explode_slice_cb;

  return tool;
}

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

static void
change_radius_first_cb (GuppiPlotTool * tool, GuppiCanvasItem * gci)
{
  GuppiPieView *view = GUPPI_PIE_VIEW (guppi_canvas_item_view (gci));

  guppi_element_state_get (guppi_canvas_item_state (gci),
			   "radius", &tool->arg1,
			   NULL);
  tool->arg2 = guppi_pie_view_max_radius (view);
}

static void
change_radius_cb (GuppiPlotTool * tool, GuppiCanvasItem * gci)
{
  gint cx0, cy0, cx1, cy1;
  double cx, cy, dx, dy;
  double ux, uy;
  double r, t;

  guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
  cx = (cx0 + cx1) / 2.0;
  cy = (cy0 + cy1) / 2.0;

  ux = tool->raw_start_x - cx;
  uy = tool->raw_start_y - cy;
  r = sqrt (ux * ux + uy * uy);
  ux /= r;
  uy /= r;


  dx = tool->raw_x - tool->raw_start_x;
  dy = tool->raw_y - tool->raw_start_y;
  t = (dx * ux + dy * uy);

  t = (guppi_x_px2pt (t) + guppi_y_px2pt (t)) / 2;

  guppi_element_state_set (guppi_canvas_item_state (gci),
			   "radius", CLAMP (tool->arg1 + t, 72 / 8.0, tool->arg2),
			   NULL);
}

GuppiPlotTool *
guppi_pie_tool_new_change_radius (void)
{
  GuppiPlotTool *tool;

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup (_("Change Radius"));
  tool->supported_type = GUPPI_TYPE_PIE_ITEM;

  tool->cursor = gdk_cursor_new (GDK_SIZING);
  tool->tracks_motion = TRUE;
  tool->repeating = FALSE;
  tool->first = change_radius_first_cb;
  tool->middle = change_radius_cb;

  return tool;

}

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

static void
spin_first_cb (GuppiPlotTool *tool, GuppiCanvasItem *gci)
{
  gint cx0, cy0, cx1, cy1, cx, cy;

  guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
  cx = (cx0 + cx1) / 2.0;
  cy = (cy0 + cy1) / 2.0;

  guppi_element_state_get (guppi_canvas_item_state (gci),
			   "base_angle", &tool->arg1,
			   NULL);
  tool->arg2 = atan2 (tool->raw_start_y - cy, tool->raw_start_x - cx);
}

static void
spin_cb (GuppiPlotTool *tool, GuppiCanvasItem *gci)
{
  gint cx0, cy0, cx1, cy1, cx, cy;
  double theta;

  guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
  cx = (cx0 + cx1) / 2.0;
  cy = (cy0 + cy1) / 2.0;

  theta = atan2 (tool->raw_y - cy, tool->raw_x - cx);

  guppi_element_state_set (guppi_canvas_item_state (gci),
			   "base_angle", tool->arg1 + theta - tool->arg2,
			   NULL);
}

GuppiPlotTool *
guppi_pie_tool_new_spin (void)
{
  GuppiPlotTool *tool;

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup (_("Rotate Pie Chart"));
  tool->supported_type = GUPPI_TYPE_PIE_ITEM;

  tool->cursor = gdk_cursor_new (GDK_EXCHANGE);
  tool->tracks_motion = TRUE;
  tool->repeating = FALSE;
  tool->first = spin_first_cb;
  tool->middle = spin_cb;

  return tool;
}

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

static void
fixed_spin_cb (GuppiPlotTool * tool, GuppiCanvasItem * item)
{
  GuppiElementState *state = guppi_canvas_item_state (item);
  double th;

  guppi_element_state_get (state, 
			   "base_angle", &th,
			   NULL);
  th += tool->arg1;
  guppi_element_state_set (state,
			   "base_angle", th,
			   NULL);
}


GuppiPlotTool *
guppi_pie_tool_new_fixed_spin (double theta_degrees)
{
  GuppiPlotTool *tool;

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup_printf (_("Rotate Pie Chart %g degrees"),
				theta_degrees);

  tool->supported_type = GUPPI_TYPE_PIE_ITEM;

  tool->arg1 = theta_degrees * (M_PI / 180);	/* convert to radians */
  tool->cursor = gdk_cursor_new (GDK_EXCHANGE);
  tool->tracks_motion = FALSE;
  tool->repeating = TRUE;
  tool->repeat_interval = 100;
  tool->first = fixed_spin_cb;
  tool->repeat = fixed_spin_cb;

  return tool;
}

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

static void
slice_callback_cb (GuppiPlotTool * tool, GuppiCanvasItem * gci)
{
  gint slice;

  /* If the pointer is inside of a slice, execute the callback
     with the slice # as an argument. */
  if (guppi_pie_item_in_slice (GUPPI_PIE_ITEM (gci),
			       tool->raw_x, tool->raw_y, &slice)) {
    GuppiPieSliceFunc func = tool->ptr_arg1;
    func (slice, tool->ptr_arg2 /* == user data */ );
  }
}

GuppiPlotTool *
guppi_pie_tool_new_slice_callback (GuppiPieSliceFunc func,
				   const gchar * name, gpointer user_data)
{
  GuppiPlotTool *tool;

  g_return_val_if_fail (func != NULL, NULL);

  tool = guppi_plot_tool_new ();
  tool->name = guppi_strdup (name);
  tool->tracks_motion = FALSE;
  tool->repeating = FALSE;
  tool->first = slice_callback_cb;
  tool->ptr_arg1 = (gpointer) func;
  tool->ptr_arg2 = user_data;

  return tool;
}

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

GuppiPlotToolkit *
guppi_pie_toolkit_default (void)
{
  GuppiPlotToolkit *tk = guppi_plot_toolkit_new (_("Default"));

  guppi_plot_toolkit_set_button_tool (tk, 1, 0,
				      guppi_pie_tool_new_explode_slice ());

  guppi_plot_toolkit_set_button_tool (tk, 1, GDK_SHIFT_MASK,
				      guppi_pie_tool_new_explode_slice ());

  guppi_plot_toolkit_set_button_tool (tk, 3, 0, guppi_pie_tool_new_spin ());

  guppi_plot_toolkit_set_button_tool (tk, 4, 0,
				      guppi_pie_tool_new_fixed_spin (15));

  guppi_plot_toolkit_set_button_tool (tk, 5, 0,
				      guppi_pie_tool_new_fixed_spin (-15));

  guppi_plot_toolkit_set_key_tool (tk, GDK_Right, 0,
				   guppi_pie_tool_new_fixed_spin (12));

  guppi_plot_toolkit_set_key_tool (tk, GDK_Left, 0,
				   guppi_pie_tool_new_fixed_spin (-12));

  return tk;
}

GuppiPlotToolkit *
guppi_pie_toolkit_explode (void)
{
  GuppiPlotToolkit *tk = guppi_plot_toolkit_new (_("Explode"));
  tk->toolbar_button_image = "pie-explode.png";

  guppi_plot_toolkit_set_button_tool (tk, 1, 0,
				      guppi_pie_tool_new_explode_slice ());

  guppi_plot_toolkit_set_button_tool (tk, 3, 0,
				      guppi_pie_tool_new_explode_all ());

  return tk;
}

GuppiPlotToolkit *
guppi_pie_toolkit_spin (void)
{
  GuppiPlotToolkit *tk = guppi_plot_toolkit_new (_("Spin"));
  tk->toolbar_button_image = "pie-spin.png";

  guppi_plot_toolkit_set_button_tool (tk, 1, 0, guppi_pie_tool_new_spin ());

  return tk;
}

/* $Id: guppi-pie-tool.c,v 1.13 2001/08/26 03:04:35 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1