X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fseltrans.cpp;h=b1d184986da06c3d2b7248c8a211beea641b5bcc;hb=457ae1f251852ceb19549b16cf82feb4f01d9066;hp=aef608420ac258085a45754a7240a6f7b4b3452d;hpb=d190791228fa8662b1de5a4d67265585c6ea663c;p=inkscape.git diff --git a/src/seltrans.cpp b/src/seltrans.cpp index aef608420..b1d184986 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -6,6 +6,7 @@ * bulia byak * Carl Hetherington * Diederik van Lierop + * Abhishek Sharma * * Copyright (C) 1999-2002 Lauris Kaplinski * Copyright (C) 1999-2008 Authors @@ -45,6 +46,7 @@ #include <2geom/angle.h> #include "display/snap-indicator.h" +using Inkscape::DocumentUndo; static void sp_remove_handles(SPKnot *knot[], gint num); @@ -265,7 +267,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s SPItem *it = (SPItem *)sp_object_ref(SP_OBJECT(l->data), NULL); _items.push_back(it); _items_const.push_back(it); - _items_affines.push_back(sp_item_i2d_affine(it)); + _items_affines.push_back(it->i2d_affine()); _items_centers.push_back(it->getCenter()); // for content-dragging, we need to remember original centers } @@ -289,19 +291,15 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s // Next, get all points to consider for snapping SnapManager const &m = _desktop->namedview->snap_manager; - Inkscape::SnapPreferences local_snapprefs = m.snapprefs; - local_snapprefs.setSnapToItemNode(true); // We should get at least the cusp nodes here. This might - // have been turned off because (for example) the user only want paths as a snap target, not nodes - // but as a snap source we still need some nodes though! _snap_points.clear(); - _snap_points = selection->getSnapPoints(&local_snapprefs); - std::vector snap_points_hull = selection->getSnapPointsConvexHull(&local_snapprefs); + _snap_points = selection->getSnapPoints(&m.snapprefs); + std::vector snap_points_hull = selection->getSnapPointsConvexHull(&m.snapprefs); if (_snap_points.size() > 200) { /* Snapping a huge number of nodes will take way too long, so limit the number of snappable nodes An average user would rarely ever try to snap such a large number of nodes anyway, because (s)he could hardly discern which node would be snapping */ if (prefs->getBool("/options/snapclosestonly/value", false)) { - _keepClosestPointOnly(_snap_points, p); + m.keepClosestPointOnly(_snap_points, p); } else { _snap_points = snap_points_hull; } @@ -337,7 +335,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s // More than 50 items will produce at least 200 bbox points, which might make Inkscape crawl // (see the comment a few lines above). In that case we will use the bbox of the selection as a whole for (unsigned i = 0; i < _items.size(); i++) { - getBBoxPoints(sp_item_bbox_desktop(_items[i], _snap_bbox_type), &_bbox_points_for_translating, false, true, emp, mp); + getBBoxPoints(_items[i]->getBboxDesktop(_snap_bbox_type), &_bbox_points_for_translating, false, true, emp, mp); } } else { _bbox_points_for_translating = _bbox_points; // use the bbox points of the selection as a whole @@ -362,14 +360,14 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s if (prefs->getBool("/options/snapclosestonly/value", false)) { if (m.snapprefs.getSnapModeNode()) { - _keepClosestPointOnly(_snap_points, p); + m.keepClosestPointOnly(_snap_points, p); } else { _snap_points.clear(); // don't keep any point } if (m.snapprefs.getSnapModeBBox()) { - _keepClosestPointOnly(_bbox_points, p); - _keepClosestPointOnly(_bbox_points_for_translating, p); + m.keepClosestPointOnly(_bbox_points, p); + m.keepClosestPointOnly(_bbox_points_for_translating, p); } else { _bbox_points.clear(); // don't keep any point _bbox_points_for_translating.clear(); @@ -405,21 +403,6 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s g_warning("Checking number of snap sources failed; nothing serious, but please report to Diederik"); } - // Optionally, show the snap source - if (!(_state == STATE_ROTATE && x != 0.5 && y != 0.5)) { // but not when we're dragging a rotation handle, because that won't snap - // Now either _bbox_points or _snap_points has a single element, the other one has zero..... or both have zero elements - if ((_snap_points.size() + _bbox_points.size() + _bbox_points_for_translating.size()) > 1) { - g_warning("too many snap sources to display, please fix this"); - } else if (m.snapprefs.getSnapEnabledGlobally()) { - if (_bbox_points.size() == 1) { - _desktop->snapindicator->set_new_snapsource(_bbox_points.at(0)); - } else if (_bbox_points_for_translating.size() == 1) { - _desktop->snapindicator->set_new_snapsource(_bbox_points_for_translating.at(0)); - } else if (_snap_points.size() == 1){ - _desktop->snapindicator->set_new_snapsource(_snap_points.at(0)); - } - } - } } if ((x != -1) && (y != -1)) { @@ -448,7 +431,7 @@ void Inkscape::SelTrans::transform(Geom::Matrix const &rel_affine, Geom::Point c for (unsigned i = 0; i < _items.size(); i++) { SPItem &item = *_items[i]; Geom::Matrix const &prev_transform = _items_affines[i]; - sp_item_set_i2d_affine(&item, prev_transform * affine); + item.set_i2d_affine(prev_transform * affine); } } else { if (_bbox) { @@ -524,17 +507,17 @@ void Inkscape::SelTrans::ungrab() _items_centers.clear(); if (_current_relative_affine.isTranslation()) { - sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Move")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Move")); } else if (_current_relative_affine.without_translation().isScale()) { - sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Scale")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Scale")); } else if (_current_relative_affine.without_translation().isRotation()) { - sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Rotate")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Rotate")); } else { - sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Skew")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Skew")); } } else { @@ -545,8 +528,8 @@ void Inkscape::SelTrans::ungrab() SPItem *it = (SPItem*)SP_OBJECT(l->data); SP_OBJECT(it)->updateRepr(); } - sp_document_done (sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Set center")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Set center")); } _items.clear(); @@ -603,15 +586,15 @@ void Inkscape::SelTrans::stamp() Geom::Matrix const *new_affine; if (_show == SHOW_OUTLINE) { - Geom::Matrix const i2d(sp_item_i2d_affine(original_item)); + Geom::Matrix const i2d(original_item->i2d_affine()); Geom::Matrix const i2dnew( i2d * _current_relative_affine ); - sp_item_set_i2d_affine(copy_item, i2dnew); + copy_item->set_i2d_affine(i2dnew); new_affine = ©_item->transform; } else { new_affine = &original_item->transform; } - sp_item_write_transform(copy_item, copy_repr, *new_affine); + copy_item->doWriteTransform(copy_repr, *new_affine); if ( copy_item->isCenterSet() && _center ) { copy_item->setCenter(*_center * _current_relative_affine); @@ -620,8 +603,8 @@ void Inkscape::SelTrans::stamp() Inkscape::GC::release(copy_repr); l = l->next; } - sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Stamp")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Stamp")); } if ( fixup && _stamp_cache ) { @@ -809,8 +792,8 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa _center_is_set = false; // center has changed _updateHandles(); } - sp_document_done (sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, - _("Reset center")); + DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Reset center")); } break; default: @@ -887,7 +870,11 @@ gboolean Inkscape::SelTrans::handleRequest(SPKnot *knot, Geom::Point *position, if (handle.request(this, handle, *position, state)) { sp_knot_set_position(knot, *position, state); SP_CTRL(_grip)->moveto(*position); - SP_CTRL(_norm)->moveto(_origin); + if (&handle == &handle_center) { + SP_CTRL(_norm)->moveto(*position); + } else { + SP_CTRL(_norm)->moveto(_origin); + } } return TRUE; @@ -1039,6 +1026,7 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) geom_scale = Geom::Scale(sn.getTransformation()); pt = _calcAbsAffineGeom(geom_scale); } + m.unSetup(); } /* Status text */ @@ -1134,6 +1122,8 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom // will have to calculate pt taking the stroke width into account pt = _calcAbsAffineGeom(geom_scale); } + + m.unSetup(); } // status text @@ -1213,7 +1203,7 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop, false, _items_const); - Inkscape::Snapper::ConstraintLine const constraint(component_vectors[dim_b]); + Inkscape::Snapper::SnapConstraint const constraint(component_vectors[dim_b]); // When skewing, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapSkew" for details Geom::Point const s(skew[dim_a], scale[dim_a]); Inkscape::SnappedPoint sn = m.constrainedSnapSkew(_snap_points, _point, constraint, s, _origin, Geom::Dim2(dim_b)); @@ -1226,6 +1216,8 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P } else { _desktop->snapindicator->remove_snaptarget(); } + + m.unSetup(); } // Update the handle position @@ -1280,7 +1272,10 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state) if (fabs(h2) < 1e-15) return FALSE; Geom::Point q2 = d2 / h2; // normalized new vector to handle - double radians; + Geom::Rotate r1(q1); + Geom::Rotate r2(q2); + + double radians = atan2(Geom::dot(Geom::rot90(d1), d2), Geom::dot(d1, d2));; if (state & GDK_CONTROL_MASK) { // Snap to defined angle increments double cos_t = Geom::dot(q1, q2); @@ -1289,15 +1284,27 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state) if (snaps) { radians = ( M_PI / snaps ) * floor( radians * snaps / M_PI + .5 ); } - q1 = Geom::Point(1, 0); - q2 = Geom::Point(cos(radians), sin(radians)); + r1 = Geom::Rotate(0); //q1 = Geom::Point(1, 0); + r2 = Geom::Rotate(radians); //q2 = Geom::Point(cos(radians), sin(radians)); } else { - radians = atan2(Geom::dot(Geom::rot90(d1), d2), - Geom::dot(d1, d2)); + SnapManager &m = _desktop->namedview->snap_manager; + m.setup(_desktop, false, _items_const); + // When rotating, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapRotate" for details + Inkscape::SnappedPoint sn = m.constrainedSnapRotate(_snap_points, _point, radians, _origin); + m.unSetup(); + + if (sn.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn); + // We snapped something, so change the rotation to reflect it + radians = sn.getTransformation()[0]; + r1 = Geom::Rotate(0); + r2 = Geom::Rotate(radians); + } else { + _desktop->snapindicator->remove_snaptarget(); + } + } - Geom::Rotate const r1(q1); - Geom::Rotate const r2(q2); // Calculate the relative affine _relative_affine = r2 * r1.inverse(); @@ -1318,36 +1325,29 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state) // Move the item's transformation center gboolean Inkscape::SelTrans::centerRequest(Geom::Point &pt, guint state) { + // When dragging the transformation center while multiple items have been selected, then those + // items will share a single center. While dragging that single center, it should never snap to the + // centers of any of the selected objects. Therefore we will have to pass the list of selected items + // to the snapper, to avoid self-snapping of the rotation center + GSList *items = (GSList *) const_cast(_selection)->itemList(); SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop); - m.freeSnapReturnByRef(pt, Inkscape::SNAPSOURCE_OTHER_HANDLE); - - if (state & GDK_CONTROL_MASK) { - if ( fabs(_point[Geom::X] - pt[Geom::X]) > fabs(_point[Geom::Y] - pt[Geom::Y]) ) { - pt[Geom::Y] = _point[Geom::Y]; - } else { - pt[Geom::X] = _point[Geom::X]; + m.setRotationCenterSource(items); + + if (state & GDK_CONTROL_MASK) { // with Ctrl, constrain to axes + std::vector constraints; + constraints.push_back(Inkscape::Snapper::SnapConstraint(_point, Geom::Point(1, 0))); + constraints.push_back(Inkscape::Snapper::SnapConstraint(_point, Geom::Point(0, 1))); + Inkscape::SnappedPoint sp = m.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_ROTATION_CENTER), constraints, state & GDK_SHIFT_MASK); + pt = sp.getPoint(); + } + else { + if (!(state & GDK_SHIFT_MASK)) { // Shift disables snapping + m.freeSnapReturnByRef(pt, Inkscape::SNAPSOURCE_ROTATION_CENTER); } } - if ( !(state & GDK_SHIFT_MASK) && _bbox ) { - // screen pixels to snap center to bbox -#define SNAP_DIST 5 - // FIXME: take from prefs - double snap_dist = SNAP_DIST / _desktop->current_zoom(); - - for (int i = 0; i < 2; i++) { - if (fabs(pt[i] - _bbox->min()[i]) < snap_dist) { - pt[i] = _bbox->min()[i]; - } - if (fabs(pt[i] - _bbox->midpoint()[i]) < snap_dist) { - pt[i] = _bbox->midpoint()[i]; - } - if (fabs(pt[i] - _bbox->max()[i]) < snap_dist) { - pt[i] = _bbox->max()[i]; - } - } - } + m.unSetup(); // status text GString *xs = SP_PX_TO_METRIC_STRING(pt[Geom::X], _desktop->namedview->getDefaultMetric()); @@ -1434,6 +1434,7 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) } m.setup(_desktop, true, _items_const); dxy = m.multipleOfGridPitch(dxy, _point); + m.unSetup(); } else if (shift) { if (control) { // shift & control: constrained movement without snapping if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) { @@ -1464,14 +1465,14 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) // the constraint-line once. The constraint lines are parallel, but might not be colinear. // Therefore we will have to set the point through which the constraint-line runs // individually for each point to be snapped; this will be handled however by _snapTransformed() - s.push_back(m.constrainedSnapTranslation(_bbox_points_for_translating, + s.push_back(m.constrainedSnapTranslate(_bbox_points_for_translating, _point, - Inkscape::Snapper::ConstraintLine(component_vectors[dim]), + Inkscape::Snapper::SnapConstraint(component_vectors[dim]), dxy)); - s.push_back(m.constrainedSnapTranslation(_snap_points, + s.push_back(m.constrainedSnapTranslate(_snap_points, _point, - Inkscape::Snapper::ConstraintLine(component_vectors[dim]), + Inkscape::Snapper::SnapConstraint(component_vectors[dim]), dxy)); } else { // !control @@ -1481,13 +1482,14 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) g_get_current_time(&starttime); */ /* Snap to things with no constraint */ - s.push_back(m.freeSnapTranslation(_bbox_points_for_translating, _point, dxy)); - s.push_back(m.freeSnapTranslation(_snap_points, _point, dxy)); + s.push_back(m.freeSnapTranslate(_bbox_points_for_translating, _point, dxy)); + s.push_back(m.freeSnapTranslate(_snap_points, _point, dxy)); /*g_get_current_time(&endtime); double elapsed = ((((double)endtime.tv_sec - starttime.tv_sec) * G_USEC_PER_SEC + (endtime.tv_usec - starttime.tv_usec))) / 1000.0; std::cout << "Time spent snapping: " << elapsed << std::endl; */ } + m.unSetup(); /* Pick one */ Inkscape::SnappedPoint best_snapped_point; @@ -1508,7 +1510,7 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) if (control) { // If we didn't snap, then we should still constrain horizontally or vertically // (When we did snap, then this constraint has already been enforced by - // calling constrainedSnapTranslation() above) + // calling constrainedSnapTranslate() above) if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) { dxy[Geom::Y] = 0; } else { @@ -1630,25 +1632,6 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale) return _calcAbsAffineDefault(geom_scale); // this is bogus, but we must return _something_ } -void Inkscape::SelTrans::_keepClosestPointOnly(std::vector &points, const Geom::Point &reference) -{ - if (points.size() < 2) return; - - Inkscape::SnapCandidatePoint closest_point = Inkscape::SnapCandidatePoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED); - Geom::Coord closest_dist = NR_HUGE; - - for(std::vector::const_iterator i = points.begin(); i != points.end(); i++) { - Geom::Coord dist = Geom::L2((*i).getPoint() - reference); - if (i == points.begin() || dist < closest_dist) { - closest_point = *i; - closest_dist = dist; - } - } - - points.clear(); - points.push_back(closest_point); -} - /* Local Variables: mode:c++ @@ -1658,4 +1641,4 @@ void Inkscape::SelTrans::_keepClosestPointOnly(std::vector