Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / object-edit.cpp
index 3b513fe8815354593b4a91c39f4985e69a5f47e8..9ad52eb1eded179bcc5a65b693ce1da31b8eb28c 100644 (file)
@@ -25,8 +25,7 @@
 #include "sp-spiral.h"
 #include "sp-offset.h"
 #include "sp-flowtext.h"
-#include "prefs-utils.h"
-#include "desktop-affine.h"
+#include "preferences.h"
 #include "style.h"
 #include "desktop.h"
 #include "desktop-handles.h"
@@ -142,14 +141,15 @@ RectKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     //In general we cannot just snap this radius to an arbitrary point, as we have only a single
     //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
     //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+    Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(-1, 0)));
 
     if (state & GDK_CONTROL_MASK) {
         gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
-        rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - p[NR::X], 0.0, temp);
+        rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp);
         rect->rx._set = rect->ry._set = true;
 
     } else {
-        rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - p[NR::X], 0.0, rect->width.computed / 2.0);
+        rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0);
         rect->rx._set = true;
     }
 
@@ -191,18 +191,20 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     //In general we cannot just snap this radius to an arbitrary point, as we have only a single
     //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
     //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+    Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(0, 1)));
 
-    if (state & GDK_CONTROL_MASK) {
+    if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry,
+                                    // resulting in a perfect circle (and not an ellipse)
         gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
-        rect->rx.computed = rect->ry.computed = CLAMP(p[NR::Y] - rect->y.computed, 0.0, temp);
+        rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp);
         rect->ry._set = rect->rx._set = true;
     } else {
         if (!rect->rx._set || rect->rx.computed == 0) {
-            rect->ry.computed = CLAMP(p[NR::Y] - rect->y.computed,
+            rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
                                       0.0,
                                       MIN(rect->height.computed / 2.0, rect->width.computed / 2.0));
         } else {
-            rect->ry.computed = CLAMP(p[NR::Y] - rect->y.computed,
+            rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
                                       0.0,
                                       rect->height.computed / 2.0);
         }
@@ -257,50 +259,66 @@ void
 RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &origin, guint state)
 {
     SPRect *rect = SP_RECT(item);
-    Geom::Point const s = snap_knot_position(p);
+
+    Geom::Point s = p;
 
     if (state & GDK_CONTROL_MASK) {
         // original width/height when drag started
-        gdouble const w_orig = (origin[NR::X] - rect->x.computed);
-        gdouble const h_orig = (origin[NR::Y] - rect->y.computed);
+        gdouble const w_orig = (origin[Geom::X] - rect->x.computed);
+        gdouble const h_orig = (origin[Geom::Y] - rect->y.computed);
 
         //original ratio
-        gdouble const ratio = (w_orig / h_orig);
+        gdouble ratio = (w_orig / h_orig);
 
         // mouse displacement since drag started
-        gdouble const minx = s[NR::X] - origin[NR::X];
-        gdouble const miny = s[NR::Y] - origin[NR::Y];
+        gdouble minx = p[Geom::X] - origin[Geom::X];
+        gdouble miny = p[Geom::Y] - origin[Geom::Y];
 
-        if (fabs(minx) > fabs(miny)) {
+        Geom::Point p_handle(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
 
+        if (fabs(minx) > fabs(miny)) {
             // snap to horizontal or diagonal
-            rect->width.computed = MAX(w_orig + minx, 0);
             if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
                 rect->height.computed = MAX(h_orig + minx / ratio, 0);
             } else {
                 // closer to the horizontal, change only width, height is h_orig
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
                 rect->height.computed = MAX(h_orig, 0);
             }
+            rect->width.computed = MAX(w_orig + minx, 0);
 
         } else {
             // snap to vertical or diagonal
-            rect->height.computed = MAX(h_orig + miny, 0);
             if (miny != 0 && fabs(minx/miny) > 0.5 * ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
                 rect->width.computed = MAX(w_orig + miny * ratio, 0);
             } else {
                 // closer to the vertical, change only height, width is w_orig
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
                 rect->width.computed = MAX(w_orig, 0);
             }
+            rect->height.computed = MAX(h_orig + miny, 0);
+
         }
 
         rect->width._set = rect->height._set = true;
 
     } else {
         // move freely
-        rect->width.computed = MAX(s[NR::X] - rect->x.computed, 0);
-        rect->height.computed = MAX(s[NR::Y] - rect->y.computed, 0);
+        s = snap_knot_position(p);
+        rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0);
+        rect->height.computed = MAX(s[Geom::Y] - rect->y.computed, 0);
         rect->width._set = rect->height._set = true;
     }
 
@@ -334,58 +352,71 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin
     gdouble opposite_y = (rect->y.computed + rect->height.computed);
 
     // original width/height when drag started
-    gdouble w_orig = opposite_x - origin[NR::X];
-    gdouble h_orig = opposite_y - origin[NR::Y];
+    gdouble w_orig = opposite_x - origin[Geom::X];
+    gdouble h_orig = opposite_y - origin[Geom::Y];
 
-    Geom::Point const s = snap_knot_position(p);
+    Geom::Point s = p;
+    Geom::Point p_handle(rect->x.computed, rect->y.computed);
 
     // mouse displacement since drag started
-    gdouble minx = s[NR::X] - origin[NR::X];
-    gdouble miny = s[NR::Y] - origin[NR::Y];
+    gdouble minx = p[Geom::X] - origin[Geom::X];
+    gdouble miny = p[Geom::Y] - origin[Geom::Y];
 
     if (state & GDK_CONTROL_MASK) {
         //original ratio
         gdouble ratio = (w_orig / h_orig);
 
         if (fabs(minx) > fabs(miny)) {
-
             // snap to horizontal or diagonal
-            rect->x.computed = MIN(s[NR::X], opposite_x);
-            rect->width.computed = MAX(w_orig - minx, 0);
             if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-                rect->y.computed = MIN(origin[NR::Y] + minx / ratio, opposite_y);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y);
                 rect->height.computed = MAX(h_orig - minx / ratio, 0);
             } else {
                 // closer to the horizontal, change only width, height is h_orig
-                rect->y.computed = MIN(origin[NR::Y], opposite_y);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->y.computed = MIN(origin[Geom::Y], opposite_y);
                 rect->height.computed = MAX(h_orig, 0);
             }
-
+            rect->x.computed = MIN(s[Geom::X], opposite_x);
+            rect->width.computed = MAX(w_orig - minx, 0);
         } else {
-
             // snap to vertical or diagonal
-            rect->y.computed = MIN(s[NR::Y], opposite_y);
-            rect->height.computed = MAX(h_orig - miny, 0);
             if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-                rect->x.computed = MIN(origin[NR::X] + miny * ratio, opposite_x);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x);
                 rect->width.computed = MAX(w_orig - miny * ratio, 0);
             } else {
                 // closer to the vertical, change only height, width is w_orig
-                rect->x.computed = MIN(origin[NR::X], opposite_x);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->x.computed = MIN(origin[Geom::X], opposite_x);
                 rect->width.computed = MAX(w_orig, 0);
             }
