[goffice] More canvas enhancements.



commit 71755a8614c9026d8ec10d6f7b522b0fc4031d6b
Author: Jean Brefort <jean brefort normalesup org>
Date:   Thu Mar 4 13:17:00 2010 +0100

    More canvas enhancements.

 ChangeLog                      |   12 ++++
 goffice/canvas/goc-arc.c       |   58 +++++++++-------
 goffice/canvas/goc-ellipse.c   |  144 +++++++++++++++++++++-------------------
 goffice/canvas/goc-rectangle.c |  126 +++++++++++++++++++++--------------
 4 files changed, 196 insertions(+), 144 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 7da88fb..e759dbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2010-03-04  Valek Filippov  <frob gnome org>
+
+	* goffice/canvas/goc-arc.c (goc_arc_prepare_draw),
+	(goc_arc_distance), (goc_arc_draw), (goc_arc_init_style): more
+	canvas improvements.
+	* goffice/canvas/goc-ellipse.c (goc_ellipse_prepare_draw),
+	(goc_ellipse_update_bounds), (goc_ellipse_distance),
+	(goc_ellipse_draw), (goc_ellipse_class_init): ditto.
+	* goffice/canvas/goc-rectangle.c (goc_rectangle_prepare_draw),
+	(goc_rectangle_update_bounds), (goc_rectangle_distance),
+	(goc_rectangle_draw), (goc_rectangle_class_init): ditto.
+
 2010-03-03  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/canvas/goc-line.c (goc_line_distance): fix distance evaluation.
diff --git a/goffice/canvas/goc-arc.c b/goffice/canvas/goc-arc.c
index 1407d1f..0701f4a 100644
--- a/goffice/canvas/goc-arc.c
+++ b/goffice/canvas/goc-arc.c
@@ -231,31 +231,24 @@ goc_arc_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
 	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;
+	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);
 	}
-	
-	return FALSE;
-
+	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.); // together with next one gives Pie
+	if (arc->type > 0)
+		cairo_close_path (cr); 		// gives "Chord"
+	cairo_restore (cr);
+	return TRUE;
 }
 
-
 static void
 goc_arc_update_bounds (GocItem *item)
 {
@@ -295,12 +288,15 @@ goc_arc_distance (GocItem *item, double x, double y, GocItem **near_item)
 	cr = cairo_create (surface);
 
 	if (goc_arc_prepare_draw (item, cr, 0)){
-		if (arc->type > 0 && style->fill.type != GO_STYLE_FILL_NONE){
+		// Filled OR both fill and stroke are none
+		if ((arc->type > 0 && style->fill.type != GO_STYLE_FILL_NONE) ||
+			(style->fill.type == GO_STYLE_FILL_NONE && !goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))){
 			if (cairo_in_fill (cr, x, y))
 				res = 0;
 		}
-		if (cairo_in_stroke (cr, x, y))
+		if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr) && cairo_in_stroke (cr, x, y)){
 			res = 0;
+		}
 	}
 
 	cairo_destroy (cr);
@@ -369,7 +365,7 @@ goc_arc_draw (GocItem const *item, cairo_t *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)){
+		if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr)) {
 			cairo_stroke (cr);
 		} else {
 			cairo_new_path (cr);
@@ -381,13 +377,23 @@ goc_arc_draw (GocItem const *item, cairo_t *cr)
 static void
 goc_arc_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
-	style->interesting_fields = GO_STYLE_LINE;
+	GocArc *arc = GOC_ARC(item);
+
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
 	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;
+	if (arc->type > 0) {
+		if (style->fill.auto_type)
+			style->fill.type  = GO_STYLE_FILL_PATTERN;
+		if (style->fill.auto_fore)
+			style->fill.pattern.fore = GO_COLOR_BLACK;
+		if (style->fill.auto_back)
+			style->fill.pattern.back = GO_COLOR_WHITE;
+	}
 }
 
 static void
