diff options
Diffstat (limited to 'src')
45 files changed, 351 insertions, 196 deletions
diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index 5d3ca7a6c..2388390b9 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -70,8 +70,6 @@ set(2geom_SRC conic_section_clipper_cr.h conic_section_clipper_impl.h conicsec.h - conjugate_gradient.h - convex-cover.h coord.h crossing.h curve.h @@ -85,7 +83,6 @@ set(2geom_SRC generic-interval.h generic-rect.h geom.h - hvlinesegment.h int-interval.h int-point.h int-rect.h @@ -93,21 +90,17 @@ set(2geom_SRC line.h linear.h math-utils.h - nearest-point.h ord.h path-intersection.h path-sink.h path.h pathvector.h piecewise.h - point-ops.h point.h pointwise.h polynomial.h ray.h rect.h - region.h - satellite.h sbasis-2d.h sbasis-curve.h sbasis-geometric.h @@ -115,7 +108,6 @@ set(2geom_SRC sbasis-poly.h sbasis-to-bezier.h sbasis.h - shape.h solver.h svg-path-parser.h svg-path-writer.h diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp index 3b36137be..089db71a4 100644 --- a/src/2geom/conicsec.cpp +++ b/src/2geom/conicsec.cpp @@ -1337,6 +1337,7 @@ bool xAx::decompose (Line& l1, Line& l2) const */ Rect xAx::arc_bound (const Point & P1, const Point & Q, const Point & P2) const { + using std::swap; //std::cout << "BOUND: P1 = " << P1 << std::endl; //std::cout << "BOUND: Q = " << Q << std::endl; //std::cout << "BOUND: P2 = " << P2 << std::endl; diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 0264ab4ae..4b5ad9762 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -205,22 +205,50 @@ Ellipse::arc(Point const &ip, Point const &inner, Point const &fp) bool sweep_flag = false; // Determination of large arc flag: - // The arc is larger than half of the ellipse if the inner point - // is on the same side of the line going from the initial - // to the final point as the center of the ellipse - Point versor = fp - ip; - double sdist_c = cross(versor, _center - ip); - double sdist_inner = cross(versor, inner - ip); - - // if we have exactly half of an arc, do not set the large flag. - if (sdist_c != 0 && sgn(sdist_c) == sgn(sdist_inner)) { + // large_arc is false when the inner point is on the same side + // of the center---initial point line as the final point, AND + // is on the same side of the center---final point line as the + // initial point. + // Additionally, large_arc is always false when we have exactly + // 1/2 of an arc, i.e. the cross product of the center -> initial point + // and center -> final point vectors is zero. + // Negating the above leads to the condition for large_arc being true. + Point fv = fp - _center; + Point iv = ip - _center; + Point innerv = inner - _center; + double ifcp = cross(fv, iv); + + if (ifcp != 0 && (sgn(cross(fv, innerv)) != sgn(ifcp) || + sgn(cross(iv, innerv)) != sgn(-ifcp))) + { large_arc_flag = true; } + //cross(-iv, fv) && large_arc_flag + + // Determination of sweep flag: - // If the inner point is on the left side of the ip-fp line, - // we go in clockwise direction. - if (sdist_inner < 0) { + // For clarity, let's assume that Y grows up. Then the cross product + // is positive for points on the left side of a vector and negative + // on the right side of a vector. + // + // cross(?, v) > 0 + // o-------------------> + // cross(?, v) < 0 + // + // If the arc is small (large_arc_flag is false) and the final point + // is on the right side of the vector initial point -> center, + // we have to go in the direction of increasing angles + // (counter-clockwise) and the sweep flag is true. + // If the arc is large, the opposite is true, since we have to reach + // the final point going the long way - in the other direction. + // We can express this observation as: + // cross(_center - ip, fp - _center) < 0 xor large_arc flag + // This is equal to: + // cross(-iv, fv) < 0 xor large_arc flag + // But cross(-iv, fv) is equal to cross(fv, iv) due to antisymmetry + // of the cross product, so we end up with the condition below. + if ((ifcp < 0) ^ large_arc_flag) { sweep_flag = true; } @@ -499,7 +527,7 @@ std::vector<ShapeIntersection> Ellipse::intersect(Ellipse const &other) const Line lines[2]; if (aa != 0) { - bb /= aa; cc /= aa; dd /= aa; ee /= aa; ff /= aa; + bb /= aa; cc /= aa; dd /= aa; ee /= aa; /*ff /= aa;*/ Coord s = (ee + std::sqrt(ee*ee - 4*bb)) / 2; Coord q = ee - s; Coord alpha = (dd - cc*q) / (s - q); @@ -508,7 +536,7 @@ std::vector<ShapeIntersection> Ellipse::intersect(Ellipse const &other) const lines[0] = Line(1, q, alpha); lines[1] = Line(1, s, beta); } else if (bb != 0) { - cc /= bb; dd /= bb; ee /= bb; ff /= bb; + cc /= bb; /*dd /= bb;*/ ee /= bb; ff /= bb; Coord s = ee; Coord q = 0; Coord alpha = cc / ee; diff --git a/src/2geom/nearest-time.cpp b/src/2geom/nearest-time.cpp index 0b21e51a2..103921021 100644 --- a/src/2geom/nearest-time.cpp +++ b/src/2geom/nearest-time.cpp @@ -80,7 +80,7 @@ Coord nearest_time(Point const &p, D2<Bezier> const &input, Coord from, Coord to t = 0; } if (dfinal < mind) { - mind = dfinal; + //mind = dfinal; t = 1; } diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 836e65013..871441751 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -441,7 +441,6 @@ std::vector<PathTime> Path::roots(Coord v, Dim2 d) const // The class below implements sweepline optimization for curve intersection in paths. // Instead of O(N^2), this takes O(N + X), where X is the number of overlaps // between the bounding boxes of curves. -namespace { struct CurveSweepTraits { struct Bound { @@ -512,8 +511,6 @@ private: Coord _precision; }; -} // end anonymous namespace - std::vector<PathIntersection> Path::intersect(Path const &other, Coord precision) const { std::vector<PathIntersection> result; diff --git a/src/2geom/point.h b/src/2geom/point.h index f2659d351..a66e64647 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -386,7 +386,9 @@ inline Coord distanceSq (Point const &a, Point const &b) { /// Test whether two points are no further apart than some threshold. /// @relates Point inline bool are_near(Point const &a, Point const &b, double eps = EPSILON) { - return are_near(distance(a, b), 0, eps); + // do not use an unqualified calls to distance before the empty + // specialization of iterator_traits is defined - see end of file + return are_near((a - b).length(), 0, eps); } /// Test whether three points lie approximately on the same line. diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp index 4f1df621e..42d92d7b8 100644 --- a/src/2geom/sbasis.cpp +++ b/src/2geom/sbasis.cpp @@ -328,9 +328,9 @@ SBasis derivative(SBasis const &a) { } int k = a.size()-1; double d = (2*k+1)*(a[k][1] - a[k][0]); - if(d == 0) + if (d == 0 && k > 0) { c.pop_back(); - else { + } else { c[k][0] = d; c[k][1] = d; } @@ -351,9 +351,9 @@ void SBasis::derive() { // in place version } int k = size()-1; double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]); - if(d == 0) + if (d == 0 && k > 0) { pop_back(); - else { + } else { (*this)[k][0] = d; (*this)[k][1] = d; } diff --git a/src/2geom/sync.sh b/src/2geom/sync.sh new file mode 100755 index 000000000..a2c162903 --- /dev/null +++ b/src/2geom/sync.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +function usage { + echo "2Geom sync to upstream script" + echo "Usage: $0 path/to/2geom/checkout/dir" +} + +if [ "x$(which rsync)" = "x" ]; then + echo "rsync not found on your system, please install it" + exit 1 +fi + +if [ "x$1" = "x" ]; then + usage $0 + exit 64 +fi +if [ ! -d "$1" ]; then + usage $0 + exit 64 +fi +if [ ! -f "$1/src/2geom/path.h" ]; then + usage $0 + exit 64 +fi + +INK_2GEOM="$(dirname $0)/" +UPSTREAM_2GEOM="$1/src/2geom/" +rsync -r --existing \ + --exclude CMakeLists.txt --exclude sync.sh \ + "$UPSTREAM_2GEOM" "$INK_2GEOM" diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 386c63166..3024d1276 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -203,8 +203,9 @@ SPCurve::moveto(double x, double y) void SPCurve::moveto(Geom::Point const &p) { - _pathv.push_back( Geom::Path() ); // for some reason Geom::Path(p) does not work... - _pathv.back().start(p); + Geom::Path path(p); + path.setStitching(true); + _pathv.push_back(path); } /** diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index 926b35599..17deea16d 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -256,7 +256,12 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap "shape", SP_KNOT_SHAPE_CROSS, NULL ); - const int timeout_val = 4000; + double timeout_val = prefs->getDouble("/options/snapindicatorpersistence/value", 2.0); + if (timeout_val < 0.1) { + timeout_val = 0.1; // a zero value would mean infinite persistence (i.e. until new snap occurs) + // Besides, negatives values would ....? + } + // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose // will be called. This will set canvas->current_item to NULL if the snap indicator was @@ -272,7 +277,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap SP_CTRL(canvasitem)->pickable = false; SP_CTRL(canvasitem)->moveto(p.getPoint()); - _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val); + _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val*1000.0); _snaptarget_is_presnap = pre_snap; // Display the tooltip, which reveals the type of snap source and the type of snap target @@ -307,7 +312,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap SP_CANVASTEXT(canvas_tooltip)->anchor_position = TEXT_ANCHOR_CENTER; g_free(tooltip_str); - _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val); + _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val*1000.0); } // Display the bounding box, if we snapped to one diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 1026f51ad..5933dd526 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -409,7 +409,8 @@ Flowing in rectangle is possible, not in arb shape. return; // don't know how to handle non-rect frames yet. is quite uncommon for latex users i think } - Geom::Rect framebox = frame->getRect() * transform(); + // We will transform the coordinates + Geom::Rect framebox = frame->getRect(); // get position and alignment // Align on topleft corner. @@ -429,7 +430,10 @@ Flowing in rectangle is possible, not in arb shape. // no need to add LaTeX code for standard justified output :) break; } - Geom::Point pos(framebox.corner(3)); //topleft corner + + // The topleft Corner was calculated after rotating the text which results in a wrong Coordinate. + // Now, the topleft Corner is rotated after calculating it + Geom::Point pos(framebox.corner(0) * transform()); //topleft corner // determine color and transparency (for now, use rgb color model as it is most native to Inkscape) bool has_color = false; // if the item has no color set, don't force black color @@ -472,7 +476,9 @@ Flowing in rectangle is possible, not in arb shape. os << "\\rotatebox{" << degrees << "}{"; } os << "\\makebox(0,0)" << alignment << "{"; - os << "\\begin{minipage}{" << framebox.width() << "\\unitlength}"; + + // Scale the x width correctly + os << "\\begin{minipage}{" << framebox.width() * transform().expansionX() << "\\unitlength}"; os << justification; // Walk through all spans in the text object. diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index e1038b03a..c73a9e9e7 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -1,7 +1,8 @@ -/* Author: +/* Authors: * Liam P. White + * Tavmjong Bah * - * Copyright (C) 2014-2015 Author + * Copyright (C) 2014-2015 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -60,14 +61,14 @@ namespace { // Internal data structure -struct join_data -{ +struct join_data { join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width) - : res(_res), outgoing(_outgoing), in_tang(_in_tang) - , out_tang(_out_tang), miter(_miter), width(_width) {} + : res(_res), outgoing(_outgoing), in_tang(_in_tang), out_tang(_out_tang), miter(_miter), width(_width) {}; - // I/O + // contains the current path that is being built on Geom::Path &res; + + // contains the next curve to append Geom::Path const& outgoing; // input tangents @@ -382,47 +383,6 @@ void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve cons tang[0] = tang1, tang[1] = tang2; } -void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) -{ - if (res.size() == 0 || temp.size() == 0) - return; - - Geom::Curve const& outgoing = temp.front(); - if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { - // if the points are /that/ close, just ignore this one - res.setFinal(temp.initialPoint()); - res.append(temp); - return; - } - - join_data jd(res, temp, in_tang, out_tang, miter, width); - - bool on_outside = (Geom::cross(in_tang, out_tang) > 0); - - if (on_outside) { - join_func *jf; - switch (join) { - case Inkscape::JOIN_BEVEL: - jf = &bevel_join; - break; - case Inkscape::JOIN_ROUND: - jf = &round_join; - break; - case Inkscape::JOIN_EXTRAPOLATE: - jf = &extrapolate_join; - break; - case Inkscape::JOIN_MITER_CLIP: - jf = &miter_clip_join; - break; - default: - jf = &miter_join; - } - jf(jd); - } else { - join_inside(jd); - } -} - // Offsetting a line segment is mathematically stable and quick to do Geom::LineSegment offset_line(Geom::LineSegment const& l, double width) { @@ -687,7 +647,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin const size_t k = (input.back_closed().isDegenerate() && input.closed()) ?input.size_default()-1:input.size_default(); for (size_t u = 0; u < k; u += 2) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u], width); @@ -696,27 +656,27 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin res.append(temp); } else { tangents(tang, input[u-1], input[u]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths if (u < k - 1) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u+1], width); tangents(tang, input[u], input[u+1]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } } if (input.closed()) { Geom::Curve const &c1 = res.back(); Geom::Curve const &c2 = res.front(); - temp = Geom::Path(); + temp.clear(); temp.append(c1); Geom::Path temp2; temp2.append(c2); tangents(tang, input.back(), input.front()); - outline_helper(temp, temp2, tang[0], tang[1], width, miter, join); + outline_join(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // @@ -727,6 +687,47 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin return res; } +void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) +{ + if (res.size() == 0 || temp.size() == 0) + return; + + Geom::Curve const& outgoing = temp.front(); + if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { + // if the points are /that/ close, just ignore this one + res.setFinal(temp.initialPoint()); + res.append(temp); + return; + } + + join_data jd(res, temp, in_tang, out_tang, miter, width); + + bool on_outside = (Geom::cross(in_tang, out_tang) > 0); + + if (on_outside) { + join_func *jf; + switch (join) { + case Inkscape::JOIN_BEVEL: + jf = &bevel_join; + break; + case Inkscape::JOIN_ROUND: + jf = &round_join; + break; + case Inkscape::JOIN_EXTRAPOLATE: + jf = &extrapolate_join; + break; + case Inkscape::JOIN_MITER_CLIP: + jf = &miter_clip_join; + break; + default: + jf = &miter_join; + } + jf(jd); + } else { + join_inside(jd); + } +} + } // namespace Inkscape /* diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h index 0cfb9f817..6697273cf 100644 --- a/src/helper/geom-pathstroke.h +++ b/src/helper/geom-pathstroke.h @@ -1,10 +1,11 @@ #ifndef INKSCAPE_HELPER_PATH_STROKE_H #define INKSCAPE_HELPER_PATH_STROKE_H -/* Author: +/* Authors: * Liam P. White + * Tavmjong Bah * - * Copyright (C) 2014-2015 Author + * Copyright (C) 2014-2015 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -26,21 +27,54 @@ enum LineCapType { BUTT_FLAT, BUTT_ROUND, BUTT_SQUARE, - BUTT_PEAK, // ? + BUTT_PEAK, // This is not a line ending supported by the SVG standard. }; /** + * Strokes the path given by @a input. + * Joins may behave oddly if the width is negative. + * + * @param[in] input Input path. + * @param[in] width Stroke width. + * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. + * @param[in] join Line join type used during offset. Member of LineJoinType enum. + * @param[in] cap Line cap type used during stroking. Member of LineCapType enum. + * + * @return Stroked path. + * If the input path is closed, the resultant vector will contain two paths. + * Otherwise, there should be only one in the output. + */ +Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); + +/** * Offset the input path by @a width. * Joins may behave oddly if the width is negative. * - * @param input - * @param width Amount to offset. - * @param miter Miter limit. Only used with JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. - * @param join + * @param[in] input Input path. + * @param[in] width Amount to offset. + * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. + * @param[in] join Line join type used during offset. Member of LineJoinType enum. + * + * @return Offsetted output. */ Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL); -Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); +/** + * Builds a join on the provided path. + * Joins may behave oddly if the width is negative. + * + * @param[inout] res The path to build the join on. + * The outgoing path (or a portion thereof) will be appended after the join is created. + * Previous segments may be modified as an optimization, beware! + * + * @param[in] outgoing The segment to append on the outgoing portion of the join. + * @param[in] in_tang The end tangent to consider on the input path. + * @param[in] out_tang The begin tangent to consider on the output path. + * @param[in] width + * @param[in] miter + * @param[in] join + */ +void outline_join(Geom::Path &res, Geom::Path const& outgoing, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, LineJoinType join); } // namespace Inkscape diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index a5bb1741c..ab7ba6b4e 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -3,7 +3,6 @@ set(live_effects_SRC lpe-angle_bisector.cpp lpe-attach-path.cpp lpe-bendpath.cpp - lpe-boolops.cpp lpe-bounding-box.cpp lpe-bspline.cpp lpe-circle_3pts.cpp @@ -81,7 +80,6 @@ set(live_effects_SRC lpe-angle_bisector.h lpe-attach-path.h lpe-bendpath.h - lpe-boolops.h lpe-bounding-box.h lpe-bspline.h lpe-circle_3pts.h diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 6ce912bcb..f90d67d4e 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -49,7 +49,7 @@ static boost::optional<Point> intersection_point( Point const & origin_a, Point { Coord denom = cross(vector_a, vector_b); if (!are_near(denom,0.)){ - Coord t = (cross(origin_b, vector_a) + cross(origin_b, vector_b)) / denom; + Coord t = (cross(vector_b, origin_a) + cross(origin_b, vector_b)) / denom; return origin_a + t * vector_a; } return boost::none; diff --git a/src/live_effects/lpeobject-reference.cpp b/src/live_effects/lpeobject-reference.cpp index 573c8a2fd..d9de6e77f 100644 --- a/src/live_effects/lpeobject-reference.cpp +++ b/src/live_effects/lpeobject-reference.cpp @@ -43,14 +43,7 @@ LPEObjectReference::~LPEObjectReference(void) bool LPEObjectReference::_acceptObject(SPObject * const obj) const { if (IS_LIVEPATHEFFECT(obj)) { - SPObject * const owner = getOwner(); - /* Refuse references to us or to an ancestor. */ - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/live_effects/parameter/path-reference.cpp b/src/live_effects/parameter/path-reference.cpp index a76fb1b32..42589b050 100644 --- a/src/live_effects/parameter/path-reference.cpp +++ b/src/live_effects/parameter/path-reference.cpp @@ -22,7 +22,7 @@ bool PathReference::_acceptObject(SPObject * const obj) const return false; } // TODO: check whether the referred path has this LPE applied, if so: deny deny deny! - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/live_effects/spiro-converters.cpp b/src/live_effects/spiro-converters.cpp index 3c7bdf99e..f116d5256 100644 --- a/src/live_effects/spiro-converters.cpp +++ b/src/live_effects/spiro-converters.cpp @@ -64,7 +64,11 @@ ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, }
-
+ConverterPath::ConverterPath(Geom::Path &path)
+ : _path(path)
+{
+ _path.setStitching(true);
+}
void
ConverterPath::moveto(double x, double y, bool is_open)
diff --git a/src/live_effects/spiro-converters.h b/src/live_effects/spiro-converters.h index 83f6ebbc3..90855d2d6 100644 --- a/src/live_effects/spiro-converters.h +++ b/src/live_effects/spiro-converters.h @@ -25,7 +25,7 @@ class ConverterSPCurve : public ConverterBase { public: ConverterSPCurve(SPCurve &curve) : _curve(curve) - {} ; + {} virtual void moveto(double x, double y, bool is_open); virtual void lineto(double x, double y); @@ -45,9 +45,7 @@ private: */ class ConverterPath : public ConverterBase { public: - ConverterPath(Geom::Path &path) - : _path(path) - {} ; + ConverterPath(Geom::Path &path); virtual void moveto(double x, double y, bool is_open); virtual void lineto(double x, double y); diff --git a/src/live_effects/spiro.h b/src/live_effects/spiro.h index 0d85da74b..066b44ca8 100644 --- a/src/live_effects/spiro.h +++ b/src/live_effects/spiro.h @@ -25,11 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #define INKSCAPE_SPIRO_H #include "live_effects/spiro-converters.h" +#include <2geom/forward.h> class SPCurve; -namespace Geom { - class Path; -} namespace Spiro { @@ -53,4 +51,4 @@ double get_knot_th(const spiro_seg *s, int i); } // namespace Spiro -#endif // INKSCAPE_SPIRO_H
\ No newline at end of file +#endif // INKSCAPE_SPIRO_H diff --git a/src/persp3d-reference.cpp b/src/persp3d-reference.cpp index 895eac6f2..4526a8d8f 100644 --- a/src/persp3d-reference.cpp +++ b/src/persp3d-reference.cpp @@ -35,7 +35,8 @@ Persp3DReference::~Persp3DReference(void) bool Persp3DReference::_acceptObject(SPObject *obj) const { - return SP_IS_PERSP3D(obj); + return SP_IS_PERSP3D(obj) && URIReference::_acceptObject(obj); +; /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-clippath.h b/src/sp-clippath.h index 91dcfd625..c9a8c68df 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -88,7 +88,7 @@ protected: return false; } SPObject * const owner = this->getOwner(); - if (obj->isAncestorOf(owner)) { + if (!URIReference::_acceptObject(obj)) { //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... diff --git a/src/sp-filter-reference.cpp b/src/sp-filter-reference.cpp index 57600ad39..afb014820 100644 --- a/src/sp-filter-reference.cpp +++ b/src/sp-filter-reference.cpp @@ -4,7 +4,7 @@ bool SPFilterReference::_acceptObject(SPObject *obj) const { - return SP_IS_FILTER(obj); + return SP_IS_FILTER(obj) && URIReference::_acceptObject(obj); /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-gradient-reference.cpp b/src/sp-gradient-reference.cpp index d2b8128fb..216ac73de 100644 --- a/src/sp-gradient-reference.cpp +++ b/src/sp-gradient-reference.cpp @@ -4,7 +4,7 @@ bool SPGradientReference::_acceptObject(SPObject *obj) const { - return SP_IS_GRADIENT(obj); + return SP_IS_GRADIENT(obj) && URIReference::_acceptObject(obj); /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-hatch.h b/src/sp-hatch.h index 5004a611f..546f06a1e 100644 --- a/src/sp-hatch.h +++ b/src/sp-hatch.h @@ -168,7 +168,7 @@ public: protected: virtual bool _acceptObject(SPObject *obj) const { - return dynamic_cast<SPHatch *>(obj) != NULL; + return dynamic_cast<SPHatch *>(obj) != NULL && URIReference::_acceptObject(obj); } }; diff --git a/src/sp-marker.h b/src/sp-marker.h index 56cbaf94f..bae13243b 100644 --- a/src/sp-marker.h +++ b/src/sp-marker.h @@ -92,7 +92,7 @@ class SPMarkerReference : public Inkscape::URIReference { } protected: virtual bool _acceptObject(SPObject *obj) const { - return SP_IS_MARKER(obj); + return SP_IS_MARKER(obj) && URIReference::_acceptObject(obj); } }; diff --git a/src/sp-mask.h b/src/sp-mask.h index 3559483bb..74bd4d66e 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -81,7 +81,7 @@ protected: return false; } SPObject * const owner = this->getOwner(); - if (obj->isAncestorOf(owner)) { + if (!URIReference::_acceptObject(obj)) { //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 0bb8c240f..db66eb3e6 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -721,6 +721,9 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns } this->cloned = cloned; + /* Invoke derived methods, if any */ + this->build(document, repr); + if ( !cloned ) { this->document->bindObjectToRepr(this->repr, this); @@ -754,8 +757,6 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns g_assert(this->getId() == NULL); } - /* Invoke derived methods, if any */ - this->build(document, repr); /* Signalling (should be connected AFTER processing derived methods */ sp_repr_add_listener(repr, &object_event_vector, this); diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index ae40ad1aa..c3416c6c8 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -27,7 +27,7 @@ SPPaintServer *SPPaintServerReference::getObject() const bool SPPaintServerReference::_acceptObject(SPObject *obj) const { - return SP_IS_PAINT_SERVER(obj); + return SP_IS_PAINT_SERVER(obj) && URIReference::_acceptObject(obj); } SPPaintServer::SPPaintServer() : SPObject() { diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 145bb934e..a5e7be1d4 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -129,9 +129,8 @@ public: } protected: - virtual bool _acceptObject(SPObject *obj) const - { - return SP_IS_PATTERN(obj); + virtual bool _acceptObject(SPObject *obj) const { + return SP_IS_PATTERN (obj)&& URIReference::_acceptObject(obj); } }; diff --git a/src/sp-tag-use-reference.cpp b/src/sp-tag-use-reference.cpp index 220cd16d1..9fcb31fd1 100644 --- a/src/sp-tag-use-reference.cpp +++ b/src/sp-tag-use-reference.cpp @@ -24,14 +24,7 @@ bool SPTagUseReference::_acceptObject(SPObject * const obj) const { if (SP_IS_ITEM(obj)) { - SPObject * const owner = getOwner(); - // Refuse references to us or to an ancestor. - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/sp-tref-reference.cpp b/src/sp-tref-reference.cpp index e82f575e0..7c6ff00e7 100644 --- a/src/sp-tref-reference.cpp +++ b/src/sp-tref-reference.cpp @@ -21,7 +21,7 @@ bool SPTRefReference::_acceptObject(SPObject * const obj) const { SPObject *owner = getOwner(); if (SP_IS_TREF(owner)) - return sp_tref_reference_allowed(SP_TREF(getOwner()), obj); + return URIReference::_acceptObject(obj); else return false; } diff --git a/src/sp-use-reference.cpp b/src/sp-use-reference.cpp index 642cfede8..f0b2985d2 100644 --- a/src/sp-use-reference.cpp +++ b/src/sp-use-reference.cpp @@ -25,18 +25,7 @@ bool SPUseReference::_acceptObject(SPObject * const obj) const { - if (SP_IS_ITEM(obj)) { - SPObject * const owner = getOwner(); - // Refuse references to us or to an ancestor. - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; - } else { - return false; - } + return URIReference::_acceptObject(obj); } diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 384aec415..1edfdfe80 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -945,17 +945,19 @@ Gtk::Dialog * Export::create_progress_dialog (Glib::ustring progress_text) { Glib::ustring Export::filename_add_extension (Glib::ustring filename, Glib::ustring extension) { Glib::ustring::size_type dot; + Glib::ustring::size_type dot_ext; dot = filename.find_last_of("."); - if ( !dot ) + dot_ext = filename.lowercase().rfind("." + extension.lowercase()); + if ( dot == std::string::npos ) { return filename = filename + "." + extension; } else { - if (dot==filename.find_last_of(Glib::ustring::compose(".", extension))) + if (dot == dot_ext) { - return filename; + return filename = filename; } else { diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index c44f66a4d..ccd23a572 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -311,7 +311,7 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h GSList *current_row = NULL; col_cnt = 0; - for(;it!=sorted.end()&&col<NoOfCols;it++) { + for(;it!=sorted.end()&&col_cnt<NoOfCols;it++) { current_row = g_slist_append (current_row, *it); col_cnt++; } diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 3b0731953..98695e080 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -1229,26 +1229,38 @@ void InkscapePreferences::initPageBehavior() this->AddPage(_page_scrolling, _("Scrolling"), iter_behavior, PREFS_PAGE_BEHAVIOR_SCROLLING); // Snapping options + _page_snapping.add_group_header( _("Snap indicator")); + _snap_indicator.init( _("Enable snap indicator"), "/options/snapindicator/value", true); - _page_snapping.add_line( false, "", _snap_indicator, "", + _page_snapping.add_line( true, "", _snap_indicator, "", _("After snapping, a symbol is drawn at the point that has snapped")); - _snap_delay.init("/options/snapdelay/value", 0, 1000, 50, 100, 300, 0); - _page_snapping.add_line( false, _("_Delay (in ms):"), _snap_delay, "", - _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true); + _snap_indicator.changed_signal.connect( sigc::mem_fun(_snap_persistence, &Gtk::Widget::set_sensitive) ); + + _snap_persistence.init("/options/snapindicatorpersistence/value", 0.1, 10, 0.1, 1, 2, 1); + _page_snapping.add_line( true, _("Snap indicator persistence (in seconds):"), _snap_persistence, "", + _("Controls how long the snap indicator message will be shown, before it disappears"), true); + + _page_snapping.add_group_header( _("What should snap")); _snap_closest_only.init( _("Only snap the node closest to the pointer"), "/options/snapclosestonly/value", false); - _page_snapping.add_line( false, "", _snap_closest_only, "", + _page_snapping.add_line( true, "", _snap_closest_only, "", _("Only try to snap the node that is initially closest to the mouse pointer")); _snap_weight.init("/options/snapweight/value", 0, 1, 0.1, 0.2, 0.5, 1); - _page_snapping.add_line( false, _("_Weight factor:"), _snap_weight, "", + _page_snapping.add_line( true, _("_Weight factor:"), _snap_weight, "", _("When multiple snap solutions are found, then Inkscape can either prefer the closest transformation (when set to 0), or prefer the node that was initially the closest to the pointer (when set to 1)"), true); _snap_mouse_pointer.init( _("Snap the mouse pointer when dragging a constrained knot"), "/options/snapmousepointer/value", false); - _page_snapping.add_line( false, "", _snap_mouse_pointer, "", + _page_snapping.add_line( true, "", _snap_mouse_pointer, "", _("When dragging a knot along a constraint line, then snap the position of the mouse pointer instead of snapping the projection of the knot onto the constraint line")); + _page_snapping.add_group_header( _("Delayed snap")); + + _snap_delay.init("/options/snapdelay/value", 0, 1, 0.1, 0.2, 0.3, 1); + _page_snapping.add_line( true, _("Delay (in seconds):"), _snap_delay, "", + _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true); + this->AddPage(_page_snapping, _("Snapping"), iter_behavior, PREFS_PAGE_BEHAVIOR_SNAPPING); // Steps options diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index dcea91741..7e0184c55 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -322,6 +322,7 @@ protected: UI::Widget::PrefCheckButton _importexport_import_res_override; UI::Widget::PrefSlider _snap_delay; UI::Widget::PrefSlider _snap_weight; + UI::Widget::PrefSlider _snap_persistence; UI::Widget::PrefCheckButton _font_dialog; UI::Widget::PrefCombo _font_unit_type; UI::Widget::PrefCheckButton _font_output_px; diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 38892517d..827dbf5c3 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -1351,8 +1351,9 @@ void PenTool::_bsplineSpiroColor() void PenTool::_bsplineSpiro(bool shift) { - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ return; + } shift?this->_bsplineSpiroOff():this->_bsplineSpiroOn(); this->_bsplineSpiroBuild(); @@ -1413,13 +1414,19 @@ void PenTool::_bsplineSpiroStartAnchor(bool shift) }else{ this->spiro = false; } - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ + SPCurve *tmp_curve = this->sa->curve->copy(); + if (this->sa->start) { + tmp_curve = tmp_curve ->create_reverse(); + } + this->overwrite_curve = tmp_curve ; return; - - if(shift) + } + if(shift){ this->_bsplineSpiroStartAnchorOff(); - else + } else { this->_bsplineSpiroStartAnchorOn(); + } } void PenTool::_bsplineSpiroStartAnchorOn() @@ -1482,9 +1489,9 @@ void PenTool::_bsplineSpiroStartAnchorOff() } void PenTool::_bsplineSpiroMotion(bool shift){ - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ return; - + } using Geom::X; using Geom::Y; if(this->red_curve->is_empty()) return; diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h index 7a6ab83e7..58eb6f88e 100644 --- a/src/ui/tools/tool-base.h +++ b/src/ui/tools/tool-base.h @@ -75,7 +75,12 @@ public: Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double value = prefs->getDoubleLimited("/options/snapdelay/value", 0, 0, 1000); - _timer_id = g_timeout_add(value, &sp_event_context_snap_watchdog_callback, this); + // We used to have this specified in milliseconds; this has changed to seconds now for consistency's sake + if (value > 1) { // Apparently we have an old preference file, this value must have been in milliseconds; + value = value / 1000.0; // now convert this value to seconds + } + + _timer_id = g_timeout_add(value*1000.0, &sp_event_context_snap_watchdog_callback, this); _event = gdk_event_copy((GdkEvent*) event); ((GdkEventMotion *)_event)->time = GDK_CURRENT_TIME; diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index 0a5697661..19ab1a280 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -266,12 +266,14 @@ PageSizer::PageSizer(Registry & _wr) _viewboxW.setDigits(2); _viewboxH.setDigits(2); + _dimensionWidth.setRange( 0.00001, 10000000 ); + _dimensionHeight.setRange( 0.00001, 10000000 ); _scaleX.setRange( 0.00001, 100000 ); _scaleY.setRange( 0.00001, 100000 ); _viewboxX.setRange( -100000, 100000 ); _viewboxY.setRange( -100000, 100000 ); - _viewboxW.setRange( 0, 200000 ); - _viewboxH.setRange( 0, 200000 ); + _viewboxW.setRange( 0.01, 200000 ); + _viewboxH.setRange( 0.01, 200000 ); _scaleY.set_sensitive (false); // We only want to display Y scale. diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 72597e4d9..e906762e3 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -205,6 +205,7 @@ void PrefCheckButton::init(Glib::ustring const &label, Glib::ustring const &pref void PrefCheckButton::on_toggled() { + this->changed_signal.emit(this->get_active()); if (this->get_visible()) //only take action if the user toggled it { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); diff --git a/src/ui/widget/preferences-widget.h b/src/ui/widget/preferences-widget.h index 8b75b8368..1d2d77699 100644 --- a/src/ui/widget/preferences-widget.h +++ b/src/ui/widget/preferences-widget.h @@ -59,6 +59,7 @@ class PrefCheckButton : public Gtk::CheckButton public: void init(Glib::ustring const &label, Glib::ustring const &prefs_path, bool default_value); + sigc::signal<void, bool> changed_signal; protected: Glib::ustring _prefs_path; void on_toggled(); diff --git a/src/uri-references.cpp b/src/uri-references.cpp index 2518c173e..04f904d39 100644 --- a/src/uri-references.cpp +++ b/src/uri-references.cpp @@ -43,6 +43,56 @@ URIReference::~URIReference() detach(); } +/* + * The main ideas here are: + * (1) "If we are inside a clone, then we can accept if and only if our "original thing" can accept the reference" + * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id, but also its cloned reprs + * (descendants of <use> referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i could not find a better way. + * FIXME: find a better and safer way to find the "original object" of anyone with the flag ->cloned + * + * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed edges are + * either parent->child relations , *** or href'ing to href'ed *** relations, stays acyclic. + * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case linear in the number of objects. + * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us", so we'll take this. + * Then we keep a set of already visited elements, and do a DFS on this graph. if we find obj, then BOOM. + */ + +bool URIReference::_acceptObject(SPObject *obj) const { + //we go back following hrefList and parent to find if the object already references ourselves indirectly + std::set<SPObject*> done; + SPObject * owner = getOwner(); + if(!owner)return true; + while(owner->cloned){ + std::vector<int> positions; + while(owner->cloned){ + int position=0; + SPObject* c = owner->parent->firstChild(); + while(c != owner && dynamic_cast<SPObject*>(c) ){position++;c=c->next;} + positions.push_back(position); + owner=owner->parent; + } + owner = ((SPUse*)owner)->get_original(); + for(int i=positions.size()-2;i>=0;i--)owner=owner->childList(false)[positions[i]]; + } + //once we have the "original" object (hopefully) we look at who is referencing it + std::list<SPObject*> todo(owner->hrefList); + todo.push_front(owner->parent); + while(!todo.empty()){ + SPObject* e = todo.front(); + todo.pop_front(); + if(!dynamic_cast<SPObject*>(e))continue; + if(done.insert(e).second){ + if(e==obj){return false;} + todo.push_front(e->parent); + todo.insert(todo.begin(),e->hrefList.begin(),e->hrefList.end()); + } + } + return true; +} + + + + void URIReference::attach(const URI &uri) throw(BadURIException) { SPDocument *document = NULL; diff --git a/src/uri-references.h b/src/uri-references.h index 0c51481cc..e56ea0612 100644 --- a/src/uri-references.h +++ b/src/uri-references.h @@ -15,11 +15,15 @@ */ #include <cstddef> +#include <vector> +#include <set> #include <sigc++/connection.h> #include <sigc++/trackable.h> #include "bad-uri-exception.h" #include "sp-object.h" +#include "sp-item.h" +#include "sp-use.h" namespace Inkscape { @@ -122,11 +126,7 @@ public: SPObject *getOwnerObject() { return _owner; } protected: - virtual bool _acceptObject(SPObject *obj) const { - (void)obj; - return true; - } - + virtual bool _acceptObject(SPObject *obj) const; private: SPObject *_owner; SPDocument *_owner_document; diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 46f895c06..553e3a31d 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -130,7 +130,7 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, g // FIXME: Do we need to create a new dragger as well? dragger->updateZOrders (); DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_3DBOX, - _("Split vanishing points")); + _("Split vanishing points")); return; } } @@ -175,22 +175,24 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, g // as is currently the case. DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_3DBOX, - _("Merge vanishing points")); + _("Merge vanishing points")); return; } } + } - // We didn't snap to another dragger, so we'll try a regular snap - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop); - Inkscape::SnappedPoint s = m.freeSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE)); - m.unSetup(); - if (s.getSnapped()) { - p = s.getPoint(); - knot->moveto(p); - } + // We didn't hit the return statement above, so we didn't snap to another dragger. Therefore we'll now try a regular snap + // Regardless of the status of the SHIFT key, we will try to snap; Here SHIFT does not disable snapping, as the shift key + // has a different purpose in this context (see above) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + Inkscape::SnappedPoint s = m.freeSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE)); + m.unSetup(); + if (s.getSnapped()) { + p = s.getPoint(); + knot->moveto(p); } dragger->point = p; // FIXME: Is dragger->point being used at all? @@ -241,7 +243,7 @@ vp_knot_ungrabbed_handler (SPKnot *knot, guint /*state*/, gpointer data) g_return_if_fail (dragger->parent); g_return_if_fail (dragger->parent->document); DocumentUndo::done(dragger->parent->document, SP_VERB_CONTEXT_3DBOX, - _("3D box: Move vanishing point")); + _("3D box: Move vanishing point")); } unsigned int VanishingPoint::global_counter = 0; @@ -630,7 +632,7 @@ VPDrag::updateBoxHandles () // FIXME: Is there a way to update the knots without accessing the // (previously) statically linked function KnotHolder::update_knots? - std::vector<SPItem*> sel = selection->itemList(); + std::vector<SPItem*> sel = selection->itemList(); if (sel.empty()) return; // no selection |
