[goffice] Canvas enhancements from frob.



commit d7d765e99a5bb7d405953c951c26459d946d2f81
Author: Jean Brefort <jean brefort normalesup org>
Date:   Mon Mar 1 16:44:31 2010 +0100

    Canvas enhancements from frob.

 ChangeLog                       |   17 ++
 NEWS                            |    3 +
 goffice/canvas/Makefile.am      |    2 +
 goffice/canvas/goc-arc.c        |  468 +++++++++++++++++++++++++++++++++++++++
 goffice/canvas/goc-arc.h        |   51 +++++
 goffice/canvas/goc-polyline.c   |  132 +++++------
 goffice/canvas/goffice-canvas.h |    2 +
 goffice/utils/go-bezier.c       |    9 +-
 goffice/utils/go-bezier.h       |    2 +-
 po/ChangeLog                    |    4 +
 po/POTFILES.in                  |    1 +
 tests/Makefile.am               |    5 +-
 tests/shapes-demo.c             |  181 +++++++++++++++
 13 files changed, 801 insertions(+), 76 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b561a3b..6a1fb1f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2010-03-01  Valek Filippov  <frob gnome org>
+
+	* goffice/canvas/Makefile.am: add arc support.
+	* goffice/canvas/goc-arc.c: ditto
+	* goffice/canvas/goc-arc.h: ditto
+	* goffice/canvas/goc-polyline.c (goc_polyline_prepare_draw),
+	(goc_polyline_update_bounds), (goc_polyline_distance),
+	(goc_polyline_draw): enhance polyline implementation.
+	* goffice/canvas/goffice-canvas.h: add arc support.
+	* tests/Makefile.am: new demo.
+	* tests/shapes-demo.c: ditto.
+
+2010-03-01  Jean Brefort  <jean brefort normalesup org>
+	* goffice/utils/go-bezier.c (go_bezier_spline_to_cairo): add a flag to
+	support rendering in an RTL canvas.
+	* goffice/utils/go-bezier.h: ditto.
+
 2010-02-26  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/graph/gog-chart-map.c (make_path_cspline): correctly manage