diff --git a/goffice/canvas/goc-ellipse.c b/goffice/canvas/goc-ellipse.c
index acbcd8f..f824682 100644
--- a/goffice/canvas/goc-ellipse.c
+++ b/goffice/canvas/goc-ellipse.c
@@ -107,19 +107,43 @@ goc_ellipse_get_property (GObject *gobject, guint param_id,
 	}
 }
 
+static gboolean
+goc_ellipse_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (item);
+	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+	
+	if (0 == ellipse->width && 0 == ellipse->height)
+		return FALSE;
+		
+	cairo_save(cr);
+	if (1 == flag) {
+		goc_group_cairo_transform (item->parent, cr, ellipse->x + ellipse->width/2., ellipse->y + ellipse->height/2.);
+	} else {
+		cairo_translate (cr, ellipse->x + ellipse->width/2., ellipse->y + ellipse->height/2.);
+	}
+	cairo_rotate (cr, ellipse->rotation);
+	cairo_scale (cr, ellipse->width/2. * sign, ellipse->height/2.);
+	cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+	cairo_restore (cr);
+	return TRUE;
+}
+
 static void
 goc_ellipse_update_bounds (GocItem *item)
 {
-	GocEllipse *ellipse = GOC_ELLIPSE (item);
-	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	/* FIXME: take rotation into account */
-	double extra_width = style->line.width /2.;
-	if (extra_width <= 0.)
-		extra_width = .5;
-	item->x0 = ellipse->x - extra_width;
-	item->y0 = ellipse->y - extra_width;
-	item->x1 = ellipse->x + ellipse->width + extra_width;
-	item->y1 = ellipse->y + ellipse->height + extra_width;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1 , 1);
+	cr = cairo_create (surface);
+
+	if (goc_ellipse_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
@@ -127,70 +151,54 @@ goc_ellipse_distance (GocItem *item, double x, double y, GocItem **near_item)
 {
 	GocEllipse *ellipse = GOC_ELLIPSE (item);
 	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	/* FIXME: take rotation into account */
-	/* FIXME: we just consider that a point inside the ellipse is at distance 0
-	 even if the ellipse is not filled */
-	double extra_width = (style->line.width)? style->line.width /2.: .5;
-	double last = G_MAXDOUBLE, df, d2f, t, cs, sn,
-		a = ellipse->width / 2, b = ellipse->height / 2,
-		c = a * a - b * b;
-	int i;
+	double tmp_width = 0;
+	double res = 20;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	if (0 == ellipse->width && 0 == ellipse->height)
+		return res;
+
 	*near_item = item;
-	x = fabs (x - ellipse->x - a);
-	y = fabs (y - ellipse->y - b);
-	if (y < DBL_EPSILON) {
-		x -= a + extra_width;
-		return (x > 0.)? x: 0.;
-	}
-	if (x < DBL_EPSILON) {
-		y -= b + extra_width;
-		return (y > 0.)? y: 0.;
+	tmp_width = style->line.width;
+	if (style->line.width < 5){
+		style->line.width = 5;
 	}
-	if (hypot (x / a, y / b) < 1.)
-		return 0.;
-
-	/* initial value: */
-	t = atan2 (y, x);
-	/* iterate using the Newton method */
-	/* iterate no more than 10 times which should be largely enough
-	 just a security to avoid an infinite loop if something goes wrong */
-	for (i = 0; i < 10; i++) {
-		cs = cos (t);
-		sn = sin (t);
-		df = a * x * sn - b * y * cs - c * cs * sn;
-		d2f = a * x * cs + b * y * sn - c * (cs * cs - sn * sn);
-		t -= df / d2f;
-		if ( last == df || fabs (df) < DBL_EPSILON || fabs (df) >= fabs (last))
-			break;
-		last = df;
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+	cr = cairo_create (surface);
+
+	if (goc_ellipse_prepare_draw (item, cr, 0)) {
+		// Filled OR both fill and stroke are none
+		if (style->fill.type != GO_STYLE_FILL_NONE ||
+			(style->fill.type == GO_STYLE_FILL_NONE && !goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))) {
+			if (cairo_in_fill (cr, x, y))
+				res = 0;
+		}
+		if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr) && cairo_in_stroke (cr, x, y)) {
+			res = 0;
+		}
 	}
-	/* evaluate the distance and store in df */
-	df = hypot (x - a * cos (t), y - b * sin (t)) - extra_width;
-	return (df > 0.)? df: 0.;
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+	style->line.width = tmp_width;
+	return res;
 }
 
 static void
 goc_ellipse_draw (GocItem const *item, cairo_t *cr)
 {
-	GocEllipse *ellipse = GOC_ELLIPSE (item);
-	double  scalex = (ellipse->width > 0.)? ellipse->width / 2.: 1.e-10,
-		scaley = (ellipse->height > 0.)? ellipse->height / 2.: 1.e-10;
-	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
-	cairo_save (cr);
-	goc_group_cairo_transform (item->parent, cr, ellipse->x, ellipse->y);
-	cairo_translate (cr, scalex * sign, scaley);
-	cairo_scale (cr, scalex, scaley);
-	cairo_rotate (cr, ellipse->rotation);
-	cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
-	cairo_restore (cr);
-	/* Fill the shape */
-	if (go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))
-		cairo_fill_preserve (cr);
-	/* Draw the line */
-	if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))
-		cairo_stroke (cr);
-	else
-		cairo_new_path (cr);
+	cairo_save(cr);
+	if (goc_ellipse_prepare_draw (item, cr, 1)) {
+		if (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
@@ -241,12 +249,12 @@ goc_ellipse_class_init (GocItemClass *item_klass)
 			_("The ellipse height"),
 			0., G_MAXDOUBLE, 0.,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-/*	g_object_class_install_property (obj_klass, ELLIPSE_PROP_ROTATION,
+	g_object_class_install_property (obj_klass, ELLIPSE_PROP_ROTATION,
 		g_param_spec_double ("rotation",
 			_("Rotation"),
 			_("The rotation around top left position"),
 			0., 2 * M_PI, 0.,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
 
 	gsi_klass->init_style = goc_ellipse_init_style;
 
diff --git a/goffice/canvas/goc-rectangle.c b/goffice/canvas/goc-rectangle.c
index 6c36a8f..6732b6e 100644
--- a/goffice/canvas/goc-rectangle.c
+++ b/goffice/canvas/goc-rectangle.c
@@ -107,19 +107,41 @@ goc_rectangle_get_property (GObject *gobject, guint param_id,
 	}
 }
 
+static gboolean
+goc_rectangle_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
+{
+	GocRectangle *rect = GOC_RECTANGLE (item);
+	
+	if (0 == rect->width && 0 == rect->height)
+		return FALSE;
+		
+	cairo_save(cr);
+	if (1 == flag) {
+		goc_group_cairo_transform (item->parent, cr, rect->x, rect->y);
+	} else {
+		cairo_translate (cr, rect->x, rect->y);
+	}
+	cairo_rotate (cr, rect->rotation);
+	cairo_rectangle (cr, 0., 0., (int) rect->width, (int)rect->height);
+	cairo_restore (cr);
+	return TRUE;
+}
+
 static void
 goc_rectangle_update_bounds (GocItem *item)
 {
-	GocRectangle *rect = GOC_RECTANGLE (item);
-	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	/* FIXME: take rotation into account */
-	double extra_width = style->line.width /2.;
-	if (extra_width <= 0.)
-		extra_width = .5;
-	item->x0 = rect->x - extra_width;
-	item->y0 = rect->y - extra_width;
-	item->x1 = rect->x + rect->width + extra_width;
-	item->y1 = rect->y + rect->height + extra_width;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1 , 1);
+	cr = cairo_create (surface);
+
+	if (goc_rectangle_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
@@ -127,51 +149,55 @@ goc_rectangle_distance (GocItem *item, double x, double y, GocItem **near_item)
 {
 	GocRectangle *rect = GOC_RECTANGLE (item);
 	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-	/* FIXME: take rotation into account */
-	double extra_width = (style->line.width)? style->line.width /2.: .5;
-	double dx, dy;
-	if (x < rect->x - extra_width) {
-		dx = rect->x - extra_width - x;
-	} else if (x < rect->x + rect->width + extra_width) {
-		dx = 0;
-	} else {
-		dx = x - extra_width - rect->x - rect->width;
+
+	double tmp_width = 0;
+	double res = 20;
+	cairo_surface_t *surface;
+	cairo_t *cr;
+
+	if (0 == rect->width && 0 == rect->height)
+		return res;
+
+	*near_item = item;
+	tmp_width = style->line.width;
+	if (style->line.width < 5){
+		style->line.width = 5;
 	}
-	if (y < rect->y - extra_width) {
-		dy = rect->y - extra_width - y;
-	} else if (y < rect->y + rect->height + extra_width) {
-		dy = 0;
-	} else {
-		dy = y - extra_width - rect->y - rect->height;
+	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+	cr = cairo_create (surface);
+
+	if (goc_rectangle_prepare_draw (item, cr, 0)) {
+		// Filled OR both fill and stroke are none
+		if (style->fill.type != GO_STYLE_FILL_NONE ||
+			(style->fill.type == GO_STYLE_FILL_NONE && !goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))) {
+			if (cairo_in_fill (cr, x, y))
+				res = 0;
+		}
+		if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr) && cairo_in_stroke (cr, x, y)) {
+			res = 0;
+		}
 	}
-	*near_item = item;
-	return hypot (dx, dy);
+
+	cairo_destroy (cr);
+	cairo_surface_destroy (surface);
+	style->line.width = tmp_width;
+	return res;
 }
 
 static void
 goc_rectangle_draw (GocItem const *item, cairo_t *cr)
 {
-	GocRectangle *rect = GOC_RECTANGLE (item);
-	double hoffs, voffs = ceil (go_styled_object_get_style (GO_STYLED_OBJECT (item))->line.width);
-	if (voffs <= 0.)
-		voffs = 1.;
-	hoffs = ((int) voffs & 1)? .5: 0.;
-	voffs = hoffs;
-	if (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)
-		hoffs += (int) rect->width;
-	cairo_save (cr);
-	goc_group_cairo_transform (item->parent, cr, hoffs + (int) rect->x, voffs + (int) rect->y);
-	cairo_rotate (cr, rect->rotation);
-	cairo_rectangle (cr, 0., 0., (int) rect->width, (int)rect->height);
-	cairo_restore (cr);
-	/* Fill the shape */
-	if (go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))
-		cairo_fill_preserve (cr);
-	/* Draw the line */
-	if (goc_styled_item_set_cairo_line (GOC_STYLED_ITEM (item), cr))
-		cairo_stroke (cr);
-	else
-		cairo_new_path (cr);
+	cairo_save(cr);
+	if (goc_rectangle_prepare_draw (item, cr, 1)) {
+		if (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
@@ -222,12 +248,12 @@ goc_rectangle_class_init (GocItemClass *item_klass)
 			_("The rectangle height"),
 			0., G_MAXDOUBLE, 0.,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-/*	g_object_class_install_property (obj_klass, RECT_PROP_ROTATION,
+	g_object_class_install_property (obj_klass, RECT_PROP_ROTATION,
 		g_param_spec_double ("rotation",
 			_("Rotation"),
 			_("The rotation around top left position"),
 			0., 2 * M_PI, 0.,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
 
 	gsi_klass->init_style = goc_rectangle_init_style;
 



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