Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / sp-rect.cpp
index 08d30b4f4be5a8db104f2c1c4ae2f6abe9ba8bee..94be7551b3a00a5db40c24ada82fdb4ff99be567 100644 (file)
@@ -1,5 +1,3 @@
-#define __SP_RECT_C__
-
 /*
  * SVG <rect> implementation
  *
@@ -21,6 +19,7 @@
 #include <display/curve.h>
 #include <libnr/nr-matrix-ops.h>
 #include <libnr/nr-matrix-fns.h>
+#include <2geom/rect.h>
 
 #include "inkscape.h"
 #include "document.h"
@@ -30,7 +29,7 @@
 #include <glibmm/i18n.h>
 #include "xml/repr.h"
 #include "sp-guide.h"
-#include "prefs-utils.h"
+#include "preferences.h"
 
 #define noRECT_VERBOSE
 
@@ -43,11 +42,11 @@ static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags);
 static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 
 static gchar *sp_rect_description(SPItem *item);
-static NR::Matrix sp_rect_set_transform(SPItem *item, NR::Matrix const &xform);
+static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform);
 static void sp_rect_convert_to_guides(SPItem *item);
 
 static void sp_rect_set_shape(SPShape *shape);
-static void sp_rect_snappoints(SPItem const *item, SnapPointsIter p);
+static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
 
 static SPShapeClass *parent_class;
 
@@ -114,12 +113,12 @@ sp_rect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
     if (((SPObjectClass *) parent_class)->build)
         ((SPObjectClass *) parent_class)->build(object, document, repr);
 
-    sp_object_read_attr(object, "x");
-    sp_object_read_attr(object, "y");
-    sp_object_read_attr(object, "width");
-    sp_object_read_attr(object, "height");
-    sp_object_read_attr(object, "rx");
-    sp_object_read_attr(object, "ry");
+    object->readAttr( "x" );
+    object->readAttr( "y" );
+    object->readAttr( "width" );
+    object->readAttr( "height" );
+    object->readAttr( "rx" );
+    object->readAttr( "ry" );
 }
 
 static void
@@ -176,9 +175,8 @@ sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
         SPRect *rect = (SPRect *) object;
         SPStyle *style = object->style;
         SPItemCtx const *ictx = (SPItemCtx const *) ctx;
-        double const d = NR::expansion(ictx->i2vp);
-        double const w = (ictx->vp.x1 - ictx->vp.x0) / d;
-        double const h = (ictx->vp.y1 - ictx->vp.y0) / d;
+        double const w = (ictx->vp.x1 - ictx->vp.x0);
+        double const h = (ictx->vp.y1 - ictx->vp.y0);
         double const em = style->font_size.computed;
         double const ex = 0.5 * em;  // fixme: get x height from pango or libnrtype.
         rect->x.update(em, ex, w);
@@ -187,7 +185,7 @@ sp_rect_update(SPObject *object, SPCtx *ctx, guint flags)
         rect->height.update(em, ex, h);
         rect->rx.update(em, ex, w);
         rect->ry.update(em, ex, h);
-        sp_shape_set_shape((SPShape *) object);
+        ((SPShape *) object)->setShape();
         flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
     }
 
@@ -233,7 +231,7 @@ sp_rect_set_shape(SPShape *shape)
     SPRect *rect = (SPRect *) shape;
 
     if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) {
-        sp_shape_set_curve_insync(SP_SHAPE(rect), NULL, TRUE);
+        SP_SHAPE(rect)->setCurveInsync( NULL, TRUE);
         return;
     }
 
@@ -280,11 +278,10 @@ sp_rect_set_shape(SPShape *shape)
         c->lineto(x + w, y + 0.0);
         c->lineto(x + w, y + h);
         c->lineto(x + 0.0, y + h);
-        c->lineto(x + 0.0, y + 0.0);
     }
 
-    c->closepath_current();
-    sp_shape_set_curve_insync(SP_SHAPE(rect), c, TRUE);
+    c->closepath();
+    SP_SHAPE(rect)->setCurveInsync( c, TRUE);
     c->unref();
 }
 
@@ -336,17 +333,17 @@ sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value)
 /* fixme: Use preferred units somehow (Lauris) */
 /* fixme: Alternately preserve whatever units there are (lauris) */
 