-
+            rect->y.computed = MIN(s[Geom::Y], opposite_y);
+            rect->height.computed = MAX(h_orig - miny, 0);
         }
 
         rect->width._set = rect->height._set = rect->x._set = rect->y._set = true;
 
     } else {
         // move freely
-        rect->x.computed = MIN(s[NR::X], opposite_x);
+        s = snap_knot_position(p);
+        minx = s[Geom::X] - origin[Geom::X];
+        miny = s[Geom::Y] - origin[Geom::Y];
+
+        rect->x.computed = MIN(s[Geom::X], opposite_x);
         rect->width.computed = MAX(w_orig - minx, 0);
-        rect->y.computed = MIN(s[NR::Y], opposite_y);
+        rect->y.computed = MIN(s[Geom::Y], opposite_y);
         rect->height.computed = MAX(h_orig - miny, 0);
         rect->width._set = rect->height._set = rect->x._set = rect->y._set = true;
     }
@@ -413,11 +444,11 @@ RectKnotHolder::RectKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderRel
                         "to make the horizontal radius the same"),
                       SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
     entity_wh->create(desktop, item, this,
-                      _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b>"
+                      _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b> "
                         "to lock ratio or stretch in one dimension only"),
                       SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
     entity_xy->create(desktop, item, this,
-                      _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b>"
+                      _("Adjust the <b>width and height</b> of the rectangle; with <b>Ctrl</b> "
                         "to lock ratio or stretch in one dimension only"),
                       SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
     entity.push_back(entity_rx);
@@ -452,7 +483,7 @@ Box3DKnotHolderEntity::knot_set_generic(SPItem *item, unsigned int knot_id, Geom
 
     g_assert(item != NULL);
     SPBox3D *box = SP_BOX3D(item);
-    NR::Matrix const i2d (from_2geom(sp_item_i2d_affine (item)));
+    Geom::Matrix const i2d (sp_item_i2d_affine (item));
 
     Box3D::Axis movement;
     if ((knot_id < 4) != (state & GDK_SHIFT_MASK)) {
@@ -628,7 +659,7 @@ Box3DKnotHolderEntityCenter::knot_set(Geom::Point const &new_pos, Geom::Point co
     Geom::Point const s = snap_knot_position(new_pos);
 
     SPBox3D *box = SP_BOX3D(item);
-    NR::Matrix const i2d (from_2geom(sp_item_i2d_affine (item)));
+    Geom::Matrix const i2d (sp_item_i2d_affine (item));
 
     box3d_set_center (SP_BOX3D(item), s * i2d, origin * i2d, !(state & GDK_SHIFT_MASK) ? Box3D::XY : Box3D::Z,
                       state & GDK_CONTROL_MASK);
@@ -729,8 +760,8 @@ public:
 static gint
 sp_genericellipse_side(SPGenericEllipse *ellipse, Geom::Point const &p)
 {
-    gdouble dx = (p[NR::X] - ellipse->cx.computed) / ellipse->rx.computed;
-    gdouble dy = (p[NR::Y] - ellipse->cy.computed) / ellipse->ry.computed;
+    gdouble dx = (p[Geom::X] - ellipse->cx.computed) / ellipse->rx.computed;
+    gdouble dy = (p[Geom::Y] - ellipse->cy.computed) / ellipse->ry.computed;
 
     gdouble s = dx * dx + dy * dy;
     if (s < 1.0) return 1;
@@ -741,7 +772,8 @@ sp_genericellipse_side(SPGenericEllipse *ellipse, Geom::Point const &p)
 void
 ArcKnotHolderEntityStart::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
-    int snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
 
     SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
     SPArc *arc = SP_ARC(item);
@@ -749,7 +781,7 @@ ArcKnotHolderEntityStart::knot_set(Geom::Point const &p, Geom::Point const &/*or
     ge->closed = (sp_genericellipse_side(ge, p) == -1) ? TRUE : FALSE;
 
     Geom::Point delta = p - Geom::Point(ge->cx.computed, ge->cy.computed);
-    NR::scale sc(ge->rx.computed, ge->ry.computed);
+    Geom::Scale sc(ge->rx.computed, ge->ry.computed);
     ge->start = atan2(delta * sc.inverse());
     if ( ( state & GDK_CONTROL_MASK )
          && snaps )
@@ -772,7 +804,8 @@ ArcKnotHolderEntityStart::knot_get()
 void
 ArcKnotHolderEntityEnd::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
-    int snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
 
     SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
     SPArc *arc = SP_ARC(item);
@@ -780,7 +813,7 @@ ArcKnotHolderEntityEnd::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     ge->closed = (sp_genericellipse_side(ge, p) == -1) ? TRUE : FALSE;
 
     Geom::Point delta = p - Geom::Point(ge->cx.computed, ge->cy.computed);
-    NR::scale sc(ge->rx.computed, ge->ry.computed);
+    Geom::Scale sc(ge->rx.computed, ge->ry.computed);
     ge->end = atan2(delta * sc.inverse());
     if ( ( state & GDK_CONTROL_MASK )
          && snaps )
@@ -820,7 +853,7 @@ ArcKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origi
 
     Geom::Point const s = snap_knot_position(p);
 
-    ge->rx.computed = fabs( ge->cx.computed - s[NR::X] );
+    ge->rx.computed = fabs( ge->cx.computed - s[Geom::X] );
 
     if ( state & GDK_CONTROL_MASK ) {
         ge->ry.computed = ge->rx.computed;
@@ -855,7 +888,7 @@ ArcKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origi
 
     Geom::Point const s = snap_knot_position(p);
 
-    ge->ry.computed = fabs( ge->cy.computed - s[NR::Y] );
+    ge->ry.computed = fabs( ge->cy.computed - s[Geom::Y] );
 
     if ( state & GDK_CONTROL_MASK ) {
         ge->rx.computed = ge->ry.computed;
@@ -897,7 +930,7 @@ ArcKnotHolder::ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderRelea
                       _("Adjust ellipse <b>height</b>, with <b>Ctrl</b> to make circle"),
                       SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR);
     entity_start->create(desktop, item, this,
-                         _("Position the <b>start point</b> of the arc or segment; with <b>Ctrl</b>"
+                         _("Position the <b>start point</b> of the arc or segment; with <b>Ctrl</b> "
                            "to snap angle; drag <b>inside</b> the ellipse for arc, <b>outside</b> for segment"),
                          SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR);
     entity_end->create(desktop, item, this,
@@ -1078,19 +1111,26 @@ public:
  *   [control] constrain inner arg to round per PI/4
  */
 void
-SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
+SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state)
 {
-    int snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
 
     SPSpiral *spiral = SP_SPIRAL(item);
 
-    gdouble   dx = p[NR::X] - spiral->cx;
-    gdouble   dy = p[NR::Y] - spiral->cy;
+    gdouble   dx = p[Geom::X] - spiral->cx;
+    gdouble   dy = p[Geom::Y] - spiral->cy;
+
+    gdouble   moved_y = p[Geom::Y] - origin[Geom::Y];
 
     if (state & GDK_MOD1_MASK) {
         // adjust divergence by vertical drag, relative to rad
-        double new_exp = (spiral->rad + dy)/(spiral->rad);
-        spiral->exp = new_exp > 0? new_exp : 0;
+        if (spiral->rad > 0) {
+            double exp_delta = 0.1*moved_y/(spiral->rad); // arbitrary multiplier to slow it down
+            spiral->exp += exp_delta;
+            if (spiral->exp < 1e-3)
+                spiral->exp = 1e-3;
+        }
     } else {
         // roll/unroll from inside
         gdouble   arg_t0;
@@ -1122,12 +1162,13 @@ SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &/
 void
 SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
-    int snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
 
     SPSpiral *spiral = SP_SPIRAL(item);
 
-    gdouble  dx = p[NR::X] - spiral->cx;
-    gdouble  dy = p[NR::Y] - spiral->cy;
+    gdouble  dx = p[Geom::X] - spiral->cx;
+    gdouble  dy = p[Geom::Y] - spiral->cy;
 
     if (state & GDK_SHIFT_MASK) { // rotate without roll/unroll
         spiral->arg = atan2(dy, dx) - 2.0*M_PI*spiral->revo;
@@ -1324,4 +1365,4 @@ FlowtextKnotHolder::FlowtextKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotH
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :