Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / sp-rect.cpp
1 /*
2  * SVG <rect> implementation
3  *
4  * Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   bulia byak <buliabyak@users.sf.net>
7  *
8  * Copyright (C) 1999-2002 Lauris Kaplinski
9  * Copyright (C) 2000-2001 Ximian, Inc.
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
19 #include <display/curve.h>
20 #include <libnr/nr-matrix-ops.h>
21 #include <libnr/nr-matrix-fns.h>
22 #include <2geom/rect.h>
24 #include "inkscape.h"
25 #include "document.h"
26 #include "attributes.h"
27 #include "style.h"
28 #include "sp-rect.h"
29 #include <glibmm/i18n.h>
30 #include "xml/repr.h"
31 #include "sp-guide.h"
32 #include "preferences.h"
34 #define noRECT_VERBOSE
36 static void sp_rect_class_init(SPRectClass *klass);
37 static void sp_rect_init(SPRect *rect);
39 static void sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
40 static void sp_rect_set(SPObject *object, unsigned key, gchar const *value);
41 static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags);
42 static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
44 static gchar *sp_rect_description(SPItem *item);
45 static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform);
46 static void sp_rect_convert_to_guides(SPItem *item);
48 static void sp_rect_set_shape(SPShape *shape);
49 static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
51 static SPShapeClass *parent_class;
53 GType
54 sp_rect_get_type(void)
55 {
56     static GType type = 0;
58     if (!type) {
59         GTypeInfo info = {
60             sizeof(SPRectClass),
61             NULL,   /* base_init */
62             NULL,   /* base_finalize */
63             (GClassInitFunc) sp_rect_class_init,
64             NULL,   /* class_finalize */
65             NULL,   /* class_data */
66             sizeof(SPRect),
67             16,     /* n_preallocs */
68             (GInstanceInitFunc) sp_rect_init,
69             NULL,   /* value_table */
70         };
71         type = g_type_register_static(SP_TYPE_SHAPE, "SPRect", &info, (GTypeFlags)0);
72     }
73     return type;
74 }
76 static void
77 sp_rect_class_init(SPRectClass *klass)
78 {
79     SPObjectClass *sp_object_class = (SPObjectClass *) klass;
80     SPItemClass *item_class = (SPItemClass *) klass;
81     SPShapeClass *shape_class = (SPShapeClass *) klass;
83     parent_class = (SPShapeClass *)g_type_class_ref(SP_TYPE_SHAPE);
85     sp_object_class->build = sp_rect_build;
86     sp_object_class->write = sp_rect_write;
87     sp_object_class->set = sp_rect_set;
88     sp_object_class->update = sp_rect_update;
90     item_class->description = sp_rect_description;
91     item_class->set_transform = sp_rect_set_transform;
92     item_class->convert_to_guides = sp_rect_convert_to_guides;
93     item_class->snappoints = sp_rect_snappoints; //override the default sp_shape_snappoints; see sp_rect_snappoints for details
95     shape_class->set_shape = sp_rect_set_shape;
96 }
98 static void
99 sp_rect_init(SPRect */*rect*/)
101     /* Initializing to zero is automatic */
102     /* sp_svg_length_unset(&rect->x, SP_SVG_UNIT_NONE, 0.0, 0.0); */
103     /* sp_svg_length_unset(&rect->y, SP_SVG_UNIT_NONE, 0.0, 0.0); */
104     /* sp_svg_length_unset(&rect->width, SP_SVG_UNIT_NONE, 0.0, 0.0); */
105     /* sp_svg_length_unset(&rect->height, SP_SVG_UNIT_NONE, 0.0, 0.0); */
106     /* sp_svg_length_unset(&rect->rx, SP_SVG_UNIT_NONE, 0.0, 0.0); */
107     /* sp_svg_length_unset(&rect->ry, SP_SVG_UNIT_NONE, 0.0, 0.0); */
110 static void
111 sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
113     if (((SPObjectClass *) parent_class)->build)
114         ((SPObjectClass *) parent_class)->build(object, document, repr);
116     object->readAttr( "x" );
117     object->readAttr( "y" );
118     object->readAttr( "width" );
119     object->readAttr( "height" );
120     object->readAttr( "rx" );
121     object->readAttr( "ry" );
124 static void
125 sp_rect_set(SPObject *object, unsigned key, gchar const *value)
127     SPRect *rect = SP_RECT(object);
129     /* fixme: We need real error processing some time */
131     switch (key) {
132         case SP_ATTR_X:
133             rect->x.readOrUnset(value);
134             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
135             break;
136         case SP_ATTR_Y:
137             rect->y.readOrUnset(value);
138             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
139             break;
140         case SP_ATTR_WIDTH:
141             if (!rect->width.read(value) || rect->width.value < 0.0) {
142                 rect->width.unset();
143             }
144             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
145             break;
146         case SP_ATTR_HEIGHT:
147             if (!rect->height.read(value) || rect->height.value < 0.0) {
148                 rect->height.unset();
149             }
150             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
151             break;
152         case SP_ATTR_RX:
153             if (!rect->rx.read(value) || rect->rx.value < 0.0) {
154                 rect->rx.unset();
155             }
156             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
157             break;
158         case SP_ATTR_RY:
159             if (!rect->ry.read(value) || rect->ry.value < 0.0) {
160                 rect->ry.unset();
161             }
162             object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
163             break;
164         default:
165             if (((SPObjectClass *) parent_class)->set)
166                 ((SPObjectClass *) parent_class)->set(object, key, value);
167             break;
168     }
171 static void
172 sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
174     if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
175         SPRect *rect = (SPRect *) object;
176         SPStyle *style = object->style;
177         SPItemCtx const *ictx = (SPItemCtx const *) ctx;
178         double const w = (ictx->vp.x1 - ictx->vp.x0);
179         double const h = (ictx->vp.y1 - ictx->vp.y0);
180         double const em = style->font_size.computed;
181         double const ex = 0.5 * em;  // fixme: get x height from pango or libnrtype.
182         rect->x.update(em, ex, w);
183         rect->y.update(em, ex, h);
184         rect->width.update(em, ex, w);
185         rect->height.update(em, ex, h);
186         rect->rx.update(em, ex, w);
187         rect->ry.update(em, ex, h);
188         ((SPShape *) object)->setShape();
189         flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
190     }
192     if (((SPObjectClass *) parent_class)->update)
193         ((SPObjectClass *) parent_class)->update(object, ctx, flags);
196 static Inkscape::XML::Node *
197 sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
199     SPRect *rect = SP_RECT(object);
201     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
202         repr = xml_doc->createElement("svg:rect");
203     }
205     sp_repr_set_svg_double(repr, "width", rect->width.computed);
206     sp_repr_set_svg_double(repr, "height", rect->height.computed);
207     if (rect->rx._set) sp_repr_set_svg_double(repr, "rx", rect->rx.computed);
208     if (rect->ry._set) sp_repr_set_svg_double(repr, "ry", rect->ry.computed);
209     sp_repr_set_svg_double(repr, "x", rect->x.computed);
210     sp_repr_set_svg_double(repr, "y", rect->y.computed);
212     if (((SPObjectClass *) parent_class)->write)
213         ((SPObjectClass *) parent_class)->write(object, xml_doc, repr, flags);
215     return repr;
218 static gchar *
219 sp_rect_description(SPItem *item)
221     g_return_val_if_fail(SP_IS_RECT(item), NULL);
223     return g_strdup(_("<b>Rectangle</b>"));
226 #define C1 0.554
228 static void
229 sp_rect_set_shape(SPShape *shape)
231     SPRect *rect = (SPRect *) shape;
233     if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) {
234         SP_SHAPE(rect)->setCurveInsync( NULL, TRUE);
235         return;
236     }
238     SPCurve *c = new SPCurve();
240     double const x = rect->x.computed;
241     double const y = rect->y.computed;
242     double const w = rect->width.computed;
243     double const h = rect->height.computed;
244     double const w2 = w / 2;
245     double const h2 = h / 2;
246     double const rx = std::min(( rect->rx._set
247                                  ? rect->rx.computed
248                                  : ( rect->ry._set
249                                      ? rect->ry.computed
250                                      : 0.0 ) ),
251                                .5 * rect->width.computed);
252     double const ry = std::min(( rect->ry._set
253                                  ? rect->ry.computed
254                                  : ( rect->rx._set
255                                      ? rect->rx.computed
256                                      : 0.0 ) ),
257                                .5 * rect->height.computed);
258     /* TODO: Handle negative rx or ry as per
259      * http://www.w3.org/TR/SVG11/shapes.html#RectElementRXAttribute once Inkscape has proper error
260      * handling (see http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing).
261      */
263     /* We don't use proper circular/elliptical arcs, but bezier curves can approximate a 90-degree
264      * arc fairly well.
265      */
266     if ((rx > 1e-18) && (ry > 1e-18)) {
267         c->moveto(x + rx, y);
268         if (rx < w2) c->lineto(x + w - rx, y);
269         c->curveto(x + w - rx * (1 - C1), y,     x + w, y + ry * (1 - C1),       x + w, y + ry);
270         if (ry < h2) c->lineto(x + w, y + h - ry);
271         c->curveto(x + w, y + h - ry * (1 - C1),     x + w - rx * (1 - C1), y + h,       x + w - rx, y + h);
272         if (rx < w2) c->lineto(x + rx, y + h);
273         c->curveto(x + rx * (1 - C1), y + h,     x, y + h - ry * (1 - C1),       x, y + h - ry);
274         if (ry < h2) c->lineto(x, y + ry);
275         c->curveto(x, y + ry * (1 - C1),     x + rx * (1 - C1), y,       x + rx, y);
276     } else {
277         c->moveto(x + 0.0, y + 0.0);
278         c->lineto(x + w, y + 0.0);
279         c->lineto(x + w, y + h);
280         c->lineto(x + 0.0, y + h);
281     }
283     c->closepath();
284     SP_SHAPE(rect)->setCurveInsync( c, TRUE);
285     c->unref();
288 /* fixme: Think (Lauris) */
290 void
291 sp_rect_position_set(SPRect *rect, gdouble x, gdouble y, gdouble width, gdouble height)
293     g_return_if_fail(rect != NULL);
294     g_return_if_fail(SP_IS_RECT(rect));
296     rect->x.computed = x;
297     rect->y.computed = y;
298     rect->width.computed = width;
299     rect->height.computed = height;
301     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
304 void
305 sp_rect_set_rx(SPRect *rect, gboolean set, gdouble value)
307     g_return_if_fail(rect != NULL);
308     g_return_if_fail(SP_IS_RECT(rect));
310     rect->rx._set = set;
311     if (set) rect->rx.computed = value;
313     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
316 void
317 sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value)
319     g_return_if_fail(rect != NULL);
320     g_return_if_fail(SP_IS_RECT(rect));
322     rect->ry._set = set;
323     if (set) rect->ry.computed = value;
325     SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
328 /*
329  * Initially we'll do:
330  * Transform x, y, set x, y, clear translation
331  */
333 /* fixme: Use preferred units somehow (Lauris) */
334 /* fixme: Alternately preserve whatever units there are (lauris) */
336 static Geom::Matrix
337 sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform)
339     SPRect *rect = SP_RECT(item);
341     /* Calculate rect start in parent coords. */
342     Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform );
344     /* This function takes care of translation and scaling, we return whatever parts we can't
345        handle. */
346     Geom::Matrix ret(Geom::Matrix(xform).without_translation());
347     gdouble const sw = hypot(ret[0], ret[1]);
348     gdouble const sh = hypot(ret[2], ret[3]);
349     if (sw > 1e-9) {
350         ret[0] /= sw;
351         ret[1] /= sw;
352     } else {
353         ret[0] = 1.0;
354         ret[1] = 0.0;
355     }
356     if (sh > 1e-9) {
357         ret[2] /= sh;
358         ret[3] /= sh;
359     } else {
360         ret[2] = 0.0;
361         ret[3] = 1.0;
362     }
364     /* fixme: Would be nice to preserve units here */
365     rect->width = rect->width.computed * sw;
366     rect->height = rect->height.computed * sh;
367     if (rect->rx._set) {
368         rect->rx = rect->rx.computed * sw;
369     }
370     if (rect->ry._set) {
371         rect->ry = rect->ry.computed * sh;
372     }
374     /* Find start in item coords */
375     pos = pos * ret.inverse();
376     rect->x = pos[Geom::X];
377     rect->y = pos[Geom::Y];
379     sp_rect_set_shape(rect);
381     // Adjust stroke width
382     item->adjust_stroke(sqrt(fabs(sw * sh)));
384     // Adjust pattern fill
385     item->adjust_pattern(xform * ret.inverse());
387     // Adjust gradient fill
388     item->adjust_gradient(xform * ret.inverse());
390     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
392     return ret;
396 /**
397 Returns the ratio in which the vector from p0 to p1 is stretched by transform
398  */
399 static gdouble
400 vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform)
402     if (p0 == p1)
403         return 0;
404     return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1));
407 void
408 sp_rect_set_visible_rx(SPRect *rect, gdouble rx)
410     if (rx == 0) {
411         rect->rx.computed = 0;
412         rect->rx._set = false;
413     } else {
414         rect->rx.computed = rx / vector_stretch(
415             Geom::Point(rect->x.computed + 1, rect->y.computed),
416             Geom::Point(rect->x.computed, rect->y.computed),
417             SP_ITEM(rect)->transform);
418         rect->rx._set = true;
419     }
420     SP_OBJECT(rect)->updateRepr();
423 void
424 sp_rect_set_visible_ry(SPRect *rect, gdouble ry)
426     if (ry == 0) {
427         rect->ry.computed = 0;
428         rect->ry._set = false;
429     } else {
430         rect->ry.computed = ry / vector_stretch(
431             Geom::Point(rect->x.computed, rect->y.computed + 1),
432             Geom::Point(rect->x.computed, rect->y.computed),
433             SP_ITEM(rect)->transform);
434         rect->ry._set = true;
435     }
436     SP_OBJECT(rect)->updateRepr();
439 gdouble
440 sp_rect_get_visible_rx(SPRect *rect)
442     if (!rect->rx._set)
443         return 0;
444     return rect->rx.computed * vector_stretch(
445         Geom::Point(rect->x.computed + 1, rect->y.computed),
446         Geom::Point(rect->x.computed, rect->y.computed),
447         SP_ITEM(rect)->transform);
450 gdouble
451 sp_rect_get_visible_ry(SPRect *rect)
453     if (!rect->ry._set)
454         return 0;
455     return rect->ry.computed * vector_stretch(
456         Geom::Point(rect->x.computed, rect->y.computed + 1),
457         Geom::Point(rect->x.computed, rect->y.computed),
458         SP_ITEM(rect)->transform);
461 Geom::Rect
462 sp_rect_get_rect (SPRect *rect)
464     Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed);
465     Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
466     return Geom::Rect(p0, p2);
469 void
470 sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform)
472     if (rect->rx.computed == 0 && rect->ry.computed == 0)
473         return; // nothing to compensate
475     // test unit vectors to find out compensation:
476     Geom::Point c(rect->x.computed, rect->y.computed);
477     Geom::Point cx = c + Geom::Point(1, 0);
478     Geom::Point cy = c + Geom::Point(0, 1);
480     // apply previous transform if any
481     c *= SP_ITEM(rect)->transform;
482     cx *= SP_ITEM(rect)->transform;
483     cy *= SP_ITEM(rect)->transform;
485     // find out stretches that we need to compensate
486     gdouble eX = vector_stretch(cx, c, xform);
487     gdouble eY = vector_stretch(cy, c, xform);
489     // If only one of the radii is set, set both radii so they have the same visible length
490     // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform
491     if ((rect->rx._set && !rect->ry._set) || (rect->ry._set && !rect->rx._set)) {
492         gdouble r = MAX(rect->rx.computed, rect->ry.computed);
493         rect->rx.computed = r / eX;
494         rect->ry.computed = r / eY;
495     } else {
496         rect->rx.computed = rect->rx.computed / eX;
497         rect->ry.computed = rect->ry.computed / eY;
498     }
500     // Note that a radius may end up larger than half-side if the rect is scaled down;
501     // that's ok because this preserves the intended radii in case the rect is enlarged again,
502     // and set_shape will take care of trimming too large radii when generating d=
504     rect->rx._set = rect->ry._set = true;
507 void
508 sp_rect_set_visible_width(SPRect *rect, gdouble width)
510     rect->width.computed = width / vector_stretch(
511         Geom::Point(rect->x.computed + 1, rect->y.computed),
512         Geom::Point(rect->x.computed, rect->y.computed),
513         SP_ITEM(rect)->transform);
514     rect->width._set = true;
515     SP_OBJECT(rect)->updateRepr();
518 void
519 sp_rect_set_visible_height(SPRect *rect, gdouble height)
521     rect->height.computed = height / vector_stretch(
522         Geom::Point(rect->x.computed, rect->y.computed + 1),
523         Geom::Point(rect->x.computed, rect->y.computed),
524         SP_ITEM(rect)->transform);
525     rect->height._set = true;
526     SP_OBJECT(rect)->updateRepr();
529 gdouble
530 sp_rect_get_visible_width(SPRect *rect)
532     if (!rect->width._set)
533         return 0;
534     return rect->width.computed * vector_stretch(
535         Geom::Point(rect->x.computed + 1, rect->y.computed),
536         Geom::Point(rect->x.computed, rect->y.computed),
537         SP_ITEM(rect)->transform);
540 gdouble
541 sp_rect_get_visible_height(SPRect *rect)
543     if (!rect->height._set)
544         return 0;
545     return rect->height.computed * vector_stretch(
546         Geom::Point(rect->x.computed, rect->y.computed + 1),
547         Geom::Point(rect->x.computed, rect->y.computed),
548         SP_ITEM(rect)->transform);
551 /**
552  * Sets the snappoint p to the unrounded corners of the rectangle
553  */
554 static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
556     /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method
557     returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping
558     the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead
559     we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners,
560     but it should be noted that this might be confusing in some cases with relatively large radii. With
561     small radii though the user will easily understand which point is snapping. */
563     g_assert(item != NULL);
564     g_assert(SP_IS_RECT(item));
566     // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
567     if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
568         return;
569     }
571     SPRect *rect = SP_RECT(item);
573     Geom::Matrix const i2d (item->i2d_affine ());
575     Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d;
576     Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
577     Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
578     Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
580     if (snapprefs->getSnapToItemNode()) {
581         p.push_back(Inkscape::SnapCandidatePoint(p0, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
582         p.push_back(Inkscape::SnapCandidatePoint(p1, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
583         p.push_back(Inkscape::SnapCandidatePoint(p2, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
584         p.push_back(Inkscape::SnapCandidatePoint(p3, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
585     }
587     if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
588         p.push_back(Inkscape::SnapCandidatePoint((p0 + p1)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
589         p.push_back(Inkscape::SnapCandidatePoint((p1 + p2)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
590         p.push_back(Inkscape::SnapCandidatePoint((p2 + p3)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
591         p.push_back(Inkscape::SnapCandidatePoint((p3 + p0)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
592     }
594     if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
595         p.push_back(Inkscape::SnapCandidatePoint((p0 + p2)/2, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
596     }
600 void
601 sp_rect_convert_to_guides(SPItem *item) {
602     SPRect *rect = SP_RECT(item);
604     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
605     if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) {
606         SP_ITEM(rect)->convert_to_guides();
607         return;
608     }
610     std::list<std::pair<Geom::Point, Geom::Point> > pts;
612     Geom::Matrix const i2d (SP_ITEM(rect)->i2d_affine());
614     Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d);
615     Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
616     Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
617     Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
619     pts.push_back(std::make_pair(A1, A2));
620     pts.push_back(std::make_pair(A2, A3));
621     pts.push_back(std::make_pair(A3, A4));
622     pts.push_back(std::make_pair(A4, A1));
624     sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts);
627 /*
628   Local Variables:
629   mode:c++
630   c-file-style:"stroustrup"
631   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
632   indent-tabs-mode:nil
633   fill-column:99
634   End:
635 */
636 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :