[goffice] Canvas: lines can have arrows in either end.



commit bdb0c406fdbe4bbbc53e2747508e531cdf2d135f
Author: Morten Welinder <terra gnome org>
Date:   Wed Oct 14 14:18:59 2009 -0400

    Canvas: lines can have arrows in either end.

 ChangeLog                 |    8 ++
 NEWS                      |    3 +
 goffice/canvas/goc-line.c |  176 ++++++++++++++++++++++++---------------------
 goffice/canvas/goc-line.h |    4 +-
 4 files changed, 108 insertions(+), 83 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 26327c5..f1f1b6d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-10-14  Morten Welinder  <terra gnome org>
 
+	* goffice/canvas/goc-line.c (goc_line_class_init): Change to
+	GOArrow for arrow properties.
+
+	* goffice/canvas/goc-line.h (struct _GocLine): Have an arrow at
+	both ends.
+
+	* goffice/canvas/goc-line.c (goc_line_draw): Draw point arrows.
+
 	* goffice/utils/go-line.c (go_arrow_init, go_arrow_get_type,
 	go_arrow_clear, go_arrow_dup): New functions.
 
diff --git a/NEWS b/NEWS
index 0a2f38d..122069f 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ Jean:
 	* Fix bounds update of GocItem. [#598091]
 	* Prepare for GSEAL_ENABLE.
 
+Morten:
+	* Canvas improvements for arrows.
+
 --------------------------------------------------------------------------
 goffice 0.7.14:
 
diff --git a/goffice/canvas/goc-line.c b/goffice/canvas/goc-line.c
index c3b4549..8ced147 100644
--- a/goffice/canvas/goc-line.c
+++ b/goffice/canvas/goc-line.c
@@ -30,7 +30,7 @@
  * @short_description: Simple line.
  *
  * #GocLine implements simple line drawing in the canvas. The line can have
- * an arrowhead at its end.
+ * arrows at the start and/or at the end.
 **/
 
 enum {
@@ -39,10 +39,8 @@ enum {
 	LINE_PROP_Y0,
 	LINE_PROP_X1,
 	LINE_PROP_Y1,
-	LINE_PROP_ARROWHEAD,
-	LINE_PROP_ARROW_SHAPE_A,
-	LINE_PROP_ARROW_SHAPE_B,
-	LINE_PROP_ARROW_SHAPE_C
+	LINE_PROP_START_ARROW,
+	LINE_PROP_END_ARROW
 };
 
 static void
@@ -68,20 +66,12 @@ goc_line_set_property (GObject *gobject, guint param_id,
 		line->endy = g_value_get_double (value);
 		break;
 
-	case LINE_PROP_ARROWHEAD:
-		line->arrowhead = g_value_get_boolean (value);
+	case LINE_PROP_START_ARROW:
+		line->start_arrow = *((GOArrow *)g_value_peek_pointer (value));
 		break;
 
-	case LINE_PROP_ARROW_SHAPE_A:
-		line->headA = g_value_get_double (value);
-		break;
-
-	case LINE_PROP_ARROW_SHAPE_B:
-		line->headB = g_value_get_double (value);
-		break;
-
-	case LINE_PROP_ARROW_SHAPE_C:
-		line->headC = g_value_get_double (value);
+	case LINE_PROP_END_ARROW:
+		line->end_arrow = *((GOArrow *)g_value_peek_pointer (value));
 		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
@@ -113,20 +103,12 @@ goc_line_get_property (GObject *gobject, guint param_id,
 		g_value_set_double (value, line->endy);
 		break;
 
-	case LINE_PROP_ARROWHEAD:
-		g_value_set_boolean (value, line->arrowhead);
-		break;
-
-	case LINE_PROP_ARROW_SHAPE_A:
-		g_value_set_double (value, line->headA);
-		break;
-
-	case LINE_PROP_ARROW_SHAPE_B:
-		g_value_set_double (value, line->headB);
+	case LINE_PROP_START_ARROW:
+		g_value_set_boxed (value, &line->start_arrow);
 		break;
 
-	case LINE_PROP_ARROW_SHAPE_C:
-		g_value_set_double (value, line->headC);
+	case LINE_PROP_END_ARROW:
+		g_value_set_boxed (value, &line->end_arrow);
 		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
@@ -158,9 +140,20 @@ goc_line_update_bounds (GocItem *item)
 		item->y0 = line->endy - extra_width;
 		item->y1 = line->starty + extra_width;
 	}
-	if (line->arrowhead) {
-		/* do not calculate things precisely, just add enough room in all directions */
-		double d = hypot (line->headB, line->headC);
+	if (line->start_arrow.typ) {
+		/*
+		 * Do not calculate things precisely, just add enough room
+		 * in all directions.
+		 */
+		double d = hypot (line->start_arrow.b, line->start_arrow.c);
+		item->x0 -= d;
+		item->x1 += d;
+		item->y0 -= d;
+		item->y1 += d;
+	}
+	if (line->end_arrow.typ) {
+		/* See above.  */
+		double d = hypot (line->end_arrow.b, line->end_arrow.c);
 		item->x0 -= d;
 		item->x1 += d;
 		item->y0 -= d;
@@ -193,44 +186,77 @@ goc_line_distance (GocItem *item, double x, double y, GocItem **near_item)
 	return (t > 0.)? t: 0.;
 }
 
-static void goc_line_draw (GocItem const *item, cairo_t *cr)
+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_TRIANGLE:
+		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;
+
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+static void
+goc_line_draw (GocItem const *item, cairo_t *cr)
 {
 	GocLine *line = GOC_LINE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
 	double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
 	double endx = (line->endx - line->startx) * sign, endy = line->endy - line->starty;
-	double hoffs, voffs = ceil (go_styled_object_get_style (GO_STYLED_OBJECT (item))->line.width);
+	double hoffs, voffs = ceil (style->line.width);
+	double startx = 0, starty = 0;
+	double phi;
+
 	if (line->startx == line->endx && line->starty == line->endy)
 		return;
+
 	if (voffs <= 0.)
 		voffs = 1.;
+
 	hoffs = ((int) voffs & 1)? .5: 0.;
 	voffs = (line->starty == line->endy)? hoffs: 0.;
 	if (line->startx != line->endx)
 	                hoffs = 0.;
+
 	cairo_save (cr);
-	goc_group_cairo_transform (item->parent, cr, hoffs + (int) line->startx, voffs + (int) line->starty);
-	if (line->arrowhead) {
-		GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-		double l = hypot (endx, endy), w = (style->line.width)? style->line.width / 2.: .5;
-		/* display the arrow head */
-		cairo_save (cr);
-		cairo_translate (cr, (int) endx, (int) endy);
-		cairo_rotate (cr, atan2 (endy, endx));
-		cairo_move_to (cr, -line->headA, w);
-		cairo_line_to (cr, -line->headB, w + line->headC);
-		cairo_line_to (cr, 0., 0.);
-		cairo_line_to (cr, -line->headB, -w - line->headC);
-		cairo_line_to (cr, -line->headA, -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 -= line->headA * endx / l;
-			endy -= line->headA * endy / l;
-		} else
-			endx = endy = 0.;
-	}
+	goc_group_cairo_transform (item->parent, cr,
+				   hoffs + (int) line->startx,
+				   voffs + (int) line->starty);
+
+	phi = atan2 (endy, endx);
+	draw_arrow (&line->start_arrow, cr, style,
+		    &startx, &starty, phi + M_PI);
+	draw_arrow (&line->end_arrow, cr, style,
+		    &endx, &endy, phi);
+
         if ((endx != 0. || endy!= 0.) && go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr)) {
 		/* try to avoid horizontal and vertical lines between two pixels */
 		cairo_move_to (cr, 0., 0.);
@@ -288,30 +314,18 @@ goc_line_class_init (GocItemClass *item_klass)
 			_("The line end y coordinate"),
 			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-	g_object_class_install_property (obj_klass, LINE_PROP_ARROWHEAD,
-		g_param_spec_boolean ("arrowhead",
-			_("Arrow head"),
-			_("Whether to add an arrow head at the end of the line"),
-			FALSE,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-	g_object_class_install_property (obj_klass, LINE_PROP_ARROW_SHAPE_A,
-		g_param_spec_double ("arrow-shape-a",
-			_("Arrow head shape A"),
-			_("The distance from tip of arrow head to center"),
-			0, G_MAXDOUBLE, 0.,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-	g_object_class_install_property (obj_klass, LINE_PROP_ARROW_SHAPE_B,
-		g_param_spec_double ("arrow-shape-b",
-			_("Arrow head shape B"),
-			_("The distance from tip of arrow head to trailing point, measured along shaft"),
-			0, G_MAXDOUBLE, 0.,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));
-	g_object_class_install_property (obj_klass, LINE_PROP_ARROW_SHAPE_C,
-		g_param_spec_double ("arrow-shape-c",
-			_("Arrow head shape C"),
-			_("The distance of trailing points from outside edge of shaft"),
-			0, G_MAXDOUBLE, 0.,
-			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+        g_object_class_install_property (obj_klass, LINE_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, LINE_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_line_update_bounds;
 	item_klass->distance = goc_line_distance;
diff --git a/goffice/canvas/goc-line.h b/goffice/canvas/goc-line.h
index 085920c..395dc4f 100644
--- a/goffice/canvas/goc-line.h
+++ b/goffice/canvas/goc-line.h
@@ -32,8 +32,8 @@ struct _GocLine {
 
 	/* using these to avoid confusion with x0 and others in GocItem */
 	double startx, starty, endx, endy;
-	gboolean arrowhead;
-	double headA, headB, headC;
+
+	GOArrow start_arrow, end_arrow;
 };
 
 typedef GocStyledItemClass GocLineClass;



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