-static NR::Matrix
-sp_rect_set_transform(SPItem *item, NR::Matrix const &xform)
+static Geom::Matrix
+sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform)
 {
     SPRect *rect = SP_RECT(item);
 
     /* Calculate rect start in parent coords. */
-    NR::Point pos( NR::Point(rect->x.computed, rect->y.computed) * xform );
+    Geom::Point pos( Geom::Point(rect->x.computed, rect->y.computed) * xform );
 
     /* This function takes care of translation and scaling, we return whatever parts we can't
        handle. */
-    NR::Matrix ret(NR::transform(xform));
+    Geom::Matrix ret(Geom::Matrix(xform).without_translation());
     gdouble const sw = hypot(ret[0], ret[1]);
     gdouble const sh = hypot(ret[2], ret[3]);
     if (sw > 1e-9) {
@@ -376,19 +373,19 @@ sp_rect_set_transform(SPItem *item, NR::Matrix const &xform)
 
     /* Find start in item coords */
     pos = pos * ret.inverse();
-    rect->x = pos[NR::X];
-    rect->y = pos[NR::Y];
+    rect->x = pos[Geom::X];
+    rect->y = pos[Geom::Y];
 
     sp_rect_set_shape(rect);
 
     // Adjust stroke width
-    sp_item_adjust_stroke(item, sqrt(fabs(sw * sh)));
+    item->adjust_stroke(sqrt(fabs(sw * sh)));
 
     // Adjust pattern fill
-    sp_item_adjust_pattern(item, xform * ret.inverse());
+    item->adjust_pattern(xform * ret.inverse());
 
     // Adjust gradient fill
-    sp_item_adjust_gradient(item, xform * ret.inverse());
+    item->adjust_gradient(xform * ret.inverse());
 
     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
 
@@ -400,11 +397,11 @@ sp_rect_set_transform(SPItem *item, NR::Matrix const &xform)
 Returns the ratio in which the vector from p0 to p1 is stretched by transform
  */
 static gdouble
-vector_stretch(NR::Point p0, NR::Point p1, NR::Matrix xform)
+vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform)
 {
     if (p0 == p1)
         return 0;
-    return (NR::distance(p0 * xform, p1 * xform) / NR::distance(p0, p1));
+    return (Geom::distance(p0 * xform, p1 * xform) / Geom::distance(p0, p1));
 }
 
 void
@@ -415,8 +412,8 @@ sp_rect_set_visible_rx(SPRect *rect, gdouble rx)
         rect->rx._set = false;
     } else {
         rect->rx.computed = rx / vector_stretch(
-            NR::Point(rect->x.computed + 1, rect->y.computed),
-            NR::Point(rect->x.computed, rect->y.computed),
+            Geom::Point(rect->x.computed + 1, rect->y.computed),
+            Geom::Point(rect->x.computed, rect->y.computed),
             SP_ITEM(rect)->transform);
         rect->rx._set = true;
     }
@@ -431,8 +428,8 @@ sp_rect_set_visible_ry(SPRect *rect, gdouble ry)
         rect->ry._set = false;
     } else {
         rect->ry.computed = ry / vector_stretch(
-            NR::Point(rect->x.computed, rect->y.computed + 1),
-            NR::Point(rect->x.computed, rect->y.computed),
+            Geom::Point(rect->x.computed, rect->y.computed + 1),
+            Geom::Point(rect->x.computed, rect->y.computed),
             SP_ITEM(rect)->transform);
         rect->ry._set = true;
     }
@@ -445,8 +442,8 @@ sp_rect_get_visible_rx(SPRect *rect)
     if (!rect->rx._set)
         return 0;
     return rect->rx.computed * vector_stretch(
-        NR::Point(rect->x.computed + 1, rect->y.computed),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed + 1, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
 }
 
@@ -456,21 +453,29 @@ sp_rect_get_visible_ry(SPRect *rect)
     if (!rect->ry._set)
         return 0;
     return rect->ry.computed * vector_stretch(
-        NR::Point(rect->x.computed, rect->y.computed + 1),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed + 1),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
 }
 
+Geom::Rect
+sp_rect_get_rect (SPRect *rect)
+{
+    Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed);
+    Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
+    return Geom::Rect(p0, p2);
+}
+
 void
