[planner: 7/32] libgnomecanvas: Import GnomeCanvasLine from older evolution copy




commit fb360994fedcb9638e311a3e53474f6ed4bb4312
Author: Mart Raudsepp <leio gentoo org>
Date:   Sun Mar 21 11:21:57 2021 +0200

    libgnomecanvas: Import GnomeCanvasLine from older evolution copy
    
    evolution didn't use GnomeCanvasLine, so it got dropped in evolution
    commit 372b46d528dc9db5c7eb03e1b5f16580e1aba9a1
    However before that, it did get ported over to cairo drawing, so
    import the code state from just before the dropping commit, as we
    will need it for PlannerCanvasLine for now.
    Fixes to avoid libart_lgpl and make it work with later libgnomecanvas
    GTK3 work will follow in subsequent commit(s) - this commit is for
    a straight unchanged import.

 src/libgnomecanvas/gnome-canvas-line.c | 1191 ++++++++++++++++++++++++++++++++
 src/libgnomecanvas/gnome-canvas-line.h |  143 ++++
 2 files changed, 1334 insertions(+)
---
diff --git a/src/libgnomecanvas/gnome-canvas-line.c b/src/libgnomecanvas/gnome-canvas-line.c
new file mode 100644
index 00000000..20cde8a6
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-line.c
@@ -0,0 +1,1191 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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 Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+/* Line/curve item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget.  Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico nuclecu unam mx>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_svp_vpath_stroke.h>
+#include "libgnomecanvas.h"
+
+#define noVERBOSE
+
+#define DEFAULT_SPLINE_STEPS 12                /* this is what Tk uses */
+#define NUM_ARROW_POINTS     6         /* number of points in an arrowhead */
+#define NUM_STATIC_POINTS    256       /* number of static points to use to avoid allocating arrays */
+
+#define GROW_BOUNDS(bx1, by1, bx2, by2, x, y) {        \
+       if (x < bx1)                            \
+               bx1 = x;                        \
+                                               \
+       if (x > bx2)                            \
+               bx2 = x;                        \
+                                               \
+       if (y < by1)                            \
+               by1 = y;                        \
+                                               \
+       if (y > by2)                            \
+               by2 = y;                        \
+}
+
+enum {
+       PROP_0,
+       PROP_POINTS,
+       PROP_FILL_COLOR,
+       PROP_FILL_COLOR_GDK,
+       PROP_FILL_COLOR_RGBA,
+       PROP_WIDTH_PIXELS,
+       PROP_WIDTH_UNITS,
+       PROP_CAP_STYLE,
+       PROP_JOIN_STYLE,
+       PROP_FIRST_ARROWHEAD,
+       PROP_LAST_ARROWHEAD,
+       PROP_SMOOTH,
+       PROP_SPLINE_STEPS,
+       PROP_ARROW_SHAPE_A,
+       PROP_ARROW_SHAPE_B,
+       PROP_ARROW_SHAPE_C
+};
+
+static void gnome_canvas_line_class_init   (GnomeCanvasLineClass *class);
+static void gnome_canvas_line_init         (GnomeCanvasLine      *line);
+static void gnome_canvas_line_destroy      (GnomeCanvasItem      *object);
+static void gnome_canvas_line_set_property (GObject              *object,
+                                           guint                 param_id,
+                                           const GValue         *value,
+                                           GParamSpec           *pspec);
+static void gnome_canvas_line_get_property (GObject              *object,
+                                           guint                 param_id,
+                                           GValue               *value,
+                                           GParamSpec           *pspec);
+
+static void   gnome_canvas_line_update      (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint 
flags);
+static void   gnome_canvas_line_draw        (GnomeCanvasItem *item, GdkDrawable *drawable,
+                                            gint x, gint y, gint width, gint height);
+static GnomeCanvasItem *gnome_canvas_line_point  (GnomeCanvasItem *item, gdouble x, gdouble y,
+                                            gint cx, gint cy);
+static void   gnome_canvas_line_bounds      (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, 
gdouble *y2);
+
+static GnomeCanvasItemClass *parent_class;
+
+GType
+gnome_canvas_line_get_type (void)
+{
+       static GType line_type;
+
+       if (!line_type) {
+               const GTypeInfo object_info = {
+                       sizeof (GnomeCanvasLineClass),
+                       (GBaseInitFunc) NULL,
+                       (GBaseFinalizeFunc) NULL,
+                       (GClassInitFunc) gnome_canvas_line_class_init,
+                       (GClassFinalizeFunc) NULL,
+                       NULL,                   /* class_data */
+                       sizeof (GnomeCanvasLine),
+                       0,                      /* n_preallocs */
+                       (GInstanceInitFunc) gnome_canvas_line_init,
+                       NULL                    /* value_table */
+               };
+
+               line_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasLine",
+                                                   &object_info, 0);
+       }
+
+       return line_type;
+}
+
+static void
+gnome_canvas_line_class_init (GnomeCanvasLineClass *class)
+{
+       GObjectClass *gobject_class;
+       GnomeCanvasItemClass *item_class;
+
+       gobject_class = (GObjectClass *) class;
+       item_class = (GnomeCanvasItemClass *) class;
+
+       parent_class = g_type_class_peek_parent (class);
+
+       gobject_class->set_property = gnome_canvas_line_set_property;
+       gobject_class->get_property = gnome_canvas_line_get_property;
+
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_POINTS,
+                 g_param_spec_boxed ("points", NULL, NULL,
+                                    GNOME_TYPE_CANVAS_POINTS,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FILL_COLOR,
+                 g_param_spec_string ("fill_color", NULL, NULL,
+                                      NULL,
+                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FILL_COLOR_GDK,
+                 g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
+                                    GDK_TYPE_COLOR,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FILL_COLOR_RGBA,
+                 g_param_spec_uint ("fill_color_rgba", NULL, NULL,
+                                   0, G_MAXUINT, 0,
+                                   (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_WIDTH_PIXELS,
+                 g_param_spec_uint ("width_pixels", NULL, NULL,
+                                   0, G_MAXUINT, 0,
+                                   (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_WIDTH_UNITS,
+                 g_param_spec_double ("width_units", NULL, NULL,
+                                     0.0, G_MAXDOUBLE, 0.0,
+                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_CAP_STYLE,
+                 g_param_spec_enum ("cap_style", NULL, NULL,
+                                    G_TYPE_UINT, /* XXX */
+                                    CAIRO_LINE_CAP_BUTT,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_JOIN_STYLE,
+                 g_param_spec_enum ("join_style", NULL, NULL,
+                                    G_TYPE_UINT, /* XXX */
+                                    CAIRO_LINE_JOIN_MITER,
+                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_FIRST_ARROWHEAD,
+                 g_param_spec_boolean ("first_arrowhead", NULL, NULL,
+                                      FALSE,
+                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_LAST_ARROWHEAD,
+                 g_param_spec_boolean ("last_arrowhead", NULL, NULL,
+                                      FALSE,
+                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_SMOOTH,
+                 g_param_spec_boolean ("smooth", NULL, NULL,
+                                      FALSE,
+                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_SPLINE_STEPS,
+                 g_param_spec_uint ("spline_steps", NULL, NULL,
+                                   0, G_MAXUINT, DEFAULT_SPLINE_STEPS,
+                                   (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_ARROW_SHAPE_A,
+                 g_param_spec_double ("arrow_shape_a", NULL, NULL,
+                                     -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_ARROW_SHAPE_B,
+                 g_param_spec_double ("arrow_shape_b", NULL, NULL,
+                                     -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property
+                (gobject_class,
+                 PROP_ARROW_SHAPE_C,
+                 g_param_spec_double ("arrow_shape_c", NULL, NULL,
+                                     -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+       item_class->destroy = gnome_canvas_line_destroy;
+       item_class->update = gnome_canvas_line_update;
+       item_class->draw = gnome_canvas_line_draw;
+       item_class->point = gnome_canvas_line_point;
+       item_class->bounds = gnome_canvas_line_bounds;
+}
+
+static void
+gnome_canvas_line_init (GnomeCanvasLine *line)
+{
+       line->width = 0.0;
+       line->cap = CAIRO_LINE_CAP_BUTT;
+       line->join = CAIRO_LINE_JOIN_MITER;
+       line->shape_a = 0.0;
+       line->shape_b = 0.0;
+       line->shape_c = 0.0;
+       line->spline_steps = DEFAULT_SPLINE_STEPS;
+}
+
+static void
+gnome_canvas_line_destroy (GnomeCanvasItem *object)
+{
+       GnomeCanvasLine *line;
+
+       g_return_if_fail (object != NULL);
+       g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+       line = GNOME_CANVAS_LINE (object);
+
+       /* remember, destroy can be run multiple times! */
+
+       if (line->coords)
+               g_free (line->coords);
+       line->coords = NULL;
+
+       if (line->first_coords)
+               g_free (line->first_coords);
+       line->first_coords = NULL;
+
+       if (line->last_coords)
+               g_free (line->last_coords);
+       line->last_coords = NULL;
+
+       if (line->fill_svp)
+               art_svp_free (line->fill_svp);
+       line->fill_svp = NULL;
+
+       if (line->first_svp)
+               art_svp_free (line->first_svp);
+       line->first_svp = NULL;
+
+       if (line->last_svp)
+               art_svp_free (line->last_svp);
+       line->last_svp = NULL;
+
+       if (GNOME_CANVAS_ITEM_CLASS (parent_class)->destroy)
+               GNOME_CANVAS_ITEM_CLASS (parent_class)->destroy (object);
+}
+
+/* Computes the bounding box of the line, including its arrow points.  Assumes that the number of
+ * points in the line is not zero.
+ */
+static void
+get_bounds (GnomeCanvasLine *line, gdouble *bx1, gdouble *by1, gdouble *bx2, gdouble *by2)
+{
+       gdouble *coords;
+       gdouble x1, y1, x2, y2;
+       gdouble width;
+       gint i;
+
+       if (!line->coords) {
+           *bx1 = *by1 = *bx2 = *by2 = 0.0;
+           return;
+       }
+
+       /* Find bounding box of line's points */
+
+       x1 = x2 = line->coords[0];
+       y1 = y2 = line->coords[1];
+
+       for (i = 1, coords = line->coords + 2; i < line->num_points; i++, coords += 2)
+               GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+       /* Add possible over-estimate for wide lines */
+
+       if (line->width_pixels)
+               width = line->width / line->item.canvas->pixels_per_unit;
+       else
+               width = line->width;
+
+       x1 -= width;
+       y1 -= width;
+       x2 += width;
+       y2 += width;
+
+       /* For mitered lines, make a second pass through all the points.  Compute the location of
+        * the two miter vertex points and add them to the bounding box.
+        */
+
+       if (line->join == CAIRO_LINE_JOIN_MITER)
+               for (i = line->num_points, coords = line->coords; i >= 3; i--, coords += 2) {
+                       gdouble mx1, my1, mx2, my2;
+
+                       if (gnome_canvas_get_miter_points (coords[0], coords[1],
+                                                          coords[2], coords[3],
+                                                          coords[4], coords[5],
+                                                          width,
+                                                          &mx1, &my1, &mx2, &my2)) {
+                               GROW_BOUNDS (x1, y1, x2, y2, mx1, my1);
+                               GROW_BOUNDS (x1, y1, x2, y2, mx2, my2);
+                       }
+               }
+
+       /* Add the arrow points, if any */
+
+       if (line->first_arrow && line->first_coords)
+               for (i = 0, coords = line->first_coords; i < NUM_ARROW_POINTS; i++, coords += 2)
+                       GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+       if (line->last_arrow && line->last_coords)
+               for (i = 0, coords = line->last_coords; i < NUM_ARROW_POINTS; i++, coords += 2)
+                       GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+       /* Done */
+
+       *bx1 = x1;
+       *by1 = y1;
+       *bx2 = x2;
+       *by2 = y2;
+}
+
+/* Computes the bounding box of the line, in canvas coordinates.  Assumes that the number of points in the 
polygon is
+ * not zero. Affine is the i2c transformation.
+ */
+static void
+get_bounds_canvas (GnomeCanvasLine *line, gdouble *bx1, gdouble *by1, gdouble *bx2, gdouble *by2, gdouble 
affine[6])
+{
+       /* It would be possible to tighten the bounds somewhat by transforming the individual points before
+          aggregating them into the bbox. But it hardly seems worth it. */
+       ArtDRect bbox_world;
+       ArtDRect bbox_canvas;
+
+       get_bounds (line, &bbox_world.x0, &bbox_world.y0, &bbox_world.x1, &bbox_world.y1);
+
+       art_drect_affine_transform (&bbox_canvas, &bbox_world, affine);
+       /* include 1 pixel of fudge */
+       *bx1 = bbox_canvas.x0 - 1;
+       *by1 = bbox_canvas.y0 - 1;
+       *bx2 = bbox_canvas.x1 + 1;
+       *by2 = bbox_canvas.y1 + 1;
+}
+
+/* Recalculates the arrow polygons for the line */
+static void
+reconfigure_arrows (GnomeCanvasLine *line)
+{
+       gdouble *poly, *coords;
+       gdouble dx, dy, length;
+       gdouble sin_theta, cos_theta, tmp;
+       gdouble frac_height;    /* Line width as fraction of arrowhead width */
+       gdouble backup;         /* Distance to backup end points so the line ends in the middle of the 
arrowhead */
+       gdouble vx, vy;         /* Position of arrowhead vertex */
+       gdouble shape_a, shape_b, shape_c;
+       gdouble width;
+       gint i;
+
+       if (line->num_points == 0)
+               return;
+
+       /* Set up things */
+
+       if (line->first_arrow) {
+               if (line->first_coords) {
+                       line->coords[0] = line->first_coords[0];
+                       line->coords[1] = line->first_coords[1];
+               } else
+                       line->first_coords = g_new (double, 2 * NUM_ARROW_POINTS);
+       } else if (line->first_coords) {
+               line->coords[0] = line->first_coords[0];
+               line->coords[1] = line->first_coords[1];
+
+               g_free (line->first_coords);
+               line->first_coords = NULL;
+       }
+
+       i = 2 * (line->num_points - 1);
+
+       if (line->last_arrow) {
+               if (line->last_coords) {
+                       line->coords[i] = line->last_coords[0];
+                       line->coords[i + 1] = line->last_coords[1];
+               } else
+                       line->last_coords = g_new (double, 2 * NUM_ARROW_POINTS);
+       } else if (line->last_coords) {
+               line->coords[i] = line->last_coords[0];
+               line->coords[i + 1] = line->last_coords[1];
+
+               g_free (line->last_coords);
+               line->last_coords = NULL;
+       }
+
+       if (!line->first_arrow && !line->last_arrow)
+               return;
+
+       if (line->width_pixels)
+               width = line->width / line->item.canvas->pixels_per_unit;
+       else
+               width = line->width;
+
+       /* Add fudge value for better-looking results */
+
+       shape_a = line->shape_a;
+       shape_b = line->shape_b;
+       shape_c = line->shape_c + width / 2.0;
+
+       if (line->width_pixels) {
+               shape_a /= line->item.canvas->pixels_per_unit;
+               shape_b /= line->item.canvas->pixels_per_unit;
+               shape_c /= line->item.canvas->pixels_per_unit;
+       }
+
+       shape_a += 0.001;
+       shape_b += 0.001;
+       shape_c += 0.001;
+
+       /* Compute the polygon for the first arrowhead and adjust the first point in the line so
+        * that the line does not stick out past the leading edge of the arrowhead.
+        */
+
+       frac_height = (line->width / 2.0) / shape_c;
+       backup = frac_height * shape_b + shape_a * (1.0 - frac_height) / 2.0;
+
+       if (line->first_arrow) {
+               poly = line->first_coords;
+               poly[0] = poly[10] = line->coords[0];
+               poly[1] = poly[11] = line->coords[1];
+
+               dx = poly[0] - line->coords[2];
+               dy = poly[1] - line->coords[3];
+               length = sqrt (dx * dx + dy * dy);
+               if (length < GNOME_CANVAS_EPSILON)
+                       sin_theta = cos_theta = 0.0;
+               else {
+                       sin_theta = dy / length;
+                       cos_theta = dx / length;
+               }
+
+               vx = poly[0] - shape_a * cos_theta;
+               vy = poly[1] - shape_a * sin_theta;
+
+               tmp = shape_c * sin_theta;
+
+               poly[2] = poly[0] - shape_b * cos_theta + tmp;
+               poly[8] = poly[2] - 2.0 * tmp;
+
+               tmp = shape_c * cos_theta;
+
+               poly[3] = poly[1] - shape_b * sin_theta - tmp;
+               poly[9] = poly[3] + 2.0 * tmp;
+
+               poly[4] = poly[2] * frac_height + vx * (1.0 - frac_height);
+               poly[5] = poly[3] * frac_height + vy * (1.0 - frac_height);
+               poly[6] = poly[8] * frac_height + vx * (1.0 - frac_height);
+               poly[7] = poly[9] * frac_height + vy * (1.0 - frac_height);
+
+               /* Move the first point towards the second so that the corners at the end of the
+                * line are inside the arrowhead.
+                */
+
+               line->coords[0] = poly[0] - backup * cos_theta;
+               line->coords[1] = poly[1] - backup * sin_theta;
+       }
+
+       /* Same process for last arrowhead */
+
+       if (line->last_arrow) {
+               coords = line->coords + 2 * (line->num_points - 2);
+               poly = line->last_coords;
+               poly[0] = poly[10] = coords[2];
+               poly[1] = poly[11] = coords[3];
+
+               dx = poly[0] - coords[0];
+               dy = poly[1] - coords[1];
+               length = sqrt (dx * dx + dy * dy);
+               if (length < GNOME_CANVAS_EPSILON)
+                       sin_theta = cos_theta = 0.0;
+               else {
+                       sin_theta = dy / length;
+                       cos_theta = dx / length;
+               }
+
+               vx = poly[0] - shape_a * cos_theta;
+               vy = poly[1] - shape_a * sin_theta;
+
+               tmp = shape_c * sin_theta;
+
+               poly[2] = poly[0] - shape_b * cos_theta + tmp;
+               poly[8] = poly[2] - 2.0 * tmp;
+
+               tmp = shape_c * cos_theta;
+
+               poly[3] = poly[1] - shape_b * sin_theta - tmp;
+               poly[9] = poly[3] + 2.0 * tmp;
+
+               poly[4] = poly[2] * frac_height + vx * (1.0 - frac_height);
+               poly[5] = poly[3] * frac_height + vy * (1.0 - frac_height);
+               poly[6] = poly[8] * frac_height + vx * (1.0 - frac_height);
+               poly[7] = poly[9] * frac_height + vy * (1.0 - frac_height);
+
+               coords[2] = poly[0] - backup * cos_theta;
+               coords[3] = poly[1] - backup * sin_theta;
+       }
+}
+
+static void
+gnome_canvas_line_set_property (GObject              *object,
+                               guint                 param_id,
+                               const GValue         *value,
+                               GParamSpec           *pspec)
+{
+       GnomeCanvasItem *item;
+       GnomeCanvasLine *line;
+       GnomeCanvasPoints *points;
+       GdkColor color = { 0, 0, 0, 0, };
+       GdkColor *pcolor;
+       gboolean color_changed;
+       gint have_pixel;
+
+       g_return_if_fail (object != NULL);
+       g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+       item = GNOME_CANVAS_ITEM (object);
+       line = GNOME_CANVAS_LINE (object);
+
+       color_changed = FALSE;
+       have_pixel = FALSE;
+
+       switch (param_id) {
+       case PROP_POINTS:
+               points = g_value_get_boxed (value);
+
+               if (line->coords) {
+                       g_free (line->coords);
+                       line->coords = NULL;
+               }
+
+               if (!points)
+                       line->num_points = 0;
+               else {
+                       line->num_points = points->num_points;
+                       line->coords = g_new (double, 2 * line->num_points);
+                       memcpy (line->coords, points->coords, 2 * line->num_points * sizeof (gdouble));
+               }
+
+               /* Drop the arrowhead polygons if they exist -- they will be regenerated */
+
+               if (line->first_coords) {
+                       g_free (line->first_coords);
+                       line->first_coords = NULL;
+               }
+
+               if (line->last_coords) {
+                       g_free (line->last_coords);
+                       line->last_coords = NULL;
+               }
+
+               /* Since the line's points have changed, we need to re-generate arrowheads in
+                * addition to recalculating the bounds.
+                */
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_FILL_COLOR:
+               if (g_value_get_string (value))
+                       gdk_color_parse (g_value_get_string (value), &color);
+               line->fill_rgba = ((color.red & 0xff00) << 16 |
+                                  (color.green & 0xff00) << 8 |
+                                  (color.blue & 0xff00) |
+                                  0xff);
+               color_changed = TRUE;
+               break;
+
+       case PROP_FILL_COLOR_GDK:
+               pcolor = g_value_get_boxed (value);
+               if (pcolor) {
+                       GdkColormap *colormap;
+                       color = *pcolor;
+
+                       colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+                       gdk_rgb_find_color (colormap, &color);
+
+                       have_pixel = TRUE;
+               }
+
+               line->fill_rgba = ((color.red & 0xff00) << 16 |
+                                  (color.green & 0xff00) << 8 |
+                                  (color.blue & 0xff00) |
+                                  0xff);
+               color_changed = TRUE;
+               break;
+
+       case PROP_FILL_COLOR_RGBA:
+               line->fill_rgba = g_value_get_uint (value);
+               color_changed = TRUE;
+               break;
+
+       case PROP_WIDTH_PIXELS:
+               line->width = g_value_get_uint (value);
+               line->width_pixels = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_WIDTH_UNITS:
+               line->width = fabs (g_value_get_double (value));
+               line->width_pixels = FALSE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_CAP_STYLE:
+               line->cap = g_value_get_enum (value);
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_JOIN_STYLE:
+               line->join = g_value_get_enum (value);
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_FIRST_ARROWHEAD:
+               line->first_arrow = g_value_get_boolean (value);
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_LAST_ARROWHEAD:
+               line->last_arrow = g_value_get_boolean (value);
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_SMOOTH:
+               /* FIXME */
+               break;
+
+       case PROP_SPLINE_STEPS:
+               /* FIXME */
+               break;
+
+       case PROP_ARROW_SHAPE_A:
+               line->shape_a = fabs (g_value_get_double (value));
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_ARROW_SHAPE_B:
+               line->shape_b = fabs (g_value_get_double (value));
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case PROP_ARROW_SHAPE_C:
+               line->shape_c = fabs (g_value_get_double (value));
+               gnome_canvas_item_request_update (item);
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+
+       if (color_changed) {
+               if (have_pixel)
+                       line->fill_pixel = color.pixel;
+               else
+                       line->fill_pixel = gnome_canvas_get_color_pixel (item->canvas,
+                                                                        line->fill_rgba);
+
+               gnome_canvas_item_request_redraw_svp (item, line->fill_svp);
+
+               if (line->first_svp)
+                       gnome_canvas_item_request_redraw_svp (item, line->first_svp);
+
+               if (line->last_svp)
+                       gnome_canvas_item_request_redraw_svp (item, line->last_svp);
+
+       }
+}
+
+/* Returns a copy of the line's points without the endpoint adjustments for
+ * arrowheads.
+ */
+static GnomeCanvasPoints *
+get_points (GnomeCanvasLine *line)
+{
+       GnomeCanvasPoints *points;
+       gint start_ofs, end_ofs;
+
+       if (line->num_points == 0)
+               return NULL;
+
+       start_ofs = end_ofs = 0;
+
+       points = gnome_canvas_points_new (line->num_points);
+
+       /* Invariant:  if first_coords or last_coords exist, then the line's
+        * endpoints have been adjusted.
+        */
+
+       if (line->first_coords) {
+               start_ofs = 1;
+
+               points->coords[0] = line->first_coords[0];
+               points->coords[1] = line->first_coords[1];
+       }
+
+       if (line->last_coords) {
+               end_ofs = 1;
+
+               points->coords[2 * (line->num_points - 1)] = line->last_coords[0];
+               points->coords[2 * (line->num_points - 1) + 1] = line->last_coords[1];
+       }
+
+       memcpy (points->coords + 2 * start_ofs,
+               line->coords + 2 * start_ofs,
+               2 * (line->num_points - (start_ofs + end_ofs)) * sizeof (gdouble));
+
+       return points;
+}
+
+static void
+gnome_canvas_line_get_property (GObject              *object,
+                               guint                 param_id,
+                               GValue               *value,
+                               GParamSpec           *pspec)
+{
+       GnomeCanvasLine *line;
+
+       g_return_if_fail (object != NULL);
+       g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+       line = GNOME_CANVAS_LINE (object);
+
+       switch (param_id) {
+       case PROP_POINTS:
+               /* get_points returns a copy */
+               g_value_take_boxed (value, get_points (line));
+               break;
+
+       case PROP_FILL_COLOR:
+               g_value_take_string (value,
+                                    g_strdup_printf ("#%02x%02x%02x",
+                                    line->fill_rgba >> 24,
+                                    (line->fill_rgba >> 16) & 0xff,
+                                    (line->fill_rgba >> 8) & 0xff));
+               break;
+
+       case PROP_FILL_COLOR_GDK: {
+               GnomeCanvas *canvas = GNOME_CANVAS_ITEM (line)->canvas;
+               GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+               GdkColor color;
+
+               gdk_colormap_query_color (colormap, line->fill_pixel, &color);
+               g_value_set_boxed (value, &color);
+               break;
+       }
+
+       case PROP_FILL_COLOR_RGBA:
+               g_value_set_uint (value, line->fill_rgba);
+               break;
+
+       case PROP_WIDTH_PIXELS:
+               g_value_set_uint (value, line->width);
+               break;
+
+       case PROP_WIDTH_UNITS:
+               g_value_set_double (value, line->width);
+               break;
+
+       case PROP_CAP_STYLE:
+               g_value_set_enum (value, line->cap);
+               break;
+
+       case PROP_JOIN_STYLE:
+               g_value_set_enum (value, line->join);
+               break;
+
+       case PROP_FIRST_ARROWHEAD:
+               g_value_set_boolean (value, line->first_arrow);
+               break;
+
+       case PROP_LAST_ARROWHEAD:
+               g_value_set_boolean (value, line->last_arrow);
+               break;
+
+       case PROP_SMOOTH:
+               g_value_set_boolean (value, line->smooth);
+               break;
+
+       case PROP_SPLINE_STEPS:
+               g_value_set_uint (value, line->spline_steps);
+               break;
+
+       case PROP_ARROW_SHAPE_A:
+               g_value_set_double (value, line->shape_a);
+               break;
+
+       case PROP_ARROW_SHAPE_B:
+               g_value_set_double (value, line->shape_b);
+               break;
+
+       case PROP_ARROW_SHAPE_C:
+               g_value_set_double (value, line->shape_c);
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+               break;
+       }
+}
+
+static void
+gnome_canvas_line_update (GnomeCanvasItem *item, gdouble *affine, ArtSVP *clip_path, gint flags)
+{
+       GnomeCanvasLine *line;
+       gdouble x1, y1, x2, y2;
+
+       line = GNOME_CANVAS_LINE (item);
+
+       if (parent_class->update)
+               (* parent_class->update) (item, affine, clip_path, flags);
+
+       reconfigure_arrows (line);
+
+        get_bounds_canvas (line, &x1, &y1, &x2, &y2, affine);
+        gnome_canvas_update_bbox (item, x1, y1, x2, y2);
+}
+
+static void
+item_to_canvas (GnomeCanvas *canvas, gdouble *item_coords, GdkPoint *canvas_coords, gint num_points,
+               gint *num_drawn_points, const cairo_matrix_t *matrix)
+{
+       gint i;
+       gint old_cx, old_cy;
+       gint cx, cy;
+       double x, y;
+
+#ifdef VERBOSE
+       {
+               gchar str[128];
+               art_affine_to_string (str, i2c);
+               g_print ("line item_to_canvas %s\n", str);
+       }
+#endif
+
+       /* the first point is always drawn */
+
+       x = item_coords[0];
+       y = item_coords[1];
+       cairo_matrix_transform_point (matrix, &x, &y);
+       cx = floor (x + 0.5);
+       cy = floor (y + 0.5);
+       canvas_coords->x = cx - x;
+       canvas_coords->y = cy - y;
+       canvas_coords++;
+       old_cx = cx;
+       old_cy = cy;
+       *num_drawn_points = 1;
+
+       for (i = 1; i < num_points; i++) {
+               x = item_coords[i * 2];
+               y = item_coords[i * 2 + 1];
+               cairo_matrix_transform_point (matrix, &x, &y);
+               cx = floor (x + 0.5);
+               cy = floor (y + 0.5);
+               if (old_cx != cx || old_cy != cy) {
+                       canvas_coords->x = cx - x;
+                       canvas_coords->y = cy - y;
+                       old_cx = cx;
+                       old_cy = cy;
+                       canvas_coords++;
+                       (*num_drawn_points)++;
+               }
+       }
+}
+
+static void
+gnome_canvas_line_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+                       gint x, gint y, gint width, gint height)
+{
+       GnomeCanvasLine *line;
+       GdkPoint static_points[NUM_STATIC_POINTS];
+       GdkPoint *points;
+       gint actual_num_points_drawn;
+       cairo_matrix_t matrix;
+        cairo_t *cr;
+        int i;
+
+       line = GNOME_CANVAS_LINE (item);
+
+       if (line->num_points == 0)
+               return;
+
+        cr = gdk_cairo_create (drawable);
+        cairo_translate (cr, -x, -y);
+
+        /* points are always centered */
+        cairo_translate (cr, 0.5, 0.5);
+
+        cairo_set_source_rgba (cr,
+                               ((line->fill_pixel >> 24) & 0xff) / 255.0,
+                               ((line->fill_pixel >> 16) & 0xff) / 255.0,
+                               ((line->fill_pixel >>  8) & 0xff) / 255.0,
+                               ((line->fill_pixel >>  0) & 0xff) / 255.0);
+       if (line->width_pixels)
+                cairo_set_line_width (cr, (gint) line->width);
+        else
+               cairo_set_line_width (cr, (gint) (line->width * line->item.canvas->pixels_per_unit + 0.5));
+        if (line->first_arrow || line->last_arrow)
+                cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+        else
+                cairo_set_line_cap (cr, line->cap);
+        cairo_set_line_join (cr, line->join);
+
+        gnome_canvas_item_i2c_matrix (item, &matrix);
+       /* Build array of canvas pixel coordinates */
+
+       if (line->num_points <= NUM_STATIC_POINTS)
+               points = static_points;
+       else
+               points = g_new (GdkPoint, line->num_points);
+
+       item_to_canvas (item->canvas, line->coords, points, line->num_points,
+                       &actual_num_points_drawn, &matrix);
+
+        cairo_move_to (cr, points[0].x, points[0].y);
+        for (i = 1; i < actual_num_points_drawn; i++)
+                cairo_line_to (cr, points[i].x, points[i].y);
+        cairo_stroke (cr);
+
+       if (points != static_points)
+               g_free (points);
+
+       /* Draw arrowheads */
+
+       points = static_points;
+
+       if (line->first_arrow) {
+               item_to_canvas (item->canvas, line->first_coords, points, NUM_ARROW_POINTS,
+                               &actual_num_points_drawn, &matrix);
+                cairo_move_to (cr, points[0].x, points[0].y);
+                for (i = 1; i < actual_num_points_drawn; i++)
+                        cairo_line_to (cr, points[i].x, points[i].y);
+                cairo_fill (cr);
+       }
+
+       if (line->last_arrow) {
+               item_to_canvas (item->canvas, line->last_coords, points, NUM_ARROW_POINTS,
+                               &actual_num_points_drawn, &matrix);
+                cairo_move_to (cr, points[0].x, points[0].y);
+                for (i = 1; i < actual_num_points_drawn; i++)
+                        cairo_line_to (cr, points[i].x, points[i].y);
+                cairo_fill (cr);
+       }
+}
+
+static GnomeCanvasItem *
+gnome_canvas_line_point (GnomeCanvasItem *item, gdouble x, gdouble y,
+                        gint cx, gint cy)
+{
+       GnomeCanvasLine *line;
+       gdouble *line_points = NULL, *coords;
+       gdouble static_points[2 * NUM_STATIC_POINTS];
+       gdouble poly[10];
+       gdouble best, dist;
+       gdouble dx, dy;
+       gdouble width;
+       gint num_points = 0, i;
+       gint changed_miter_to_bevel;
+
+#ifdef VERBOSE
+       g_print ("gnome_canvas_line_point x, y = (%g, %g); cx, cy = (%d, %d)\n", x, y, cx, cy);
+#endif
+
+       line = GNOME_CANVAS_LINE (item);
+
+       best = 1.0e36;
+
+       /* Handle smoothed lines by generating an expanded set ot points */
+
+       if (line->smooth && (line->num_points > 2)) {
+               /* FIXME */
+       } else {
+               num_points = line->num_points;
+               line_points = line->coords;
+       }
+
+       /* Compute a polygon for each edge of the line and test the point against it.  The effective
+        * width of the line is adjusted so that it will be at least one pixel thick (so that zero
+        * pixel-wide lines can be pickedup as well).
+        */
+
+       if (line->width_pixels)
+               width = line->width / item->canvas->pixels_per_unit;
+       else
+               width = line->width;
+
+       if (width < (1.0 / item->canvas->pixels_per_unit))
+               width = 1.0 / item->canvas->pixels_per_unit;
+
+       changed_miter_to_bevel = 0;
+
+       for (i = num_points, coords = line_points; i >= 2; i--, coords += 2) {
+               /* If rounding is done around the first point, then compute distance between the
+                * point and the first point.
+                */
+
+               if (((line->cap == CAIRO_LINE_CAP_ROUND) && (i == num_points))
+                   || ((line->join == CAIRO_LINE_JOIN_ROUND) && (i != num_points))) {
+                       dx = coords[0] - x;
+                       dy = coords[1] - y;
+                       dist = sqrt (dx * dx + dy * dy) - width / 2.0;
+                       if (dist < GNOME_CANVAS_EPSILON) {
+                               best = 0.0;
+                               goto done;
+                       } else if (dist < best)
+                               best = dist;
+               }
+
+               /* Compute the polygonal shape corresponding to this edge, with two points for the
+                * first point of the edge and two points for the last point of the edge.
+                */
+
+               if (i == num_points)
+                       gnome_canvas_get_butt_points (coords[2], coords[3], coords[0], coords[1],
+                                                     width, (line->cap == CAIRO_LINE_CAP_SQUARE),
+                                                     poly, poly + 1, poly + 2, poly + 3);
+               else if ((line->join == CAIRO_LINE_JOIN_MITER) && !changed_miter_to_bevel) {
+                       poly[0] = poly[6];
+                       poly[1] = poly[7];
+                       poly[2] = poly[4];
+                       poly[3] = poly[5];
+               } else {
+                       gnome_canvas_get_butt_points (coords[2], coords[3], coords[0], coords[1],
+                                                     width, FALSE,
+                                                     poly, poly + 1, poly + 2, poly + 3);
+
+                       /* If this line uses beveled joints, then check the distance to a polygon
+                        * comprising the last two points of the previous polygon and the first two
+                        * from this polygon; this checks the wedges that fill the mitered point.
+                        */
+
+                       if ((line->join == CAIRO_LINE_JOIN_BEVEL) || changed_miter_to_bevel) {
+                               poly[8] = poly[0];
+                               poly[9] = poly[1];
+
+                               dist = gnome_canvas_polygon_to_point (poly, 5, x, y);
+                               if (dist < GNOME_CANVAS_EPSILON) {
+                                       best = 0.0;
+                                       goto done;
+                               } else if (dist < best)
+                                       best = dist;
+
+                               changed_miter_to_bevel = FALSE;
+                       }
+               }
+
+               if (i == 2)
+                       gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+                                                     width, (line->cap == CAIRO_LINE_CAP_SQUARE),
+                                                     poly + 4, poly + 5, poly + 6, poly + 7);
+               else if (line->join == CAIRO_LINE_JOIN_MITER) {
+                       if (!gnome_canvas_get_miter_points (coords[0], coords[1],
+                                                           coords[2], coords[3],
+                                                           coords[4], coords[5],
+                                                           width,
+                                                           poly + 4, poly + 5, poly + 6, poly + 7)) {
+                               changed_miter_to_bevel = TRUE;
+                               gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+                                                             width, FALSE,
+                                                             poly + 4, poly + 5, poly + 6, poly + 7);
+                       }
+               } else
+                       gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+                                                     width, FALSE,
+                                                     poly + 4, poly + 5, poly + 6, poly + 7);
+
+               poly[8] = poly[0];
+               poly[9] = poly[1];
+
+               dist = gnome_canvas_polygon_to_point (poly, 5, x, y);
+               if (dist < GNOME_CANVAS_EPSILON) {
+                       best = 0.0;
+                       goto done;
+               } else if (dist < best)
+                       best = dist;
+       }
+
+       /* If caps are rounded, check the distance to the cap around the final end point of the line */
+
+       if (line->cap == CAIRO_LINE_CAP_ROUND) {
+               dx = coords[0] - x;
+               dy = coords[1] - y;
+               dist = sqrt (dx * dx + dy * dy) - width / 2.0;
+               if (dist < GNOME_CANVAS_EPSILON) {
+                       best = 0.0;
+                       goto done;
+               } else
+                       best = dist;
+       }
+
+       /* sometimes the GnomeCanvasItem::update signal will not have
+           been processed between deleting the arrow points and a call
+           to this routine -- this can cause a segfault here */
+       if ((line->first_arrow && !line->first_coords) ||
+           (line->last_arrow && !line->last_coords))
+               reconfigure_arrows (line);
+
+       /* If there are arrowheads, check the distance to them */
+
+       if (line->first_arrow) {
+               dist = gnome_canvas_polygon_to_point (line->first_coords, NUM_ARROW_POINTS, x, y);
+               if (dist < GNOME_CANVAS_EPSILON) {
+                       best = 0.0;
+                       goto done;
+               } else
+                       best = dist;
+       }
+
+       if (line->last_arrow) {
+               dist = gnome_canvas_polygon_to_point (line->last_coords, NUM_ARROW_POINTS, x, y);
+               if (dist < GNOME_CANVAS_EPSILON) {
+                       best = 0.0;
+                       goto done;
+               } else
+                       best = dist;
+       }
+
+done:
+
+       if ((line_points != static_points) && (line_points != line->coords))
+               g_free (line_points);
+
+       return best == 0.0 ? item : NULL;
+}
+
+static void
+gnome_canvas_line_bounds (GnomeCanvasItem *item, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2)
+{
+       GnomeCanvasLine *line;
+
+       line = GNOME_CANVAS_LINE (item);
+
+       if (line->num_points == 0) {
+               *x1 = *y1 = *x2 = *y2 = 0.0;
+               return;
+       }
+
+       get_bounds (line, x1, y1, x2, y2);
+}
diff --git a/src/libgnomecanvas/gnome-canvas-line.h b/src/libgnomecanvas/gnome-canvas-line.h
new file mode 100644
index 00000000..749478ff
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-line.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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 Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+/* Line/curve item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget.  Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico nuclecu unam mx>
+ */
+
+#ifndef GNOME_CANVAS_LINE_H
+#define GNOME_CANVAS_LINE_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+G_BEGIN_DECLS
+
+/* Line item for the canvas.  This is a polyline with configurable width, cap/join styles, and arrowheads.
+ * If arrowheads are enabled, then three values are used to specify their shape:
+ *
+ *     arrow_shape_a:  Distance from tip of arrowhead to the center point.
+ *     arrow_shape_b:  Distance from tip of arrowhead to trailing point, measured along the shaft.
+ *     arrow_shape_c:  Distance of trailing point from outside edge of shaft.
+ *
+ * The following object arguments are available:
+ *
+ * name                        type                    read/write      description
+ * ------------------------------------------------------------------------------------------
+ * points              GnomeCanvasPoints*      RW              Pointer to a GnomeCanvasPoints structure.
+ *                                                             This can be created by a call to
+ *                                                             gnome_canvas_points_new() (in 
gnome-canvas-util.h).
+ *                                                             X coordinates are in the even indices of the
+ *                                                             points->coords array, Y coordinates are in
+ *                                                             the odd indices.
+ * fill_color          string                  W               X color specification for line
+ * fill_color_gdk      GdkColor*               RW              Pointer to an allocated GdkColor
+ * width_pixels                uint                    R               Width of the line in pixels.  The 
line width
+ *                                                             will not be scaled when the canvas zoom 
factor changes.
+ * width_units         gdouble                 R               Width of the line in canvas units.  The line 
width
+ *                                                             will be scaled when the canvas zoom factor 
changes.
+ * cap_style           GdkCapStyle             RW              Cap ("endpoint") style for the line.
+ * join_style          GdkJoinStyle            RW              Join ("vertex") style for the line.
+ * line_style          GdkLineStyle            RW              Line dash style
+ * first_arrowhead     boolean                 RW              Specifies whether to draw an arrowhead on the
+ *                                                             first point of the line.
+ * last_arrowhead      boolean                 RW              Specifies whether to draw an arrowhead on the
+ *                                                             last point of the line.
+ * smooth              boolean                 RW              Specifies whether to smooth the line using
+ *                                                             parabolic splines.
+ * spline_steps                uint                    RW              Specifies the number of steps to use 
when rendering curves.
+ * arrow_shape_a       gdouble                 RW              First arrow shape specifier.
+ * arrow_shape_b       gdouble                 RW              Second arrow shape specifier.
+ * arrow_shape_c       gdouble                 RW              Third arrow shape specifier.
+ */
+
+#define GNOME_TYPE_CANVAS_LINE            (gnome_canvas_line_get_type ())
+#define GNOME_CANVAS_LINE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_CANVAS_LINE, 
GnomeCanvasLine))
+#define GNOME_CANVAS_LINE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_LINE, 
GnomeCanvasLineClass))
+#define GNOME_IS_CANVAS_LINE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_CANVAS_LINE))
+#define GNOME_IS_CANVAS_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_LINE))
+#define GNOME_CANVAS_LINE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_CANVAS_LINE, 
GnomeCanvasLineClass))
+
+typedef struct _GnomeCanvasLine GnomeCanvasLine;
+typedef struct _GnomeCanvasLineClass GnomeCanvasLineClass;
+
+struct _GnomeCanvasLine {
+       GnomeCanvasItem item;
+
+       gdouble *coords;                /* Array of coordinates for the line's points.  X coords are in the
+                                * even indices, Y coords are in the odd indices.  If the line has
+                                * arrowheads then the first and last points have been adjusted to
+                                * refer to the necks of the arrowheads rather than their tips.  The
+                                * actual endpoints are stored in the first_arrow and last_arrow
+                                * arrays, if they exist.
+                                */
+
+       gdouble *first_coords;  /* Array of points describing polygon for the first arrowhead */
+       gdouble *last_coords;   /* Array of points describing polygon for the last arrowhead */
+
+       GdkGC *gc;              /* GC for drawing line */
+
+        ArtSVP *fill_svp;              /* The SVP for the outline shape */ /*AA*/
+       ArtSVP *first_svp;              /* The SVP for the first arrow */ /*AA*/
+       ArtSVP *last_svp;               /* The SVP for the last arrow */ /*AA*/
+
+       gdouble width;          /* Width of the line */
+
+       gdouble shape_a;                /* Distance from tip of arrowhead to center */
+       gdouble shape_b;                /* Distance from tip of arrowhead to trailing point, measured along 
shaft */
+       gdouble shape_c;                /* Distance of trailing points from outside edge of shaft */
+
+       cairo_line_cap_t cap;   /* Cap style for line */
+       cairo_line_join_t join; /* Join style for line */
+
+       gulong fill_pixel;      /* Color for line */
+
+       guint32 fill_rgba;              /* RGBA color for outline */ /*AA*/
+
+       gint num_points;                /* Number of points in the line */
+       guint fill_color;       /* Fill color, RGBA */
+
+       gint spline_steps;      /* Number of steps in each spline segment */
+
+       guint width_pixels : 1; /* Is the width specified in pixels or units? */
+       guint first_arrow : 1;  /* Draw first arrowhead? */
+       guint last_arrow : 1;   /* Draw last arrowhead? */
+       guint smooth : 1;       /* Smooth line (with parabolic splines)? */
+};
+
+struct _GnomeCanvasLineClass {
+       GnomeCanvasItemClass parent_class;
+};
+
+/* Standard Gtk function */
+GType gnome_canvas_line_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif


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