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, bool const target, SnapPointsWithType &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*/)
100 {
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); */
108 }
110 static void
111 sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
112 {
113 if (((SPObjectClass *) parent_class)->build)
114 ((SPObjectClass *) parent_class)->build(object, document, repr);
116 sp_object_read_attr(object, "x");
117 sp_object_read_attr(object, "y");
118 sp_object_read_attr(object, "width");
119 sp_object_read_attr(object, "height");
120 sp_object_read_attr(object, "rx");
121 sp_object_read_attr(object, "ry");
122 }
124 static void
125 sp_rect_set(SPObject *object, unsigned key, gchar const *value)
126 {
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 }
169 }
171 static void
172 sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
173 {
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 sp_shape_set_shape((SPShape *) object);
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);
194 }
196 static Inkscape::XML::Node *
197 sp_rect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
198 {
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;
216 }
218 static gchar *
219 sp_rect_description(SPItem *item)
220 {
221 g_return_val_if_fail(SP_IS_RECT(item), NULL);
223 return g_strdup(_("<b>Rectangle</b>"));
224 }
226 #define C1 0.554
228 static void
229 sp_rect_set_shape(SPShape *shape)
230 {
231 SPRect *rect = (SPRect *) shape;
233 if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) {
234 sp_shape_set_curve_insync(SP_SHAPE(rect), 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 c->lineto(x + 0.0, y + 0.0);
282 }
284 c->closepath_current();
285 sp_shape_set_curve_insync(SP_SHAPE(rect), c, TRUE);
286 c->unref();
287 }
289 /* fixme: Think (Lauris) */
291 void
292 sp_rect_position_set(SPRect *rect, gdouble x, gdouble y, gdouble width, gdouble height)
293 {
294 g_return_if_fail(rect != NULL);
295 g_return_if_fail(SP_IS_RECT(rect));
297 rect->x.computed = x;
298 rect->y.computed = y;
299 rect->width.computed = width;
300 rect->height.computed = height;
302 SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
303 }
305 void
306 sp_rect_set_rx(SPRect *rect, gboolean set, gdouble value)
307 {
308 g_return_if_fail(rect != NULL);
309 g_return_if_fail(SP_IS_RECT(rect));
311 rect->rx._set = set;
312 if (set) rect->rx.computed = value;
314 SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
315 }
317 void
318 sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value)
319 {
320 g_return_if_fail(rect != NULL);
321 g_return_if_fail(SP_IS_RECT(rect));
323 rect->ry._set = set;
324 if (set) rect->ry.computed = value;
326 SP_OBJECT(rect)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
327 }
329 /*
330 * Initially we'll do:
331 * Transform x, y, set x, y, clear translation
332 */
334 /* fixme: Use preferred units somehow (Lauris) */
335 /* fixme: Alternately preserve whatever units there are (lauris) */
337 static Geom::Matrix
338 sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform)
339 {
340 SPRect *rect = SP_RECT(item);
342 /* Calculate rect start in parent coords. */
343 Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform );
345 /* This function takes care of translation and scaling, we return whatever parts we can't
346 handle. */
347 Geom::Matrix ret(Geom::Matrix(xform).without_translation());
348 gdouble const sw = hypot(ret[0], ret[1]);
349 gdouble const sh = hypot(ret[2], ret[3]);
350 if (sw > 1e-9) {
351 ret[0] /= sw;
352 ret[1] /= sw;
353 } else {
354 ret[0] = 1.0;
355 ret[1] = 0.0;
356 }
357 if (sh > 1e-9) {
358 ret[2] /= sh;
359 ret[3] /= sh;
360 } else {
361 ret[2] = 0.0;
362 ret[3] = 1.0;
363 }
365 /* fixme: Would be nice to preserve units here */
366 rect->width = rect->width.computed * sw;
367 rect->height = rect->height.computed * sh;
368 if (rect->rx._set) {
369 rect->rx = rect->rx.computed * sw;
370 }
371 if (rect->ry._set) {
372 rect->ry = rect->ry.computed * sh;
373 }
375 /* Find start in item coords */
376 pos = pos * ret.inverse();
377 rect->x = pos[Geom::X];
378 rect->y = pos[Geom::Y];
380 sp_rect_set_shape(rect);
382 // Adjust stroke width
383 sp_item_adjust_stroke(item, sqrt(fabs(sw * sh)));
385 // Adjust pattern fill
386 sp_item_adjust_pattern(item, xform * ret.inverse());
388 // Adjust gradient fill
389 sp_item_adjust_gradient(item, xform * ret.inverse());
391 item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
393 return ret;
394 }
397 /**
398 Returns the ratio in which the vector from p0 to p1 is stretched by transform
399 */
400 static gdouble
401 vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform)
402 {
403 if (p0 == p1)
404 return 0;
405 return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1));
406 }
408 void
409 sp_rect_set_visible_rx(SPRect *rect, gdouble rx)
410 {
411 if (rx == 0) {
412 rect->rx.computed = 0;
413 rect->rx._set = false;
414 } else {
415 rect->rx.computed = rx / vector_stretch(
416 Geom::Point(rect->x.computed + 1, rect->y.computed),
417 Geom::Point(rect->x.computed, rect->y.computed),
418 SP_ITEM(rect)->transform);
419 rect->rx._set = true;
420 }
421 SP_OBJECT(rect)->updateRepr();
422 }
424 void
425 sp_rect_set_visible_ry(SPRect *rect, gdouble ry)
426 {
427 if (ry == 0) {
428 rect->ry.computed = 0;
429 rect->ry._set = false;
430 } else {
431 rect->ry.computed = ry / vector_stretch(
432 Geom::Point(rect->x.computed, rect->y.computed + 1),
433 Geom::Point(rect->x.computed, rect->y.computed),
434 SP_ITEM(rect)->transform);
435 rect->ry._set = true;
436 }
437 SP_OBJECT(rect)->updateRepr();
438 }
440 gdouble
441 sp_rect_get_visible_rx(SPRect *rect)
442 {
443 if (!rect->rx._set)
444 return 0;
445 return rect->rx.computed * vector_stretch(
446 Geom::Point(rect->x.computed + 1, rect->y.computed),
447 Geom::Point(rect->x.computed, rect->y.computed),
448 SP_ITEM(rect)->transform);
449 }
451 gdouble
452 sp_rect_get_visible_ry(SPRect *rect)
453 {
454 if (!rect->ry._set)
455 return 0;
456 return rect->ry.computed * vector_stretch(
457 Geom::Point(rect->x.computed, rect->y.computed + 1),
458 Geom::Point(rect->x.computed, rect->y.computed),
459 SP_ITEM(rect)->transform);
460 }
462 Geom::Rect
463 sp_rect_get_rect (SPRect *rect)
464 {
465 Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed);
466 Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
467 return Geom::Rect(p0, p2);
468 }
470 void
471 sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform)
472 {
473 if (rect->rx.computed == 0 && rect->ry.computed == 0)
474 return; // nothing to compensate
476 // test unit vectors to find out compensation:
477 Geom::Point c(rect->x.computed, rect->y.computed);
478 Geom::Point cx = c + Geom::Point(1, 0);
479 Geom::Point cy = c + Geom::Point(0, 1);
481 // apply previous transform if any
482 c *= SP_ITEM(rect)->transform;
483 cx *= SP_ITEM(rect)->transform;
484 cy *= SP_ITEM(rect)->transform;
486 // find out stretches that we need to compensate
487 gdouble eX = vector_stretch(cx, c, xform);
488 gdouble eY = vector_stretch(cy, c, xform);
490 // If only one of the radii is set, set both radii so they have the same visible length
491 // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform
492 if ((rect->rx._set && !rect->ry._set) || (rect->ry._set && !rect->rx._set)) {
493 gdouble r = MAX(rect->rx.computed, rect->ry.computed);
494 rect->rx.computed = r / eX;
495 rect->ry.computed = r / eY;
496 } else {
497 rect->rx.computed = rect->rx.computed / eX;
498 rect->ry.computed = rect->ry.computed / eY;
499 }
501 // Note that a radius may end up larger than half-side if the rect is scaled down;
502 // that's ok because this preserves the intended radii in case the rect is enlarged again,
503 // and set_shape will take care of trimming too large radii when generating d=
505 rect->rx._set = rect->ry._set = true;
506 }
508 void
509 sp_rect_set_visible_width(SPRect *rect, gdouble width)
510 {
511 rect->width.computed = width / vector_stretch(
512 Geom::Point(rect->x.computed + 1, rect->y.computed),
513 Geom::Point(rect->x.computed, rect->y.computed),
514 SP_ITEM(rect)->transform);
515 rect->width._set = true;
516 SP_OBJECT(rect)->updateRepr();
517 }
519 void
520 sp_rect_set_visible_height(SPRect *rect, gdouble height)
521 {
522 rect->height.computed = height / vector_stretch(
523 Geom::Point(rect->x.computed, rect->y.computed + 1),
524 Geom::Point(rect->x.computed, rect->y.computed),
525 SP_ITEM(rect)->transform);
526 rect->height._set = true;
527 SP_OBJECT(rect)->updateRepr();
528 }
530 gdouble
531 sp_rect_get_visible_width(SPRect *rect)
532 {
533 if (!rect->width._set)
534 return 0;
535 return rect->width.computed * vector_stretch(
536 Geom::Point(rect->x.computed + 1, rect->y.computed),
537 Geom::Point(rect->x.computed, rect->y.computed),
538 SP_ITEM(rect)->transform);
539 }
541 gdouble
542 sp_rect_get_visible_height(SPRect *rect)
543 {
544 if (!rect->height._set)
545 return 0;
546 return rect->height.computed * vector_stretch(
547 Geom::Point(rect->x.computed, rect->y.computed + 1),
548 Geom::Point(rect->x.computed, rect->y.computed),
549 SP_ITEM(rect)->transform);
550 }
552 /**
553 * Sets the snappoint p to the unrounded corners of the rectangle
554 */
555 static void sp_rect_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs)
556 {
557 /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method
558 returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping
559 the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead
560 we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners,
561 but it should be noted that this might be confusing in some cases with relatively large radii. With
562 small radii though the user will easily understand which point is snapping. */
564 g_assert(item != NULL);
565 g_assert(SP_IS_RECT(item));
567 // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
568 if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
569 return;
570 }
572 SPRect *rect = SP_RECT(item);
574 Geom::Matrix const i2d (sp_item_i2d_affine (item));
576 Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d;
577 Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
578 Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
579 Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
581 int type;
583 if (snapprefs->getSnapToItemNode()) {
584 type = target ? int(Inkscape::SNAPTARGET_CORNER) : int(Inkscape::SNAPSOURCE_CORNER);
585 p.push_back(std::make_pair(p0, type));
586 p.push_back(std::make_pair(p1, type));
587 p.push_back(std::make_pair(p2, type));
588 p.push_back(std::make_pair(p3, type));
589 }
591 if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
592 type = target ? int(Inkscape::SNAPTARGET_LINE_MIDPOINT) : int(Inkscape::SNAPSOURCE_LINE_MIDPOINT);
593 p.push_back(std::make_pair((p0 + p1)/2, type));
594 p.push_back(std::make_pair((p1 + p2)/2, type));
595 p.push_back(std::make_pair((p2 + p3)/2, type));
596 p.push_back(std::make_pair((p3 + p0)/2, type));
597 }
599 if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
600 type = target ? int(Inkscape::SNAPTARGET_OBJECT_MIDPOINT) : int(Inkscape::SNAPSOURCE_OBJECT_MIDPOINT);
601 p.push_back(std::make_pair((p0 + p2)/2, type));
602 }
604 }
606 void
607 sp_rect_convert_to_guides(SPItem *item) {
608 SPRect *rect = SP_RECT(item);
610 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
611 if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) {
612 sp_item_convert_to_guides(SP_ITEM(rect));
613 return;
614 }
616 std::list<std::pair<Geom::Point, Geom::Point> > pts;
618 Geom::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(rect)));
620 Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d);
621 Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
622 Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
623 Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
625 pts.push_back(std::make_pair(A1, A2));
626 pts.push_back(std::make_pair(A2, A3));
627 pts.push_back(std::make_pair(A3, A4));
628 pts.push_back(std::make_pair(A4, A1));
630 sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts);
631 }
633 /*
634 Local Variables:
635 mode:c++
636 c-file-style:"stroustrup"
637 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
638 indent-tabs-mode:nil
639 fill-column:99
640 End:
641 */
642 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :