// -*- C++ -*-

/* 
 * GChemPaint arrows plugin
 * arrowtool.cc 
 *
 * Copyright (C) 2001-2007 Jean Bréfort <jean.brefort@normalesup.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "gchempaint-config.h"
#include "arrowtool.h"
#include "retrosynthesisarrow.h"
#include "lib/settings.h"
#include "libgcpcanvas/gcp-canvas-line.h"
#include "libgcpcanvas/gcp-canvas-group.h"
#include "libgcpcanvas/gcp-canvas-bpath.h"
#include "lib/document.h"
#include "lib/application.h"
#include "lib/mesomery-arrow.h"
#include "lib/reaction-arrow.h"
#include "lib/settings.h"
#include "lib/theme.h"
#include <glib/gi18n-lib.h>
#include <gconf/gconf-client.h>
#include <cmath>

static char* ToolNames[] = {
	(char*) "SimpleArrow",
	(char*) "ReversibleArrow",
	(char*) "ReversibleArrow",
	(char*) "DoubleHeadedArrow",
	(char*) "RetrosynthesisArrow"
};

static void on_default (GtkToggleButton *button)
{
	GConfClient *conf_client = gconf_client_get_default ();
	gconf_client_set_bool (conf_client, "/apps/gchempaint/plugins/arrows/full-arrows-heads", gtk_toggle_button_get_active (button), NULL);
	g_object_unref (conf_client);
}

gcpArrowTool::gcpArrowTool(gcpApplication* App, unsigned ArrowType): gcpTool(App, ToolNames[ArrowType])
{
	points = gnome_canvas_points_new(2);
	m_ArrowType = ArrowType;
}

gcpArrowTool::~gcpArrowTool()
{
	gnome_canvas_points_free(points);
}	

bool gcpArrowTool::OnClicked()
{
	if (m_pObject) return false;
		gcpDocument *pDoc = m_pView->GetDoc ();
	gcpTheme *pTheme = pDoc->GetTheme ();
	m_y1 = m_y0;
	m_x1 = m_x0 + pDoc->GetArrowLength () * pTheme->GetZoomFactor ();
	switch(m_ArrowType)
	{
		case gcpSimpleArrow:
			points->coords[0] = m_x0;
			points->coords[1] = m_y0;
			points->coords[2] = m_x1;
			points->coords[3] = m_y0;
			m_pItem = gnome_canvas_item_new(
										m_pGroup,
										gnome_canvas_line_ext_get_type(),
										"points", points,
										"fill_color", AddColor,
										"width_units", pTheme->GetArrowWidth (),
										"last_arrowhead", true,
										"arrow_shape_a", pTheme->GetArrowHeadA (),
										"arrow_shape_b", pTheme->GetArrowHeadB (),
										"arrow_shape_c", pTheme->GetArrowHeadC (),
										"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										NULL);
			break;
		case gcpReversibleArrow:
			points->coords[0] = m_x0;
			points->coords[1] = points->coords[3] = m_y0 - pTheme->GetArrowDist () / 2;
			points->coords[2] = m_x1;
			m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
								NULL);
			points->coords[2] = m_x0;
			points->coords[1] = points->coords[3] = m_y0 + pTheme->GetArrowDist () / 2;
			points->coords[0] = m_x0 + pDoc->GetArrowLength ();
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
								NULL);
			break;
		case gcpFullReversibleArrow:
			points->coords[0] = m_x0;
			points->coords[1] = points->coords[3] = m_y0 - pTheme->GetArrowDist () / 2;
			points->coords[2] = m_x1;
			m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
								NULL);
			points->coords[2] = m_x0;
			points->coords[1] = points->coords[3] = m_y0 + pTheme->GetArrowDist () / 2;
			points->coords[0] = m_x0 + pDoc->GetArrowLength ();
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
								NULL);
			break;
		case gcpDoubleHeadedArrow:
			points->coords[0] = m_x0;
			points->coords[1] = m_y0;
			points->coords[2] = m_x1;
			points->coords[3] = m_y0;
			m_pItem = gnome_canvas_item_new(
										m_pGroup,
										gnome_canvas_line_ext_get_type(),
										"points", points,
										"fill_color", AddColor,
										"width_units", pTheme->GetArrowWidth (),
										"first_arrowhead", true,
										"last_arrowhead", true,
										"arrow_shape_a", pTheme->GetArrowHeadA (),
										"arrow_shape_b", pTheme->GetArrowHeadB (),
										"arrow_shape_c", pTheme->GetArrowHeadC (),
										"first_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										NULL);
			break;
		case gcpDoubleQueuedArrow: {
			GnomeCanvasPathDef* path = gnome_canvas_path_def_new ();
			gnome_canvas_path_def_moveto (path, m_x0, m_y0 - pTheme->GetArrowDist () / 2.);
			gnome_canvas_path_def_lineto (path, m_x1 - pTheme->GetArrowDist () / 2., m_y0 - pTheme->GetArrowDist () / 2.);
			gnome_canvas_path_def_moveto (path, m_x0, m_y0 + pTheme->GetArrowDist () / 2.);
			gnome_canvas_path_def_lineto (path, m_x1 - pTheme->GetArrowDist () / 2., m_y0 + pTheme->GetArrowDist () / 2.);
			gnome_canvas_path_def_moveto (path, m_x1 - pTheme->GetArrowDist () / 2. - pTheme->GetArrowHeadC (), m_y0 - pTheme->GetArrowDist () / 2. - pTheme->GetArrowHeadC ());
			gnome_canvas_path_def_lineto (path, m_x1, m_y0);
			gnome_canvas_path_def_lineto (path, m_x1 - pTheme->GetArrowDist () / 2. - pTheme->GetArrowHeadC (), m_y0 + pTheme->GetArrowDist () / 2. + pTheme->GetArrowHeadC ());
			m_pItem = gnome_canvas_item_new(
									m_pGroup,
									gnome_canvas_bpath_ext_get_type(),
									"bpath", path,
									"outline_color", AddColor,
									"width_units", pTheme->GetArrowWidth (),
									"cap-style", GDK_CAP_BUTT,
									"join-style", GDK_JOIN_MITER,
									NULL);
			break;
		}
	}
	return true;
}

void gcpArrowTool::OnDrag()
{
	double x1, y1, x2, y2;
	gcpDocument *pDoc = m_pView->GetDoc ();
	gcpTheme *pTheme = pDoc->GetTheme ();
	if (m_pItem)
	{
		gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2);
		gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem)));
		gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2);
		m_pItem = NULL;
	}
	double dAngle;
	m_x -= m_x0;
	m_y -= m_y0;
	if (m_x == 0)
	{
		if (m_y == 0) return;
		dAngle = (m_y < 0) ? 90 : 270;
	}
	else
	{
		dAngle = atan(-m_y/m_x) * 180 / M_PI;
		if (!(m_nState & GDK_CONTROL_MASK)) dAngle = rint(dAngle / 5) * 5;
		if (m_x < 0) dAngle += 180;
	}
	m_dAngle = dAngle * M_PI / 180;
	double d = (m_nState & GDK_SHIFT_MASK)? sqrt(square(m_x) + square(m_y)): pDoc->GetArrowLength () * pTheme->GetZoomFactor ();
	char tmp[32];
	if (dAngle < 0) dAngle += 360;
	snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), dAngle);
	m_pApp->SetStatusText(tmp);
	m_x1 = m_x0 + d * cos(m_dAngle);
	m_y1 = m_y0 - d * sin(m_dAngle);
	switch(m_ArrowType)
	{
		case gcpSimpleArrow:
			points->coords[2] = m_x1;
			points->coords[3] = m_y1;
			m_pItem = gnome_canvas_item_new(
										m_pGroup,
										gnome_canvas_line_ext_get_type(),
										"points", points,
										"fill_color", AddColor,
										"width_units", pTheme->GetArrowWidth (),
										"last_arrowhead", true,
										"arrow_shape_a", pTheme->GetArrowHeadA (),
										"arrow_shape_b", pTheme->GetArrowHeadB (),
										"arrow_shape_c", pTheme->GetArrowHeadC (),
										"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										NULL);
			break;
		case gcpReversibleArrow:
			points->coords[0] = m_x0 - pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[1] = m_y0 - pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			points->coords[2] = m_x1 - pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[3] = m_y1 - pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
								NULL);
			points->coords[2] = m_x0 + pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[3] = m_y0 + pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			points->coords[0] = m_x1 + pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[1] = m_y1 + pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
								NULL);
			break;
		case gcpFullReversibleArrow:
			points->coords[0] = m_x0 - pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[1] = m_y0 - pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			points->coords[2] = m_x1 - pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[3] = m_y1 - pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
								NULL);
			points->coords[2] = m_x0 + pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[3] = m_y0 + pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			points->coords[0] = m_x1 + pTheme->GetArrowDist () / 2 * sin(m_dAngle);
			points->coords[1] = m_y1 + pTheme->GetArrowDist () / 2 * cos(m_dAngle);
			gnome_canvas_item_new(
								GNOME_CANVAS_GROUP(m_pItem),
								gnome_canvas_line_ext_get_type(),
								"points", points,
								"fill_color", AddColor,
								"width_units", pTheme->GetArrowWidth (),
								"last_arrowhead", true,
								"arrow_shape_a", pTheme->GetArrowHeadA (),
								"arrow_shape_b", pTheme->GetArrowHeadB (),
								"arrow_shape_c", pTheme->GetArrowHeadC (),
								"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
								NULL);
			break;
		case gcpDoubleHeadedArrow:
			points->coords[2] = m_x1;
			points->coords[3] = m_y1;
			m_pItem = gnome_canvas_item_new(
										m_pGroup,
										gnome_canvas_line_ext_get_type(),
										"points", points,
										"fill_color", AddColor,
										"width_units", pTheme->GetArrowWidth (),
										"first_arrowhead", true,
										"last_arrowhead", true,
										"arrow_shape_a", pTheme->GetArrowHeadA (),
										"arrow_shape_b", pTheme->GetArrowHeadB (),
										"arrow_shape_c", pTheme->GetArrowHeadC (),
										"first_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
										NULL);
			break;
		case gcpDoubleQueuedArrow: {
			double x1, y1;
			x1 = pTheme->GetArrowDist () / 2 * sin (m_dAngle);
			y1 = pTheme->GetArrowDist () / 2 * cos (m_dAngle);
			GnomeCanvasPathDef* path = gnome_canvas_path_def_new ();
			gnome_canvas_path_def_moveto (path, m_x0 - x1, m_y0 - y1);
			gnome_canvas_path_def_lineto (path, m_x1 - x1 - y1, m_y1 - y1 + x1);
			gnome_canvas_path_def_moveto (path, m_x0 + x1, m_y0 + y1);
			gnome_canvas_path_def_lineto (path, m_x1 + x1 - y1, m_y1 + y1 + x1);
			x1 += pTheme->GetArrowHeadC () * sin (m_dAngle);
			y1 += pTheme->GetArrowHeadC () * cos (m_dAngle);
			gnome_canvas_path_def_moveto (path, m_x1 - x1 - y1, m_y1 - y1 + x1);
			gnome_canvas_path_def_lineto (path, m_x1, m_y1);
			gnome_canvas_path_def_lineto (path, m_x1 + x1 - y1, m_y1 + y1 + x1);
			m_pItem = gnome_canvas_item_new(
									m_pGroup,
									gnome_canvas_bpath_ext_get_type(),
									"bpath", path,
									"outline_color", AddColor,
									"width_units", pTheme->GetArrowWidth (),
									"cap-style", GDK_CAP_BUTT,
									"join-style", GDK_JOIN_MITER,
									NULL);
			break;
		}
	}
}

void gcpArrowTool::OnRelease()
{
	double x1, y1, x2, y2;
	if (m_pItem)
	{
		gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2);
		gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem)));
		gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2);
		m_pItem = NULL;
	}
	else return;
	m_pApp->ClearStatus();
	gcpDocument* pDoc = m_pView->GetDoc();
	gcpArrow* a;
	switch(m_ArrowType)
	{
	case gcpDoubleHeadedArrow:
		{
			a = new gcpMesomeryArrow(NULL);
			a->SetCoords(m_x0 / m_dZoomFactor, m_y0 / m_dZoomFactor, m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
			pDoc->AddObject(a);
		}
		break;
	case gcpDoubleQueuedArrow: {
			a = new gcpRetrosynthesisArrow (NULL);
			a->SetCoords(m_x0 / m_dZoomFactor, m_y0 / m_dZoomFactor, m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
			pDoc->AddObject(a);
		}
		break;
	default:
		{
			a = new gcpReactionArrow(NULL, m_ArrowType);
			a->SetCoords(m_x0 / m_dZoomFactor, m_y0 / m_dZoomFactor, m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
			pDoc->AddObject(a);
		}
	}
	pDoc->FinishOperation();
}

static void on_full_toggled (GtkToggleButton *button, gcpArrowTool *tool)
{
	tool->SetArrowType (gtk_toggle_button_get_active (button)? gcpFullReversibleArrow: gcpReversibleArrow);
}

static void on_length_changed (GtkSpinButton *btn, gcpArrowTool *tool)
{
	tool->SetLength (gtk_spin_button_get_value (btn));
}

GtkWidget *gcpArrowTool::GetPropertyPage ()
{
	bool show_all = m_ArrowType == gcpReversibleArrow || m_ArrowType == gcpFullReversibleArrow;
	GladeXML *xml = glade_xml_new (GLADEDIR"/arrowtool.glade", (show_all? "arrow-box": "length-box"), GETTEXT_PACKAGE);
	if (show_all) {
		GtkTable *table = GTK_TABLE (glade_xml_get_widget (xml, "heads-table"));
		GnomeCanvas *canvas = GNOME_CANVAS (gnome_canvas_new_aa ());
		gcpTheme *Theme = ThemeManager.GetTheme ("Default");
		double width = (Theme->GetArrowLength () * Theme->GetZoomFactor () + 2 * Theme->GetArrowPadding ()),
			height = Theme->GetArrowDist () + Theme->GetArrowWidth () + 2 * (Theme->GetArrowHeadB () + Theme->GetPadding ());
		gtk_widget_set_size_request (GTK_WIDGET (canvas), (int) width, (int) height);
		GnomeCanvasGroup *group = gnome_canvas_root (canvas);
		GnomeCanvasPoints *points = gnome_canvas_points_new (2);
		gnome_canvas_set_scroll_region (canvas, 0, 0, Theme->GetArrowLength (), Theme->GetArrowDist () + Theme->GetArrowWidth () + 2 * Theme->GetArrowHeadB ());
		points->coords[0] = (width - Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		points->coords[1] = points->coords[3] = (height - Theme->GetArrowDist  ()) / 2.;
		points->coords[2] = (width + Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		gnome_canvas_item_new (
							group,
							gnome_canvas_line_ext_get_type (),
							"points", points,
							"fill_color", "black",
							"width_units", Theme->GetArrowWidth (),
							"last_arrowhead", true,
							"arrow_shape_a",Theme->GetArrowHeadA (),
							"arrow_shape_b",Theme->GetArrowHeadB (),
							"arrow_shape_c",Theme->GetArrowHeadC (),
							"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
							NULL);
		points->coords[0] = (width + Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		points->coords[1] = points->coords[3] = (height + Theme->GetArrowDist ()) / 2.;
		points->coords[2] = (width - Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		gnome_canvas_item_new (
							group,
							gnome_canvas_line_ext_get_type (),
							"points", points,
							"fill_color", "black",
							"width_units",Theme->GetArrowWidth (),
							"last_arrowhead", true,
							"arrow_shape_a",Theme->GetArrowHeadA (),
							"arrow_shape_b",Theme->GetArrowHeadB (),
							"arrow_shape_c",Theme->GetArrowHeadC (),
							"last_arrowhead_style", (unsigned char)ARROW_HEAD_LEFT,
							NULL);
		gtk_widget_show (GTK_WIDGET (canvas));
		gtk_table_attach (table, GTK_WIDGET (canvas), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 10, 0);
		canvas = GNOME_CANVAS (gnome_canvas_new_aa ());
		gtk_widget_set_size_request (GTK_WIDGET (canvas), (int) width, (int) height);
		group = gnome_canvas_root (canvas);
		gnome_canvas_set_scroll_region (canvas, 0, 0, Theme->GetArrowLength (), Theme->GetArrowDist () + Theme->GetArrowWidth () + 2 * Theme->GetArrowHeadB ());
		points->coords[0] = (width - Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		points->coords[1] = points->coords[3] = (height - Theme->GetArrowDist ()) / 2.;
		points->coords[2] = (width + Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		gnome_canvas_item_new (
							group,
							gnome_canvas_line_ext_get_type (),
							"points", points,
							"fill_color", "black",
							"width_units", Theme->GetArrowWidth (),
							"last_arrowhead", true,
							"arrow_shape_a",Theme->GetArrowHeadA (),
							"arrow_shape_b",Theme->GetArrowHeadB (),
							"arrow_shape_c",Theme->GetArrowHeadC (),
							"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
							NULL);
		points->coords[0] = (width + Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		points->coords[1] = points->coords[3] = (height + Theme->GetArrowDist ()) / 2.;
		points->coords[2] = (width - Theme->GetArrowLength () * Theme->GetZoomFactor ()) / 2.;
		gnome_canvas_item_new (
							group,
							gnome_canvas_line_ext_get_type (),
							"points", points,
							"fill_color", "black",
							"width_units",Theme->GetArrowWidth (),
							"last_arrowhead", true,
							"arrow_shape_a",Theme->GetArrowHeadA (),
							"arrow_shape_b",Theme->GetArrowHeadB (),
							"arrow_shape_c",Theme->GetArrowHeadC (),
							"last_arrowhead_style", (unsigned char)ARROW_HEAD_BOTH,
							NULL);
		gtk_widget_show (GTK_WIDGET (canvas));
		gtk_table_attach (table, GTK_WIDGET (canvas), 1, 2, 1, 2, GTK_FILL, GTK_FILL, 10, 0);
		gnome_canvas_points_free (points);
		GtkWidget *b = glade_xml_get_widget (xml, "full");
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), m_ArrowType == gcpFullReversibleArrow);
		g_signal_connect (G_OBJECT (b), "toggled", G_CALLBACK (on_full_toggled), this);
		GtkWidget *w = glade_xml_get_widget (xml, "default");
		g_signal_connect_swapped (w, "clicked", G_CALLBACK (on_default), b);
	}
	m_LengthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-length"));
	g_signal_connect (m_LengthBtn, "value-changed", G_CALLBACK (on_length_changed), this);
	return glade_xml_get_widget (xml, (show_all? "arrow-box": "length-box"));
}

void gcpArrowTool::SetLength (double length)
{
	m_pApp->GetActiveDocument ()->SetArrowLength (length);
}

void gcpArrowTool::Activate ()
{
	gtk_spin_button_set_value (m_LengthBtn, m_pApp->GetActiveDocument ()->GetArrowLength ());
}


syntax highlighted by Code2HTML, v. 0.9.1