diff --git a/NEWS b/NEWS
index 3d8da3f..b04fa1c 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@ Jean:
 	* Fix crash in GogGuru. [#610435]
 	* Fix cubic splines with invalid data. [#611163]
 
+Valek:
+	* Canvas improvements.
+
 --------------------------------------------------------------------------
 goffice 0.8.0:
 
diff --git a/goffice/canvas/Makefile.am b/goffice/canvas/Makefile.am
index 0083dca..993131b 100644
--- a/goffice/canvas/Makefile.am
+++ b/goffice/canvas/Makefile.am
@@ -1,6 +1,7 @@
 noinst_LTLIBRARIES = libgoffice-canvas.la
 
 libgoffice_canvas_la_SOURCES =	\
+	goc-arc.c		\
 	goc-canvas.c		\
 	goc-circle.c		\
 	goc-ellipse.c		\
@@ -19,6 +20,7 @@ libgoffice_canvas_la_SOURCES =	\
 
 libgoffice_canvas_ladir = $(goffice_include_dir)/canvas
 libgoffice_canvas_la_HEADERS =	\
+	goc-arc.h		\
 	goc-canvas.h		\
 	goc-circle.h		\
 	goc-ellipse.h		\
diff --git a/goffice/canvas/goc-arc.c b/goffice/canvas/goc-arc.c
new file mode 100644
index 0000000..c5a36e2
--- /dev/null
+++ b/goffice/canvas/goc-arc.c
@@ -0,0 +1,468 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-arc.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (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 <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+/**
+ * SECTION:goc-arc
+ * @short_description: Simple elliptic arc.
+ *
+ * #GocArc implements simple elliptic arc drawing in the canvas. The arc can have
+ * arrows at the start and/or at the end.
+**/
+
+enum {
+	ARC_PROP_0,
+	ARC_PROP_XC,
+	ARC_PROP_YC,
+	ARC_PROP_XR,
+	ARC_PROP_YR,
+	ARC_PROP_ANG1,
+	ARC_PROP_ANG2,
+	ARC_PROP_ROTATION,
+	ARC_PROP_TYPE,
+	ARC_PROP_START_ARROW,
+	ARC_PROP_END_ARROW
+};
+
+enum {
+	ARC_TYPE_ARC,
+	ARC_TYPE_CHORD,
+	ARC_TYPE_PIE
+};
+	
+static void
+goc_arc_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocArc *arc = GOC_ARC (gobject);
+
+	switch (param_id) {
+	case ARC_PROP_XC:
+		arc->xc = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_YC:
+		arc->yc = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_XR:
+		arc->xr = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_YR:
+		arc->yr = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_ANG1:
+		arc->ang1 = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_ANG2:
+		arc->ang2 = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_ROTATION:
+		arc->rotation = g_value_get_double (value);
+		break;
+
+	case ARC_PROP_TYPE:
+		arc->type = g_value_get_int (value);
+		break;
+
+	case ARC_PROP_START_ARROW:
+		arc->start_arrow = *((GOArrow *) g_value_peek_pointer (value));
+		break;
+
+	case ARC_PROP_END_ARROW:
+		arc->end_arrow = *((GOArrow *) g_value_peek_pointer (value));
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+}
+
+static void
+goc_arc_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocArc *arc = GOC_ARC (gobject);
+
+	switch (param_id) {
+	case ARC_PROP_XC:
+		g_value_set_double (value, arc->xc);
+		break;
+
+	case ARC_PROP_YC:
+		g_value_set_double (value, arc->yc);
+		break;
+
+	case ARC_PROP_XR:
+		g_value_set_double (value, arc->xr);
+		break;
+
+	case ARC_PROP_YR:
+		g_value_set_double (value, arc->yr);
+		break;
+
+	case ARC_PROP_ANG1:
+		g_value_set_double (value, arc->ang1);
+		break;
+
+	case ARC_PROP_ANG2:
+		g_value_set_double (value, arc->ang2);
+		break;
+
+	case ARC_PROP_ROTATION:
+		g_value_set_double (value, arc->rotation);
+		break;
+
+	case ARC_PROP_TYPE:
+		g_value_set_int (value, arc->type);
+		break;
+		
+	case ARC_PROP_START_ARROW:
+		g_value_set_boxed (value, &arc->start_arrow);
+		break;
+
+	case ARC_PROP_END_ARROW:
+		g_value_set_boxed (value, &arc->end_arrow);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+handle_arrow_bounds (GOArrow const *arrow, GocItem *item)
+{
+	/*
+	 * Do not calculate things precisely, just add enough room
+	 * in all directions.
+	 */
+
+	switch (arrow->typ) {
+	case GO_ARROW_NONE:
+		break;
+	case GO_ARROW_KITE: {
+		double d = hypot (arrow->b, arrow->c);
+		item->x0 -= d;
+		item->x1 += d;
+		item->y0 -= d;
+		item->y1 += d;
+		break;
+	}
+	case GO_ARROW_OVAL: {
+		double d = MAX (arrow->a, arrow->b);
+		item->x0 -= d;
+		item->x1 += d;
+		item->y0 -= d;
+		item->y1 += d;
+		break;
+	}
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+static void
+goc_arc_start (GocItem const *item, double x, double y)
+{
+	GocArc *arc = GOC_ARC (item);
+	double x1, y1, s;
+
+	x1 = arc->xr * cos (atan2 (arc->xr / arc->yr * sin (arc->ang1), cos (arc->ang1)));
+	y1 = arc->yr * sin (atan2 (arc->xr / arc->yr * sin (arc->ang1), cos (arc->ang1)));
+	s = sqrt (x1 * x1 + y1 * y1);
+	
+	x = arc->xc + s * cos (arc->ang1 - arc->rotation);
+	y = arc->yc - s * sin (arc->ang1 - arc->rotation);
+}
+
+static void
+goc_arc_end (GocItem const *item, double x, double y)
+{
+	GocArc *arc = GOC_ARC (item);
+	double x1, y1, s;
+
+	x1 = arc->xr * cos (atan2 (arc->xr / arc->yr * sin (arc->ang2), cos (arc->ang2)));
+	y1 = arc->yr * sin (atan2 (arc->xr / arc->yr * sin (arc->ang2), cos (arc->ang2)));
+	s = sqrt (x1 * x1 + y1 * y1);
+	
+	x = arc->xc + s * cos (arc->ang2 - arc->rotation);
+	y = arc->yc - s * sin (arc->ang2 - arc->rotation);
+}
+
+static gboolean
+goc_arc_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
+{
+	GocArc *arc = GOC_ARC (item);
+	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+	double ecc = 1;
+
+	if (0 == arc->xr || 0 == arc->yr || arc->ang1 == arc->ang2)
+		return FALSE;
+
+	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr) ||
+		(arc->type > 0 && go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))) { // anything with stroke or Chord/Pie with fill only
+		cairo_save (cr);
+		if (1 == flag) {
+			goc_group_cairo_transform (item->parent, cr, arc->xc, arc->yc);
+		} else {
+			cairo_translate (cr, arc->xc, arc->yc);
+		}
+		cairo_rotate (cr, arc->rotation);
+		ecc = arc->xr / arc->yr;
+		cairo_scale (cr, arc->xr * sign, arc->yr);
+		cairo_arc_negative (cr, 0., 0., 1., -atan2 (ecc * sin (arc->ang1), cos (arc->ang1)), -atan2 (ecc * sin (arc->ang2), cos (arc->ang2)));
+		if (ARC_TYPE_PIE == arc->type)
+			cairo_line_to (cr, 0., 0.);//arc->xc,arc->yc); // together with next one gives Pie
+		if (arc->type > 0)
+			cairo_close_path (cr); // <-- gives "Chord"
+		cairo_restore (cr);
+		return TRUE;
+	}
+	
+	return FALSE;
+
+}
+
+
+static void
+goc_arc_update_bounds (GocItem *item)
+{
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, goc_canvas_get_width(item->canvas),goc_canvas_get_height(item->canvas));
+	cr = cairo_create (surface);
+
+	if (goc_arc_prepare_draw (item, cr, 0)) {
+		cairo_stroke_extents (cr, &item->x0, &item->y0, &item->x1, &item->y1);
+	}
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+}
+
+static double
+goc_arc_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocArc *arc = GOC_ARC (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	double tmp_width = 0;
+	double res = 20;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	if (0 == arc->xr || 0 == arc->yr || arc->ang1 == arc->ang2)
+		return res;
+
+	*near_item = item;
+	tmp_width = style->line.width;
+	if (style->line.width < 5){
+		style->line.width = 5;
+	}
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, goc_canvas_get_width(item->canvas),goc_canvas_get_height(item->canvas));
+	cr = cairo_create (surface);
+
+	if (goc_arc_prepare_draw (item, cr, 0)){
+		if (arc->type > 0){
+			if (cairo_in_fill (cr, x, y))
+				res = 0;
+		}
+		if (cairo_in_stroke (cr, x, y))
+			res = 0;
+	}
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+	style->line.width = tmp_width;
+	return res;
+}
+
+static void
+draw_arrow (GOArrow const *arrow, cairo_t *cr, GOStyle *style,
+	    double *endx, double *endy, double phi)
+{
+	double l, w;
+
+	if (arrow->typ == GO_ARROW_NONE)
+		return;
+
+	l = hypot (*endx, *endy);
+	w = style->line.width ? style->line.width / 2.0 : 0.5;
+
+	switch (arrow->typ) {
+	case GO_ARROW_KITE:
+		cairo_save (cr);
+		cairo_translate (cr, (int) *endx, (int) *endy);
+		cairo_rotate (cr, phi);
+		cairo_move_to (cr, -arrow->a, w);
+		cairo_line_to (cr, -arrow->b, w + arrow->c);
+		cairo_line_to (cr, 0., 0.);
+		cairo_line_to (cr, -arrow->b, -w - arrow->c);
+		cairo_line_to (cr, -arrow->a, -w);
+		cairo_close_path (cr);
+		cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.color));
+		cairo_fill (cr);
+		cairo_restore (cr);
+		if (l > 0.) {
+			(*endx) -= arrow->a * *endx / l;
+			(*endy) -= arrow->a * *endy / l;
+		} else
+			*endx = *endy = 0.;
+		break;
+
+	case GO_ARROW_OVAL:
+		cairo_save (cr);
+		cairo_translate (cr, *endx, *endy);
+		cairo_rotate (cr, phi);
+		cairo_scale (cr, arrow->a, arrow->b);
+		cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+		cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.color));
+		cairo_fill (cr);
+		cairo_restore (cr);
+		break;
+
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+static void
+goc_arc_draw (GocItem const *item, cairo_t *cr)
+{
+	GocArc *arc = GOC_ARC (item);
+	
+	cairo_save(cr);
+	if (goc_arc_prepare_draw (item, cr, 1)) {
+		if (arc->type > 0 && go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))
+			cairo_fill_preserve (cr);
+		if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr)){
+			cairo_stroke (cr);
+		} else {
+			cairo_new_path (cr);
+		}
+	}
+	cairo_restore(cr);
+}
+
+static void
+goc_arc_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_LINE;
+	if (style->line.auto_dash)
+		style->line.dash_type = GO_LINE_SOLID;
+	if (style->line.auto_color)
+		style->line.color = GO_COLOR_BLACK;
+	if (style->line.auto_fore)
+		style->line.fore  = 0;
+}
+
+static void
+goc_arc_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	gsi_klass->init_style = goc_arc_init_style;
+
+	obj_klass->get_property = goc_arc_get_property;
+	obj_klass->set_property = goc_arc_set_property;
+	g_object_class_install_property (obj_klass, ARC_PROP_XC,
+		g_param_spec_double ("xc",
+			_("xc"),
+			_("The arc center x coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_YC,
+		g_param_spec_double ("yc",
+			_("yc"),
+			_("The arc center y coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_XR,
+		g_param_spec_double ("xr",
+			_("xr"),
+			_("The arc x radius"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_YR,
+		g_param_spec_double ("yr",
+			_("yr"),
+			_("The arc y radius"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_ANG1,
+		g_param_spec_double ("ang1",
+			_("ang1"),
+			_("The arc start angle"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_ANG2,
+		g_param_spec_double ("ang2",
+			_("ang2"),
+			_("The arc end angle"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_ROTATION,
+		g_param_spec_double ("rotation",
+			_("Rotation"),
+			_("The rotation around center position"),
+			0., 2 * M_PI, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_TYPE,
+		g_param_spec_int ("type",
+			_("Type"),
+			_("The type of arc: arc, chord or pie"),
+			0, 2, 0,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+			
+	g_object_class_install_property (obj_klass, ARC_PROP_START_ARROW,
+		g_param_spec_boxed ("start-arrow",
+			_("Start Arrow"),
+			_("Arrow for line's start"),
+			GO_ARROW_TYPE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ARC_PROP_END_ARROW,
+		g_param_spec_boxed ("end-arrow",
+			_("End Arrow"),
+			_("Arrow for line's end"),
+			GO_ARROW_TYPE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->update_bounds = goc_arc_update_bounds;
+	item_klass->distance = goc_arc_distance;
+	item_klass->draw = goc_arc_draw;
+}
+
+GSF_CLASS (GocArc, goc_arc,
+	   goc_arc_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-arc.h b/goffice/canvas/goc-arc.h
new file mode 100644
index 0000000..4422031
--- /dev/null
+++ b/goffice/canvas/goc-arc.h
@@ -0,0 +1,51 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-arc.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (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
+ */
+
+#ifndef GOC_ARC_H
+#define GOC_ARC_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocArc {
+	GocStyledItem base;
+
+	double rotation;
+	/* part of the ellipse: center, radiuses, angles */
+	double xc, yc, xr, yr, ang1, ang2;
+	int type;
+
+	GOArrow start_arrow, end_arrow;
+};
+
+typedef GocStyledItemClass GocArcClass;
+
+#define GOC_TYPE_ARC	(goc_arc_get_type ())
+#define GOC_ARC(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_ARC, GocArc))
+#define GOC_IS_ARC(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_ARC))
+
+GType goc_arc_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_ARC_H */
diff --git a/goffice/canvas/goc-polyline.c b/goffice/canvas/goc-polyline.c
index c62302a..eb65755 100644
--- a/goffice/canvas/goc-polyline.c
+++ b/goffice/canvas/goc-polyline.c
@@ -91,34 +91,49 @@ goc_polyline_get_property (GObject *gobject, guint param_id,
 	}
 }
 
-static void
-goc_polyline_update_bounds (GocItem *item)
+static gboolean
+goc_polyline_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
 {
 	GocPolyline *polyline = GOC_POLYLINE (item);
-	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	double extra_width = style->line.width;
 	unsigned i;
-	if (extra_width <= 0.)
-		extra_width = 1.;
+	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+
 	if (polyline->nb_points == 0)
-		return;
-	/* FIXME: implement the use_spline case */
-	item->x0 = item->x1 = polyline->points[0].x;
-	item->y0 = item->y1 = polyline->points[0].y;
-	for (i = 1; i < polyline->nb_points; i++) {
-		if (polyline->points[i].x < item->x0)
-			item->x0 = polyline->points[i].x;
-		else if (polyline->points[i].x > item->x1)
-			item->x1 = polyline->points[i].x;
-		if (polyline->points[i].y < item->y0)
-			item->y0 = polyline->points[i].y;
-		else if (polyline->points[i].y > item->y1)
-			item->y1 = polyline->points[i].y;
+		return FALSE;
+
+	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr)) {
+		if (1 == flag) {
+			goc_group_cairo_transform (item->parent, cr, polyline->points[0].x, polyline->points[0].y);
+			cairo_move_to (cr, 0., 0.);
+		} else {
+			cairo_move_to (cr, polyline->points[0].x, polyline->points[0].y);
+		}
+		/* FIXME: implement the use_spline case */
+		for (i = 1; i < polyline->nb_points; i++)
+			cairo_line_to (cr, (polyline->points[i].x - polyline->points[0].x * flag) * sign,
+				polyline->points[i].y - polyline->points[0].y * flag);
+		
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+goc_polyline_update_bounds (GocItem *item)
+{
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, goc_canvas_get_width(item->canvas),goc_canvas_get_height(item->canvas));
+	cr = cairo_create (surface);
+
+	if (goc_polyline_prepare_draw (item, cr, 0)) {
+		cairo_stroke_extents (cr, &item->x0, &item->y0, &item->x1, &item->y1);
 	}
-	item->x0 -= extra_width;
-	item->y0 -= extra_width;
-	item->x1 -= extra_width;
-	item->y1 -= extra_width;
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
 }
 
 static double
@@ -126,63 +141,40 @@ goc_polyline_distance (GocItem *item, double x, double y, GocItem **near_item)
 {
 	GocPolyline *polyline = GOC_POLYLINE (item);
 	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	/* FIXME: implement the use_spline case */
-	double extra_width = (style->line.width)? style->line.width /2.: .5;
-	double dx, dy, l, startx, starty, x_, y_, t, res;
-	unsigned i;
+	double tmp_width = 0;
+	double res = 20;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	if (polyline->nb_points == 0)
+		return res;
 
 	*near_item = item;
-	/* FIXME: not tested!!! */
-	/* first test if the point is inside the polygon */
-	startx = polyline->points[0].x;
-	starty = polyline->points[0].y;
-	res = hypot (polyline->points[polyline->nb_points - 1].x - x, polyline->points[polyline->nb_points - 1].y - y);
-	for (i = 0; i < polyline->nb_points; i++) {
-		dx = polyline->points[i].x - startx;
-		dy = polyline->points[i].y - starty;
-		l = hypot (dx, dy);
-		x_ = x - startx;
-		y_ = y - starty;
-		t = (x_ * dx + y_ * dy) / l;
-		y = (-x_ * dy + y_ * dx) / l;
-		x_ = t;
-		*near_item = item;
-		if (x < 0. ) {
-			t = hypot (x_, y_);
-			if (t < res)
-				res = t;
-		} else if (t <= l) {
-			if (y_ < res)
-				res = y_;
-		}
-		startx = polyline->points[i].x;
-		starty = polyline->points[i].y;
+	tmp_width = style->line.width;
+	if (style->line.width < 5) {
+		style->line.width = 5;
+	}
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, goc_canvas_get_width (item->canvas), goc_canvas_get_height (item->canvas));
+	cr = cairo_create (surface);
+
+	if (goc_polyline_prepare_draw (item,cr,0)) {
+		if (cairo_in_stroke (cr,x,y))
+			res = 0;
 	}
-	res -= extra_width; /* no need to be more precise */
-	return (res > 0.)? res: 0.;
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+	style->line.width = tmp_width;
+	return res;
 }
 
 static void
 goc_polyline_draw (GocItem const *item, cairo_t *cr)
 {
-	GocPolyline *polyline = GOC_POLYLINE (item);
-	unsigned i;
-	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
-	if (polyline->nb_points == 0)
-		return;
 	cairo_save (cr);
-	goc_group_cairo_transform (item->parent, cr, polyline->points[0].x, polyline->points[0].y);
-        cairo_move_to (cr, 0., 0.);
-	/* FIXME: implement the use_spline case */
-
-	for (i = 1; i < polyline->nb_points; i++)
-		cairo_line_to (cr, (polyline->points[i].x - polyline->points[0].x) * sign,
-		               polyline->points[i].y - polyline->points[0].y);
-
-	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+	if (goc_polyline_prepare_draw (item,cr,1)) {
 		cairo_stroke (cr);
-	else
-		cairo_new_path (cr);
+	}
 	cairo_restore (cr);
 }
 
diff --git a/goffice/canvas/goffice-canvas.h b/goffice/canvas/goffice-canvas.h
index 14b8411..4dd3b2c 100644
--- a/goffice/canvas/goffice-canvas.h
+++ b/goffice/canvas/goffice-canvas.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
 typedef struct _GocCanvas	GocCanvas;
 typedef struct _GocItem		GocItem;
 typedef struct _GocGroup	GocGroup;
+typedef struct _GocArc		GocArc;
 typedef struct _GocLine		GocLine;
 typedef struct _GocPixbuf	GocPixbuf;
 typedef struct _GocPolyline	GocPolyline;
@@ -57,6 +58,7 @@ G_END_DECLS
 #include <goffice/canvas/goc-ellipse.h>
 #include <goffice/canvas/goc-graph.h>
 #include <goffice/canvas/goc-group.h>
+#include <goffice/canvas/goc-arc.h>
 #include <goffice/canvas/goc-line.h>
 #include <goffice/canvas/goc-pixbuf.h>
 #include <goffice/canvas/goc-polyline.h>
diff --git a/goffice/utils/go-bezier.c b/goffice/utils/go-bezier.c
index b02d1a3..c091b57 100644
--- a/goffice/utils/go-bezier.c
+++ b/goffice/utils/go-bezier.c
@@ -344,15 +344,16 @@ go_bezier_spline_to_path (GOBezierSpline *sp)
  * Renders the spline in \a cr
  **/
 void
-go_bezier_spline_to_cairo (GOBezierSpline *sp, cairo_t *cr)
+go_bezier_spline_to_cairo (GOBezierSpline *sp, cairo_t *cr, gboolean horiz_flip)
 {
 	int i, j;
+	double sign = horiz_flip? -1: 1;
 	cairo_new_path (cr);
-	cairo_move_to (cr, sp->x[0], sp->y[0]);
+	cairo_move_to (cr, sp->x[0] * sign, sp->y[0]);
 	for (i = j = 1; i < sp->n; i++, j += 3)
-		cairo_curve_to (cr, sp->x[j], sp->y[j], sp->x[j+1], sp->y[j+1], sp->x[j+2], sp->y[j+2]);
+		cairo_curve_to (cr, sp->x[j] * sign, sp->y[j], sp->x[j+1] * sign, sp->y[j+1], sp->x[j+2] * sign, sp->y[j+2]);
 	if (sp->closed) {
-		cairo_curve_to (cr, sp->x[j], sp->y[j], sp->x[j+1], sp->y[j+1], sp->x[0], sp->y[0]);
+		cairo_curve_to (cr, sp->x[j] * sign, sp->y[j], sp->x[j+1] * sign, sp->y[j+1], sp->x[0] * sign, sp->y[0]);
 		cairo_close_path (cr);
 	}
 }
diff --git a/goffice/utils/go-bezier.h b/goffice/utils/go-bezier.h
index 1e55cda..9e5480f 100644
--- a/goffice/utils/go-bezier.h
+++ b/goffice/utils/go-bezier.h
@@ -38,7 +38,7 @@ GOBezierSpline *go_bezier_spline_init (double const *x, double const *y, int n,
 void go_bezier_spline_destroy (GOBezierSpline *sp);
 
 GOPath *go_bezier_spline_to_path (GOBezierSpline *sp);
-void go_bezier_spline_to_cairo (GOBezierSpline *sp, cairo_t *cr);
+void go_bezier_spline_to_cairo (GOBezierSpline *sp, cairo_t *cr, gboolean horiz_flip);
 
 G_END_DECLS
 
diff --git a/po/ChangeLog b/po/ChangeLog
index a4767b2..bc1de81 100644
--- a/po/ChangeLog
+++ b/po/ChangeLog
@@ -1,3 +1,7 @@
+2010-03-01  Jean Brefort  <jean brefort normalesup org>
+
+	* POTFILES.in: updated files list.
+
 2010-02-13  Morten Welinder <terra gnome org>
 
 	* Release 0.8.0
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 343b1c6..9c065ca 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -37,6 +37,7 @@ goffice/app/io-context-priv.h
 goffice/app/io-context.c
 goffice/app/io-context.h
 goffice/app/module-plugin-defs.h
+goffice/canvas/goc-arc.c
 goffice/canvas/goc-circle.c
 goffice/canvas/goc-ellipse.c
 goffice/canvas/goc-graph.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1739198..02f7b1b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,5 @@
 if WITH_GTK
-check_PROGRAMS = pie-demo go-demo 
+check_PROGRAMS = pie-demo go-demo shapes-demo
 endif
 
 include $(top_srcdir)/goffice.mk
@@ -12,5 +12,8 @@ pie_demo_SOURCES = pie-demo.c
 go_demo_LDADD = $(GOFFICE_PLUGIN_LIBADD)
 go_demo_SOURCES = go-demo.c
 
+shapes_demo_LDADD = $(GOFFICE_PLUGIN_LIBADD)
+shapes_demo_SOURCES = shapes-demo.c
+
 EXTRA_DIST = go-demo.ui
 
diff --git a/tests/shapes-demo.c b/tests/shapes-demo.c
new file mode 100644
index 0000000..b3e1867
--- /dev/null
+++ b/tests/shapes-demo.c
@@ -0,0 +1,181 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * shapes-demo.c :
+ *
+ * Copyright (C) 2003-2005 Jean Brefort (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 Library 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 <gtk/gtk.h>
+#include <goffice/goffice.h>
+#include <goffice/utils/go-style.h>
+#include <goffice/utils/go-styled-object.h>
+
+
+
+static void
+change_shape (GocItem *goi)
+{
+	GocPoints *points = goc_points_new (4);
+	
+	points->points[0].x = 135;
+	points->points[0].y = 150;
+	points->points[1].x = 114;
+	points->points[1].y = 160;
+	points->points[2].x = 110;
+	points->points[2].y = 180;
+	points->points[3].x = 200;
+	points->points[3].y = 200;
+	
+	goc_item_set (goi, "points", points, NULL);
+
+}
+
+//
+static void
+my_test (GocCanvas *canvas, GdkEventButton *event, G_GNUC_UNUSED gpointer data) {
+	GocItem *item;
+	double x,y;
+	GOStyle *style;
+	
+	g_print ("%.0f %.0f Button: %d\n", event->x, event->y, event->button);
+
+	if (event->window != gtk_layout_get_bin_window (&canvas->base))
+		return;
+		
+	x = (canvas->direction == GOC_DIRECTION_RTL)?
+		canvas->scroll_x1 + (canvas->width - event->x) / canvas->pixels_per_unit:
+		canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+	y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	item = goc_canvas_get_item_at (canvas, x, y);
+	if (item) {
+		style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+		if (style->line.color == GO_COLOR_BLACK) {
+			style->line.color = GO_COLOR_RED;
+		} else {
+			style->line.color = GO_COLOR_BLACK;
+		}
+		goc_item_invalidate (item);
+	}
+	goc_canvas_scroll_to (canvas, 10, -10);
+}
+
+static void
+create_shape (GocCanvas *canvas)
+{
+	GocItem *goi;
+	double x = 180, y = 120, w = 50, h = 20;
+
+	goi = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_RECTANGLE, NULL);
+	goc_item_set (goi, "width", w, "height", h, "x", x, "y", y, NULL);
+	
+
+}
+
+
+static void
+on_quit (GtkObject *object)
+{
+	gtk_object_destroy (object);
+	gtk_main_quit ();
+}
+
+int
+main (int argc, char *argv[])
+{
+	GtkWidget *window, *box, *hbox, *widget;
+	GocCanvas *canvas;
+	GOStyle *style;
+	/* GError *error; */
+	GocItem *goi, *goi2;
+	double xc = 80.,yc = 150., xr = 30.,yr = 60.,ang1=M_PI*0.45,ang2 = M_PI*1.75;
+	GocPoints *points = goc_points_new (5);
+	
+	points->points[0].x = xc + xr * cos (atan2 (xr / yr * sin (ang1), cos (ang1)));
+	points->points[0].y = yc - yr * sin (atan2 (xr / yr * sin (ang1), cos (ang1)));
+	points->points[1].x = 10;
+	points->points[1].y = 40;
+	points->points[2].x = 23;
+	points->points[2].y = 25;
+	points->points[3].x = 120;
+	points->points[3].y = 150;
+	points->points[4].x = xc + xr * cos (atan2 (xr / yr * sin (ang2), cos (ang2)));
+	points->points[4].y = yc - yr * sin (atan2 (xr / yr * sin (ang2), cos (ang2)));
+
+	g_print("Arc: %.0f %.0f %.0f %.0f\n", points->points[0].x, points->points[0].y, points->points[4].x, points->points[4].y);
+
+	gtk_init (&argc, &argv);
+	/* Initialize libgoffice */
+	libgoffice_init ();
+	/* Initialize plugins manager */
+
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_resize (GTK_WINDOW (window), 300, 340);
+	gtk_window_set_title (GTK_WINDOW (window), "shapes demo");
+	g_signal_connect (window, "destroy", gtk_main_quit, NULL);
+
+	box = gtk_vbox_new (FALSE, 0);
+	hbox = gtk_hbox_new (FALSE, 0);
+	canvas =g_object_new (GOC_TYPE_CANVAS, NULL);
+	g_signal_connect_swapped (canvas, "button-press-event", G_CALLBACK (my_test), canvas);
+
+	goi = goc_item_new(goc_canvas_get_root (canvas), GOC_TYPE_POLYLINE, NULL);
+	goc_item_set (goi, "points", points, NULL);
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (goi));
+	style->line.width = 1;
+	style->line.color = GO_COLOR_BLACK;
+
+	goi2 = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_ARC,
+	 "xc", xc, "yc", yc, "xr",xr, "yr", yr,
+	 "ang1", ang1, "ang2", ang2, NULL);
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (goi2));
+	style->line.width = 3;
+	style->line.color = GO_COLOR_YELLOW;
+
+	goi2 = goc_item_new (goc_canvas_get_root(canvas), GOC_TYPE_ARC,
+	 "xc", xc, "yc", yc, "xr", xr, "yr", yr,
+	 "ang1", ang1, "ang2", ang2, "rotation", M_PI / 4., NULL);
+
+	widget = gtk_button_new_from_stock (GTK_STOCK_QUIT);
+	g_signal_connect_swapped (widget, "clicked", G_CALLBACK (on_quit), window);
+	gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+	widget = gtk_button_new_from_stock (GTK_STOCK_NEW);
+	g_signal_connect_swapped (widget, "clicked", G_CALLBACK (create_shape), canvas);
+	gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+	widget = gtk_button_new_from_stock (GTK_STOCK_OPEN);
+	g_signal_connect_swapped (widget, "clicked", G_CALLBACK (change_shape), goi);
+	gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+
+	gtk_box_pack_end (GTK_BOX (box), hbox, FALSE, FALSE, 0);
+
+	widget = gtk_hseparator_new ();
+	gtk_box_pack_end (GTK_BOX (box), widget, FALSE, FALSE, 2);
+
+	gtk_box_pack_end (GTK_BOX (box), GTK_WIDGET(canvas), TRUE, TRUE, 0);
+
+	gtk_container_add (GTK_CONTAINER (window), box);
+	gtk_widget_show_all (GTK_WIDGET (window));
+
+	widget = gtk_hseparator_new ();
+	gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+	gtk_main ();
+
+	/* Clean libgoffice stuff */
+	libgoffice_shutdown ();
+	return 0;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]