-sp_rect_compensate_rxry(SPRect *rect, NR::Matrix xform)
+sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform)
 {
     if (rect->rx.computed == 0 && rect->ry.computed == 0)
         return; // nothing to compensate
 
     // test unit vectors to find out compensation:
-    NR::Point c(rect->x.computed, rect->y.computed);
-    NR::Point cx = c + NR::Point(1, 0);
-    NR::Point cy = c + NR::Point(0, 1);
+    Geom::Point c(rect->x.computed, rect->y.computed);
+    Geom::Point cx = c + Geom::Point(1, 0);
+    Geom::Point cy = c + Geom::Point(0, 1);
 
     // apply previous transform if any
     c *= SP_ITEM(rect)->transform;
@@ -503,8 +508,8 @@ void
 sp_rect_set_visible_width(SPRect *rect, gdouble width)
 {
     rect->width.computed = width / vector_stretch(
-        NR::Point(rect->x.computed + 1, rect->y.computed),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed + 1, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
     rect->width._set = true;
     SP_OBJECT(rect)->updateRepr();
@@ -514,8 +519,8 @@ void
 sp_rect_set_visible_height(SPRect *rect, gdouble height)
 {
     rect->height.computed = height / vector_stretch(
-        NR::Point(rect->x.computed, rect->y.computed + 1),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed + 1),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
     rect->height._set = true;
     SP_OBJECT(rect)->updateRepr();
@@ -527,8 +532,8 @@ sp_rect_get_visible_width(SPRect *rect)
     if (!rect->width._set)
         return 0;
     return rect->width.computed * vector_stretch(
-        NR::Point(rect->x.computed + 1, rect->y.computed),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed + 1, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
 }
 
@@ -538,53 +543,78 @@ sp_rect_get_visible_height(SPRect *rect)
     if (!rect->height._set)
         return 0;
     return rect->height.computed * vector_stretch(
-        NR::Point(rect->x.computed, rect->y.computed + 1),
-        NR::Point(rect->x.computed, rect->y.computed),
+        Geom::Point(rect->x.computed, rect->y.computed + 1),
+        Geom::Point(rect->x.computed, rect->y.computed),
         SP_ITEM(rect)->transform);
 }
 
 /**
  * Sets the snappoint p to the unrounded corners of the rectangle
  */
-static void sp_rect_snappoints(SPItem const *item, SnapPointsIter p)
+static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
 {
     /* This method overrides sp_shape_snappoints, which is the default for any shape. The default method
     returns all eight points along the path of a rounded rectangle, but not the real corners. Snapping
-    the startpoint and endpoint of each rounded corner is not very usefull and really confusing. Instead 
+    the startpoint and endpoint of each rounded corner is not very useful and really confusing. Instead
     we could snap either the real corners, or not snap at all. Bulia Byak opted to snap the real corners,
-    but it should be noted that this might be confusing in some cases with relatively large radii. With 
+    but it should be noted that this might be confusing in some cases with relatively large radii. With
     small radii though the user will easily understand which point is snapping. */
-    
+
     g_assert(item != NULL);
     g_assert(SP_IS_RECT(item));
 
+    // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
+    if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
+        return;
+    }
+
     SPRect *rect = SP_RECT(item);
 
-    NR::Matrix const i2d (from_2geom(sp_item_i2d_affine (item)));
+    Geom::Matrix const i2d (item->i2d_affine ());
+
+    Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d;
+    Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
+    Geom::Point p2 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
+    Geom::Point p3 = Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
+
+    if (snapprefs->getSnapToItemNode()) {
+        p.push_back(Inkscape::SnapCandidatePoint(p0, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
+        p.push_back(Inkscape::SnapCandidatePoint(p1, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
+        p.push_back(Inkscape::SnapCandidatePoint(p2, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
+        p.push_back(Inkscape::SnapCandidatePoint(p3, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER));
+    }
+
+    if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
+        p.push_back(Inkscape::SnapCandidatePoint((p0 + p1)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+        p.push_back(Inkscape::SnapCandidatePoint((p1 + p2)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+        p.push_back(Inkscape::SnapCandidatePoint((p2 + p3)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+        p.push_back(Inkscape::SnapCandidatePoint((p3 + p0)/2, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+    }
+
+    if (snapprefs->getSnapObjectMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
+        p.push_back(Inkscape::SnapCandidatePoint((p0 + p2)/2, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
+    }
 
-    *p = NR::Point(rect->x.computed, rect->y.computed) * i2d;
-    *p = NR::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d;
-    *p = NR::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d;
-    *p = NR::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d;
 }
 
 void
 sp_rect_convert_to_guides(SPItem *item) {
     SPRect *rect = SP_RECT(item);
 
-    if (prefs_get_int_attribute("tools.shapes.rect", "convertguides", 1) == 0) {
-        sp_item_convert_to_guides(SP_ITEM(rect));
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    if (!prefs->getBool("/tools/shapes/rect/convertguides", true)) {
+        SP_ITEM(rect)->convert_to_guides();
         return;
     }
 
     std::list<std::pair<Geom::Point, Geom::Point> > pts;
 
-    NR::Matrix const i2d (from_2geom(sp_item_i2d_affine(SP_ITEM(rect))));
+    Geom::Matrix const i2d (SP_ITEM(rect)->i2d_affine());
 
-    NR::Point A1(NR::Point(rect->x.computed, rect->y.computed) * i2d);
-    NR::Point A2(NR::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
-    NR::Point A3(NR::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
-    NR::Point A4(NR::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
+    Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d);
+    Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d);
+    Geom::Point A3(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed) * i2d);
+    Geom::Point A4(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed) * i2d);
 
     pts.push_back(std::make_pair(A1, A2));
     pts.push_back(std::make_pair(A2, A3));