1 #define __SP_LINE_C__
3 /*
4 * SVG <line> implementation
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * Copyright (C) 1999-2002 Lauris Kaplinski
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
17 #include "attributes.h"
18 #include "style.h"
19 #include "sp-line.h"
20 #include "sp-guide.h"
21 #include "display/curve.h"
22 #include <glibmm/i18n.h>
23 #include <libnr/nr-matrix-fns.h>
24 #include <xml/repr.h>
25 #include "document.h"
26 #include "inkscape.h"
28 static void sp_line_class_init (SPLineClass *klass);
29 static void sp_line_init (SPLine *line);
31 static void sp_line_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr);
32 static void sp_line_set (SPObject *object, unsigned int key, const gchar *value);
33 static Inkscape::XML::Node *sp_line_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
35 static gchar *sp_line_description (SPItem * item);
36 static Geom::Matrix sp_line_set_transform(SPItem *item, Geom::Matrix const &xform);
38 static void sp_line_update (SPObject *object, SPCtx *ctx, guint flags);
39 static void sp_line_set_shape (SPShape *shape);
40 static void sp_line_convert_to_guides(SPItem *item);
42 static SPShapeClass *parent_class;
44 GType
45 sp_line_get_type (void)
46 {
47 static GType line_type = 0;
49 if (!line_type) {
50 GTypeInfo line_info = {
51 sizeof (SPLineClass),
52 NULL, /* base_init */
53 NULL, /* base_finalize */
54 (GClassInitFunc) sp_line_class_init,
55 NULL, /* klass_finalize */
56 NULL, /* klass_data */
57 sizeof (SPLine),
58 16, /* n_preallocs */
59 (GInstanceInitFunc) sp_line_init,
60 NULL, /* value_table */
61 };
62 line_type = g_type_register_static (SP_TYPE_SHAPE, "SPLine", &line_info, (GTypeFlags)0);
63 }
64 return line_type;
65 }
67 static void
68 sp_line_class_init (SPLineClass *klass)
69 {
70 parent_class = (SPShapeClass *) g_type_class_ref (SP_TYPE_SHAPE);
72 SPObjectClass *sp_object_class = (SPObjectClass *) klass;
73 sp_object_class->build = sp_line_build;
74 sp_object_class->set = sp_line_set;
75 sp_object_class->write = sp_line_write;
77 SPItemClass *item_class = (SPItemClass *) klass;
78 item_class->description = sp_line_description;
79 item_class->set_transform = sp_line_set_transform;
80 item_class->convert_to_guides = sp_line_convert_to_guides;
82 sp_object_class->update = sp_line_update;
84 SPShapeClass *shape_class = (SPShapeClass *) klass;
85 shape_class->set_shape = sp_line_set_shape;
86 }
88 static void
89 sp_line_init (SPLine * line)
90 {
91 line->x1.unset();
92 line->y1.unset();
93 line->x2.unset();
94 line->y2.unset();
95 }
98 static void
99 sp_line_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr)
100 {
101 if (((SPObjectClass *) parent_class)->build) {
102 ((SPObjectClass *) parent_class)->build (object, document, repr);
103 }
105 sp_object_read_attr (object, "x1");
106 sp_object_read_attr (object, "y1");
107 sp_object_read_attr (object, "x2");
108 sp_object_read_attr (object, "y2");
109 }
111 static void
112 sp_line_set (SPObject *object, unsigned int key, const gchar *value)
113 {
114 SPLine * line = SP_LINE (object);
116 /* fixme: we should really collect updates */
118 switch (key) {
119 case SP_ATTR_X1:
120 line->x1.readOrUnset(value);
121 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
122 break;
123 case SP_ATTR_Y1:
124 line->y1.readOrUnset(value);
125 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
126 break;
127 case SP_ATTR_X2:
128 line->x2.readOrUnset(value);
129 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
130 break;
131 case SP_ATTR_Y2:
132 line->y2.readOrUnset(value);
133 object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
134 break;
135 default:
136 if (((SPObjectClass *) parent_class)->set)
137 ((SPObjectClass *) parent_class)->set (object, key, value);
138 break;
139 }
140 }
142 static void
143 sp_line_update (SPObject *object, SPCtx *ctx, guint flags)
144 {
145 if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
146 SPLine *line = SP_LINE (object);
148 SPStyle const *style = object->style;
149 SPItemCtx const *ictx = (SPItemCtx const *) ctx;
150 double const w = (ictx->vp.x1 - ictx->vp.x0);
151 double const h = (ictx->vp.y1 - ictx->vp.y0);
152 double const em = style->font_size.computed;
153 double const ex = em * 0.5; // fixme: get from pango or libnrtype.
154 line->x1.update(em, ex, w);
155 line->x2.update(em, ex, w);
156 line->y1.update(em, ex, h);
157 line->y2.update(em, ex, h);
159 sp_shape_set_shape ((SPShape *) object);
160 }
162 if (((SPObjectClass *) parent_class)->update)
163 ((SPObjectClass *) parent_class)->update (object, ctx, flags);
164 }
167 static Inkscape::XML::Node *
168 sp_line_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
169 {
170 SPLine *line = SP_LINE (object);
172 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
173 repr = xml_doc->createElement("svg:line");
174 }
176 if (repr != SP_OBJECT_REPR (object)) {
177 repr->mergeFrom(SP_OBJECT_REPR (object), "id");
178 }
180 sp_repr_set_svg_double(repr, "x1", line->x1.computed);
181 sp_repr_set_svg_double(repr, "y1", line->y1.computed);
182 sp_repr_set_svg_double(repr, "x2", line->x2.computed);
183 sp_repr_set_svg_double(repr, "y2", line->y2.computed);
185 if (((SPObjectClass *) (parent_class))->write)
186 ((SPObjectClass *) (parent_class))->write (object, xml_doc, repr, flags);
188 return repr;
189 }
191 static gchar *
192 sp_line_description(SPItem */*item*/)
193 {
194 return g_strdup(_("<b>Line</b>"));
195 }
197 static void
198 sp_line_convert_to_guides(SPItem *item)
199 {
200 SPLine *line = SP_LINE(item);
201 Geom::Point points[2];
203 Geom::Matrix const i2d (sp_item_i2d_affine(item));
205 points[0] = Geom::Point(line->x1.computed, line->y1.computed)*i2d;
206 points[1] = Geom::Point(line->x2.computed, line->y2.computed)*i2d;
208 sp_guide_create(inkscape_active_desktop(), points[0], points[1]);
209 }
211 static Geom::Matrix
212 sp_line_set_transform (SPItem *item, Geom::Matrix const &xform)
213 {
214 SPLine *line = SP_LINE (item);
215 Geom::Point points[2];
217 points[0] = Geom::Point(line->x1.computed, line->y1.computed);
218 points[1] = Geom::Point(line->x2.computed, line->y2.computed);
220 points[0] *= xform;
221 points[1] *= xform;
223 line->x1.computed = points[0][Geom::X];
224 line->y1.computed = points[0][Geom::Y];
225 line->x2.computed = points[1][Geom::X];
226 line->y2.computed = points[1][Geom::Y];
228 sp_item_adjust_stroke(item, xform.descrim());
230 SP_OBJECT (item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
232 return Geom::identity();
233 }
235 static void
236 sp_line_set_shape (SPShape *shape)
237 {
238 SPLine *line = SP_LINE (shape);
240 SPCurve *c = new SPCurve ();
242 c->moveto(line->x1.computed, line->y1.computed);
243 c->lineto(line->x2.computed, line->y2.computed);
245 sp_shape_set_curve_insync (shape, c, TRUE); // *_insync does not call update, avoiding infinite recursion when set_shape is called by update
247 c->unref();
248 }