diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-03-18 18:10:06 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-03-18 18:10:06 +0000 |
| commit | b4e2b53ff72280b9b3f1d902bd6a39dcb2761baf (patch) | |
| tree | 90ccefcb9b692d95c4837de089ed2d154f7677fa /src | |
| parent | Update to new simplify (diff) | |
| parent | Latvian translation update (diff) | |
| download | inkscape-b4e2b53ff72280b9b3f1d902bd6a39dcb2761baf.tar.gz inkscape-b4e2b53ff72280b9b3f1d902bd6a39dcb2761baf.zip | |
update to trunk
(bzr r13973.1.10)
Diffstat (limited to 'src')
34 files changed, 825 insertions, 444 deletions
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index 0525be04b..a2e4253d2 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -37,6 +37,7 @@ #include <2geom/choose.h> #include <2geom/path-sink.h> #include <2geom/exception.h> +#include <2geom/convex-cover.h> #include <iostream> @@ -203,11 +204,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) THROW_RANGEERROR("size of sb is too small"); } - bz.resize(4, Point(0,0)); - bz[0][X] = sb[X][0][0]; - bz[0][Y] = sb[Y][0][0]; - bz[3][X] = sb[X][0][1]; - bz[3][Y] = sb[Y][0][1]; + sbasis_to_bezier(bz, sb, 4); // zeroth-order estimate + Geom::ConvexHull bezhull(bz); // calculate first derivatives of x and y wrt t @@ -231,17 +229,23 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) midx += (sb[X][i][0] + sb[X][i][1])/div; div *= 4; } - midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; div = 2; for (size_t i = 0; i < sb[Y].size(); ++i) { midy += (sb[Y][i][0] + sb[Y][i][1])/div; div *= 4; } - midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + +// is midpoint in hull: if not, the solution will be ill-conditioned, LP Bug 1428683 + + if (!bezhull.contains_point(Geom::Point(midx, midy))) + return; // calculate Bezier control arms + midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center + midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON) && ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach numer = midx*xprime[1] + midy*yprime[1]; @@ -258,7 +262,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) dely[0] = yprime[0]*numer/denom; delx[1] = 0; dely[1] = 0; - } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > EPSILON) { // general case : fit mid fxn value + } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value + 0.002 * std::abs(xprime[1]*xprime[0] + yprime[1]*yprime[0])) { // approx. 0.1 degree of angle denom = xprime[1]*yprime[0] - yprime[1]*xprime[0]; for (int i = 0; i < 2; ++i) { numer = xprime[1 - i]*midy - yprime[1 - i]*midx; diff --git a/src/document.cpp b/src/document.cpp index 2a50d00bd..62e2f5b46 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -611,7 +611,25 @@ Inkscape::Util::Unit const& SPDocument::getSVGUnit() const return nv ? nv->getSVGUnit() : *unit_table.getUnit("px"); } -/// Returns document scale as defined by width/height and viewBox (real world to user-units). +/// Sets document scale (by changing viewBox) +void SPDocument::setDocumentScale( double scaleX, double scaleY ) { + + root->viewBox = Geom::Rect::from_xywh( + root->viewBox.left(), + root->viewBox.top(), + root->width.computed * scaleX, + root->height.computed * scaleY ); + root->viewBox_set = true; + root->updateRepr(); +} + +/// Sets document scale (by changing viewBox, x and y scaling equal) +void SPDocument::setDocumentScale( double scale ) { + setDocumentScale( scale, scale ); +} + +/// Returns document scale as defined by width/height (in pixels) and viewBox (real world to +/// user-units). Geom::Scale SPDocument::getDocumentScale() const { Geom::Scale scale; @@ -660,10 +678,12 @@ void SPDocument::setWidthAndHeight(const Inkscape::Util::Quantity &width, const root->height.value = height.quantity; root->height.unit = (SVGLength::Unit) height.unit->svgUnit(); - if (root->viewBox_set && changeSize) + // viewBox scaled by relative change in page size (maintains document scale). + if (root->viewBox_set && changeSize) { root->viewBox.setMax(Geom::Point( root->viewBox.left() + (root->width.value / old_width_converted ) * root->viewBox.width(), root->viewBox.top() + (root->height.value / old_height_converted) * root->viewBox.height())); + } root->updateRepr(); } diff --git a/src/document.h b/src/document.h index a33b476cc..ed19d123b 100644 --- a/src/document.h +++ b/src/document.h @@ -242,6 +242,8 @@ public: SPDocument *doUnref(); Inkscape::Util::Unit const* getDisplayUnit() const; Inkscape::Util::Unit const& getSVGUnit() const; + void setDocumentScale( const double scaleX, const double scaleY ); + void setDocumentScale( const double scale ); Geom::Scale getDocumentScale() const; Inkscape::Util::Quantity getWidth() const; Inkscape::Util::Quantity getHeight() const; diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 1f48d2097..7fbdc4296 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -517,7 +517,7 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx) SPStyle* style = item->style; if((ctx->getFilterToBitmap() == TRUE) && (style->filter.set != 0)) { - sp_asbitmap_render(item, ctx); + return sp_asbitmap_render(item, ctx); } SPRoot *root = dynamic_cast<SPRoot *>(item); diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 6eba6e949..91689375f 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -556,6 +556,55 @@ pathv_to_linear( Geom::PathVector const &pathv, double /*maxdisp*/) return output; } +/* + * Converts all segments in all paths to Geom Cubic bezier. + * This is used in lattice2 LPE, maybe is better move the function to the effect + * But maybe could be usable by others, so i put here. + * The straight curve part is needed as it for the effect to work apropiately + */ +Geom::PathVector +pathv_to_cubicbezier( Geom::PathVector const &pathv) +{ + Geom::PathVector output; + double cubicGap = 0.01; + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + output.push_back( Geom::Path() ); + output.back().start( pit->initialPoint() ); + output.back().close( pit->closed() ); + bool end_open = false; + if (pit->closed()) { + const Geom::Curve &closingline = pit->back_closed(); + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { + end_open = true; + } + } + Geom::Path pitCubic = (Geom::Path)(*pit); + if(end_open && pit->closed()){ + pitCubic.close(false); + pitCubic.appendNew<Geom::LineSegment>( pitCubic.initialPoint() ); + pitCubic.close(true); + } + for (Geom::Path::const_iterator cit = pitCubic.begin(); cit != pitCubic.end_open(); ++cit) { + if (is_straight_curve(*cit)) { + Geom::CubicBezier b(cit->initialPoint(), cit->pointAt(0.3334) + Geom::Point(cubicGap,cubicGap), cit->finalPoint(), cit->finalPoint()); + output.back().append(b); + } else { + Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); + if (curve && curve->order() == 3) { + Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); + output.back().append(b); + } else { + // convert all other curve types to cubicbeziers + Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); + output.back().append(cubicbezier_path); + } + } + } + } + + return output; +} + // The next routine is modified from curv4_div::recursive_bezier from file agg_curves.cpp //---------------------------------------------------------------------------- // Anti-Grain Geometry (AGG) - Version 2.5 diff --git a/src/helper/geom.h b/src/helper/geom.h index caff95733..3232d9fd5 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -27,6 +27,7 @@ void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geo Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ); Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp ); +Geom::PathVector pathv_to_cubicbezier( Geom::PathVector const &pathv); void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, std::vector<Geom::Point> &pointlist, diff --git a/src/knotholder.cpp b/src/knotholder.cpp index f46daa09e..a2d1cf017 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -165,7 +165,8 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) if (saved_item) { //increasingly aggressive sanity checks if (saved_item->document) { - if (object_verb <= SP_VERB_LAST && object_verb >= SP_VERB_INVALID) { + // enum is unsigned so can't be less than SP_VERB_INVALID + if (object_verb <= SP_VERB_LAST) { DocumentUndo::done(saved_item->document, object_verb, _("Change handle")); } diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index aab64fe64..1da364580 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -363,6 +363,10 @@ Effect::Effect(LivePathEffectObject *lpeobject) show_orig_path(false), lpeobj(lpeobject), concatenate_before_pwd2(false), + sp_lpe_item(NULL), + defaultUnit("px"), + current_zoom(1), + sp_curve(NULL), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden { @@ -461,9 +465,11 @@ void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); defaultUnit = sp_lpe_item->document->getDisplayUnit()->abbr; //printf("(SPLPEITEM*) %p\n", sp_lpe_item); - sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); - pathvector_before_effect = sp_curve->get_pathvector(); - + SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item); + if(shape){ + sp_curve = shape->getCurve(); + pathvector_before_effect = sp_curve->get_pathvector(); + } doBeforeEffect(lpeitem); } diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index ce0e4941b..c05bae7e1 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -236,21 +236,21 @@ LPELattice::resetDefaults(SPItem const* item) grid_point15[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min(); grid_point15[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min(); - grid_point1.param_set_and_write_new_value(grid_point1); - grid_point2.param_set_and_write_new_value(grid_point2); - grid_point3.param_set_and_write_new_value(grid_point3); - grid_point4.param_set_and_write_new_value(grid_point4); - grid_point5.param_set_and_write_new_value(grid_point5); - grid_point6.param_set_and_write_new_value(grid_point6); - grid_point7.param_set_and_write_new_value(grid_point7); - grid_point8.param_set_and_write_new_value(grid_point8); - grid_point9.param_set_and_write_new_value(grid_point9); - grid_point10.param_set_and_write_new_value(grid_point10); - grid_point11.param_set_and_write_new_value(grid_point11); - grid_point12.param_set_and_write_new_value(grid_point12); - grid_point13.param_set_and_write_new_value(grid_point13); - grid_point14.param_set_and_write_new_value(grid_point14); - grid_point15.param_set_and_write_new_value(grid_point15); + grid_point1.param_update_default(grid_point1); + grid_point2.param_update_default(grid_point2); + grid_point3.param_update_default(grid_point3); + grid_point4.param_update_default(grid_point4); + grid_point5.param_update_default(grid_point5); + grid_point6.param_update_default(grid_point6); + grid_point7.param_update_default(grid_point7); + grid_point8.param_update_default(grid_point8); + grid_point9.param_update_default(grid_point9); + grid_point10.param_update_default(grid_point10); + grid_point11.param_update_default(grid_point11); + grid_point12.param_update_default(grid_point12); + grid_point13.param_update_default(grid_point13); + grid_point14.param_update_default(grid_point14); + grid_point15.param_update_default(grid_point15); } /** diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index 1bcbe286f..08bbbd504 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -23,18 +23,17 @@ #include "sp-path.h" #include "display/curve.h" #include "svg/svg.h" - +#include "helper/geom.h" +#include <2geom/path.h> #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> +#include "helper/geom-curves.h" #include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/d2.h> #include <2geom/piecewise.h> #include <2geom/transforms.h> -#include "ui/tools-switch.h" - -#include "desktop.h" // TODO: should be factored out (see below) using namespace Geom; @@ -43,61 +42,63 @@ namespace LivePathEffect { LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) : Effect(lpeobject), - // initialise your parameters here: - grid_point0(_("Control handle 0:"), _("Control handle 0 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint0", &wr, this), - grid_point1(_("Control handle 1:"), _("Control handle 1 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint1", &wr, this), - grid_point2(_("Control handle 2:"), _("Control handle 2 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint2", &wr, this), - grid_point3(_("Control handle 3:"), _("Control handle 3 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint3", &wr, this), - grid_point4(_("Control handle 4:"), _("Control handle 4 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint4", &wr, this), - grid_point5(_("Control handle 5:"), _("Control handle 5 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint5", &wr, this), - grid_point6(_("Control handle 6:"), _("Control handle 6 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint6", &wr, this), - grid_point7(_("Control handle 7:"), _("Control handle 7 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint7", &wr, this), - grid_point8x9(_("Control handle 8x9:"), _("Control handle 8x9 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint8x9", &wr, this), - grid_point10x11(_("Control handle 10x11:"), _("Control handle 10x11 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint10x11", &wr, this), - grid_point12(_("Control handle 12:"), _("Control handle 12 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint12", &wr, this), - grid_point13(_("Control handle 13:"), _("Control handle 13 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint13", &wr, this), - grid_point14(_("Control handle 14:"), _("Control handle 14 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint14", &wr, this), - grid_point15(_("Control handle 15:"), _("Control handle 15 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint15", &wr, this), - grid_point16(_("Control handle 16:"), _("Control handle 16 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint16", &wr, this), - grid_point17(_("Control handle 17:"), _("Control handle 17 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint17", &wr, this), - grid_point18(_("Control handle 18:"), _("Control handle 18 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint18", &wr, this), - grid_point19(_("Control handle 19:"), _("Control handle 19 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint19", &wr, this), - grid_point20x21(_("Control handle 20x21:"), _("Control handle 20x21 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint20x21", &wr, this), - grid_point22x23(_("Control handle 22x23:"), _("Control handle 22x23 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint22x23", &wr, this), - grid_point24x26(_("Control handle 24x26:"), _("Control handle 24x26 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint24x26", &wr, this), - grid_point25x27(_("Control handle 25x27:"), _("Control handle 25x27 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint25x27", &wr, this), - grid_point28x30(_("Control handle 28x30:"), _("Control handle 28x30 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint28x30", &wr, this), - grid_point29x31(_("Control handle 29x31:"), _("Control handle 29x31 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint29x31", &wr, this), - grid_point32x33x34x35(_("Control handle 32x33x34x35:"), _("Control handle 32x33x34x35 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint32x33x34x35", &wr, this) - - + horizontalMirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontalMirror", &wr, this, false), + verticalMirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "verticalMirror", &wr, this, false), + grid_point0(_("Control 0:"), _("Control 0 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint0", &wr, this), + grid_point1(_("Control 1:"), _("Control 1 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint1", &wr, this), + grid_point2(_("Control 2:"), _("Control 2 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint2", &wr, this), + grid_point3(_("Control 3:"), _("Control 3 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint3", &wr, this), + grid_point4(_("Control 4:"), _("Control 4 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint4", &wr, this), + grid_point5(_("Control 5:"), _("Control 5 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint5", &wr, this), + grid_point6(_("Control 6:"), _("Control 6 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint6", &wr, this), + grid_point7(_("Control 7:"), _("Control 7 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint7", &wr, this), + grid_point8x9(_("Control 8x9:"), _("Control 8x9 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint8x9", &wr, this), + grid_point10x11(_("Control 10x11:"), _("Control 10x11 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint10x11", &wr, this), + grid_point12(_("Control 12:"), _("Control 12 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint12", &wr, this), + grid_point13(_("Control 13:"), _("Control 13 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint13", &wr, this), + grid_point14(_("Control 14:"), _("Control 14 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint14", &wr, this), + grid_point15(_("Control 15:"), _("Control 15 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint15", &wr, this), + grid_point16(_("Control 16:"), _("Control 16 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint16", &wr, this), + grid_point17(_("Control 17:"), _("Control 17 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint17", &wr, this), + grid_point18(_("Control 18:"), _("Control 18 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint18", &wr, this), + grid_point19(_("Control 19:"), _("Control 19 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint19", &wr, this), + grid_point20x21(_("Control 20x21:"), _("Control 20x21 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint20x21", &wr, this), + grid_point22x23(_("Control 22x23:"), _("Control 22x23 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint22x23", &wr, this), + grid_point24x26(_("Control 24x26:"), _("Control 24x26 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint24x26", &wr, this), + grid_point25x27(_("Control 25x27:"), _("Control 25x27 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint25x27", &wr, this), + grid_point28x30(_("Control 28x30:"), _("Control 28x30 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint28x30", &wr, this), + grid_point29x31(_("Control 29x31:"), _("Control 29x31 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint29x31", &wr, this), + grid_point32x33x34x35(_("Control 32x33x34x35:"), _("Control 32x33x34x35 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint32x33x34x35", &wr, this), + expanded(false) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&grid_point0) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point1) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point2) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point3) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point4) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point5) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point6) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point7) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point8x9) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point10x11) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point12) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point13) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point16) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point17) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point18) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point19) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point20x21) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point22x23) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point24x26) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point25x27) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point28x30) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point29x31) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point32x33x34x35) ); + registerParameter(&horizontalMirror); + registerParameter(&verticalMirror); + registerParameter(&grid_point0); + registerParameter(&grid_point1); + registerParameter(&grid_point2); + registerParameter(&grid_point3); + registerParameter(&grid_point4); + registerParameter(&grid_point5); + registerParameter(&grid_point6); + registerParameter(&grid_point7); + registerParameter(&grid_point8x9); + registerParameter(&grid_point10x11); + registerParameter(&grid_point12); + registerParameter(&grid_point13); + registerParameter(&grid_point14); + registerParameter(&grid_point15); + registerParameter(&grid_point16); + registerParameter(&grid_point17); + registerParameter(&grid_point18); + registerParameter(&grid_point19); + registerParameter(&grid_point20x21); + registerParameter(&grid_point22x23); + registerParameter(&grid_point24x26); + registerParameter(&grid_point25x27); + registerParameter(&grid_point28x30); + registerParameter(&grid_point29x31); + registerParameter(&grid_point32x33x34x35); } LPELattice2::~LPELattice2() @@ -107,6 +108,10 @@ LPELattice2::~LPELattice2() Geom::Piecewise<Geom::D2<Geom::SBasis> > LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { + PathVector pathv = path_from_piecewise(pwd2_in,0.001); + //this is because strange problems whith sb2 and LineSegment + PathVector cubic = pathv_to_cubicbezier(pathv); + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in_linear_and_cubic = paths_to_pw(cubic); D2<SBasis2d> sb2; //Initialisation of the sb2 @@ -118,44 +123,45 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd } //Grouping the point params in a convenient vector - std::vector<Geom::Point *> handles(36); + + std::vector<Geom::Point > handles(36); - handles[0] = &grid_point0; - handles[1] = &grid_point1; - handles[2] = &grid_point2; - handles[3] = &grid_point3; - handles[4] = &grid_point4; - handles[5] = &grid_point5; - handles[6] = &grid_point6; - handles[7] = &grid_point7; - handles[8] = &grid_point8x9; - handles[9] = &grid_point8x9; - handles[10] = &grid_point10x11; - handles[11] = &grid_point10x11; - handles[12] = &grid_point12; - handles[13] = &grid_point13; - handles[14] = &grid_point14; - handles[15] = &grid_point15; - handles[16] = &grid_point16; - handles[17] = &grid_point17; - handles[18] = &grid_point18; - handles[19] = &grid_point19; - handles[20] = &grid_point20x21; - handles[21] = &grid_point20x21; - handles[22] = &grid_point22x23; - handles[23] = &grid_point22x23; - handles[24] = &grid_point24x26; - handles[25] = &grid_point25x27; - handles[26] = &grid_point24x26; - handles[27] = &grid_point25x27; - handles[28] = &grid_point28x30; - handles[29] = &grid_point29x31; - handles[30] = &grid_point28x30; - handles[31] = &grid_point29x31; - handles[32] = &grid_point32x33x34x35; - handles[33] = &grid_point32x33x34x35; - handles[34] = &grid_point32x33x34x35; - handles[35] = &grid_point32x33x34x35; + handles[0] = grid_point0; + handles[1] = grid_point1; + handles[2] = grid_point2; + handles[3] = grid_point3; + handles[4] = grid_point4; + handles[5] = grid_point5; + handles[6] = grid_point6; + handles[7] = grid_point7; + handles[8] = grid_point8x9; + handles[9] = grid_point8x9; + handles[10] = grid_point10x11; + handles[11] = grid_point10x11; + handles[12] = grid_point12; + handles[13] = grid_point13; + handles[14] = grid_point14; + handles[15] = grid_point15; + handles[16] = grid_point16; + handles[17] = grid_point17; + handles[18] = grid_point18; + handles[19] = grid_point19; + handles[20] = grid_point20x21; + handles[21] = grid_point20x21; + handles[22] = grid_point22x23; + handles[23] = grid_point22x23; + handles[24] = grid_point24x26; + handles[25] = grid_point25x27; + handles[26] = grid_point24x26; + handles[27] = grid_point25x27; + handles[28] = grid_point28x30; + handles[29] = grid_point29x31; + handles[30] = grid_point28x30; + handles[31] = grid_point29x31; + handles[32] = grid_point32x33x34x35; + handles[33] = grid_point32x33x34x35; + handles[34] = grid_point32x33x34x35; + handles[35] = grid_point32x33x34x35; Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min()); @@ -185,7 +191,7 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd // i = Upperleft corner of the considerated rectangle // corner = actual corner of the rectangle // origin = Upperleft point - double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); + double dl = dot((handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi); } } @@ -195,8 +201,8 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd Piecewise<D2<SBasis> > output; output.push_cut(0.); - for(unsigned i = 0; i < pwd2_in.size(); i++) { - D2<SBasis> B = pwd2_in[i]; + for(unsigned i = 0; i < pwd2_in_linear_and_cubic.size(); i++) { + D2<SBasis> B = pwd2_in_linear_and_cubic[i]; B[Geom::X] -= origin[Geom::X]; B[Geom::X]*= 1/width; B[Geom::Y] -= origin[Geom::Y]; @@ -211,6 +217,7 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd return output; } + Gtk::Widget * LPELattice2::newWidget() { @@ -221,7 +228,10 @@ LPELattice2::newWidget() vbox->set_homogeneous(false); vbox->set_spacing(6); Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); - Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); + Gtk::VBox * vboxExpander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vboxExpander->set_border_width(0); + vboxExpander->set_spacing(2); + Gtk::Button * resetButton = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPELattice2::resetGrid)); resetButton->set_size_request(140,30); vbox->pack_start(*hbox, true,true,2); @@ -236,7 +246,11 @@ LPELattice2::newWidget() } Glib::ustring * tip = param->param_getTooltip(); if (widg) { - vbox->pack_start(*widg, true, true, 2); + if (param->param_key == "horizontalMirror" || param->param_key == "verticalMirror") { + vbox->pack_start(*widg, true, true, 2); + } else { + vboxExpander->pack_start(*widg, true, true, 2); + } if (tip) { widg->set_tooltip_text(*tip); } else { @@ -248,14 +262,96 @@ LPELattice2::newWidget() ++it; } + + expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show Points")))); + expander->add(*vboxExpander); + expander->set_expanded(expanded); + vbox->pack_start(*expander, true, true, 2); + expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPELattice2::on_expander_changed) ); return dynamic_cast<Gtk::Widget *>(vbox); } void +LPELattice2::on_expander_changed() +{ + expanded = expander->get_expanded(); + if(expander->get_expanded()){ + expander->set_label (Glib::ustring(_("Hide Points"))); + } else { + expander->set_label (Glib::ustring(_("Show Points"))); + } +} +void +LPELattice2::vertical(PointParam ¶mA, PointParam ¶mB, Geom::Line vert){ + Geom::Point A = paramA; + Geom::Point B = paramB; + double Y = (A[Geom::Y] + B[Geom::Y])/2; + A[Geom::Y] = Y; + B[Geom::Y] = Y; + Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + double distA = Geom::distance(A,nearest); + double distB = Geom::distance(B,nearest); + double distanceMed = (distA + distB)/2; + if(A[Geom::X] > B[Geom::X]){ + distanceMed *= -1; + } + A[Geom::X] = nearest[Geom::X] - distanceMed; + B[Geom::X] = nearest[Geom::X] + distanceMed; + paramA.param_setValue(A, true); + paramB.param_setValue(B, true); +} + +void +LPELattice2::horizontal(PointParam ¶mA, PointParam ¶mB, Geom::Line horiz){ + Geom::Point A = paramA; + Geom::Point B = paramB; + double X = (A[Geom::X] + B[Geom::X])/2; + A[Geom::X] = X; + B[Geom::X] = X; + Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + double distA = Geom::distance(A,nearest); + double distB = Geom::distance(B,nearest); + double distanceMed = (distA + distB)/2; + if(A[Geom::Y] > B[Geom::Y]){ + distanceMed *= -1; + } + A[Geom::Y] = nearest[Geom::Y] - distanceMed; + B[Geom::Y] = nearest[Geom::Y] + distanceMed; + paramA.param_setValue(A, true); + paramB.param_setValue(B, true); +} + +void LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); setDefaults(); + Geom::Line vert(grid_point8x9.param_get_default(),grid_point10x11.param_get_default()); + Geom::Line horiz(grid_point24x26.param_get_default(),grid_point25x27.param_get_default()); + if(verticalMirror){ + vertical(grid_point0, grid_point1,vert); + vertical(grid_point2, grid_point3,vert); + vertical(grid_point4, grid_point5,vert); + vertical(grid_point6, grid_point7,vert); + vertical(grid_point12, grid_point13,vert); + vertical(grid_point14, grid_point15,vert); + vertical(grid_point16, grid_point17,vert); + vertical(grid_point18, grid_point19,vert); + vertical(grid_point24x26, grid_point25x27,vert); + vertical(grid_point28x30, grid_point29x31,vert); + } + if(horizontalMirror){ + horizontal(grid_point0, grid_point2,horiz); + horizontal(grid_point1, grid_point3,horiz); + horizontal(grid_point4, grid_point6,horiz); + horizontal(grid_point5, grid_point7,horiz); + horizontal(grid_point8x9, grid_point10x11,horiz); + horizontal(grid_point12, grid_point14,horiz); + horizontal(grid_point13, grid_point15,horiz); + horizontal(grid_point16, grid_point18,horiz); + horizontal(grid_point17, grid_point19,horiz); + horizontal(grid_point20x21, grid_point22x23,horiz); + } SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); item->apply_to_clippath(item); item->apply_to_mask(item); @@ -369,36 +465,31 @@ LPELattice2::setDefaults() void LPELattice2::resetGrid() { - grid_point0.param_set_and_write_default(); - grid_point1.param_set_and_write_default(); - grid_point2.param_set_and_write_default(); - grid_point3.param_set_and_write_default(); - grid_point4.param_set_and_write_default(); - grid_point5.param_set_and_write_default(); - grid_point6.param_set_and_write_default(); - grid_point7.param_set_and_write_default(); - grid_point8x9.param_set_and_write_default(); - grid_point10x11.param_set_and_write_default(); - grid_point12.param_set_and_write_default(); - grid_point13.param_set_and_write_default(); - grid_point14.param_set_and_write_default(); - grid_point15.param_set_and_write_default(); - grid_point16.param_set_and_write_default(); - grid_point17.param_set_and_write_default(); - grid_point18.param_set_and_write_default(); - grid_point19.param_set_and_write_default(); - grid_point20x21.param_set_and_write_default(); - grid_point22x23.param_set_and_write_default(); - grid_point24x26.param_set_and_write_default(); - grid_point25x27.param_set_and_write_default(); - grid_point28x30.param_set_and_write_default(); - grid_point29x31.param_set_and_write_default(); - grid_point32x33x34x35.param_set_and_write_default(); - //todo:this hack is only to reposition the knots on reser grid button - //Better update path effect in LPEITEM - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - tools_switch(desktop, TOOLS_SELECT); - tools_switch(desktop, TOOLS_NODES); + grid_point0.param_set_default(); + grid_point1.param_set_default(); + grid_point2.param_set_default(); + grid_point3.param_set_default(); + grid_point4.param_set_default(); + grid_point5.param_set_default(); + grid_point6.param_set_default(); + grid_point7.param_set_default(); + grid_point8x9.param_set_default(); + grid_point10x11.param_set_default(); + grid_point12.param_set_default(); + grid_point13.param_set_default(); + grid_point14.param_set_default(); + grid_point15.param_set_default(); + grid_point16.param_set_default(); + grid_point17.param_set_default(); + grid_point18.param_set_default(); + grid_point19.param_set_default(); + grid_point20x21.param_set_default(); + grid_point22x23.param_set_default(); + grid_point24x26.param_set_default(); + grid_point25x27.param_set_default(); + grid_point28x30.param_set_default(); + grid_point29x31.param_set_default(); + grid_point32x33x34x35.param_set_default(); } void diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h index 5084ceead..086bdab7e 100644 --- a/src/live_effects/lpe-lattice2.h +++ b/src/live_effects/lpe-lattice2.h @@ -18,7 +18,7 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include <gtkmm.h> #include "live_effects/parameter/enum.h" #include "live_effects/effect.h" #include "live_effects/parameter/point.h" @@ -43,8 +43,14 @@ public: virtual void calculateCurve(Geom::Point a,Geom::Point b, SPCurve *c, bool horizontal, bool move); + virtual void vertical(PointParam ¶mA,PointParam ¶mB, Geom::Line vert); + + virtual void horizontal(PointParam ¶mA,PointParam ¶mB,Geom::Line horiz); + virtual void setDefaults(); + virtual void on_expander_changed(); + virtual void resetGrid(); //virtual void original_bbox(SPLPEItem const* lpeitem, bool absolute = false); @@ -56,6 +62,8 @@ protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); private: + BoolParam horizontalMirror; + BoolParam verticalMirror; PointParam grid_point0; PointParam grid_point1; PointParam grid_point2; @@ -82,6 +90,9 @@ private: PointParam grid_point29x31; PointParam grid_point32x33x34x35; + bool expanded; + Gtk::Expander * expander; + LPELattice2(const LPELattice2&); LPELattice2& operator=(const LPELattice2&); }; diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index 232f1c9db..ba7179476 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -44,7 +44,7 @@ LPEOffset::doOnApply(SPLPEItem const* lpeitem) { Geom::Point offset = *(SP_SHAPE(lpeitem)->_curve->first_point()); offset_pt.param_update_default(offset); - offset_pt.param_set_and_write_new_value(offset); + offset_pt.param_setValue(offset,true); } static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp index a1e713fe2..aa7405607 100644 --- a/src/live_effects/lpe-parallel.cpp +++ b/src/live_effects/lpe-parallel.cpp @@ -74,7 +74,7 @@ LPEParallel::doOnApply (SPLPEItem const* lpeitem) dir = unit_vector(B - A); Geom::Point offset = (A + B)/2 + dir.ccw() * 100; offset_pt.param_update_default(offset); - offset_pt.param_set_and_write_new_value(offset); + offset_pt.param_setValue(offset, true); } Geom::Piecewise<Geom::D2<Geom::SBasis> > diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index d38427d0a..d60a13c23 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -19,9 +19,7 @@ #include "helper/geom.h" #include "display/curve.h" #include "svg/svg.h" -#include "ui/tools-switch.h" #include <gsl/gsl_linalg.h> -#include "desktop.h" using namespace Geom; @@ -331,15 +329,10 @@ LPEPerspectiveEnvelope::setDefaults() void LPEPerspectiveEnvelope::resetGrid() { - Up_Left_Point.param_set_and_write_default(); - Up_Right_Point.param_set_and_write_default(); - Down_Right_Point.param_set_and_write_default(); - Down_Left_Point.param_set_and_write_default(); - //todo:this hack is only to reposition the knots on reser grid button - //Better update path effect in LPEITEM - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - tools_switch(desktop, TOOLS_SELECT); - tools_switch(desktop, TOOLS_NODES); + Up_Left_Point.param_set_default(); + Up_Right_Point.param_set_default(); + Down_Right_Point.param_set_default(); + Down_Left_Point.param_set_default(); } void @@ -347,8 +340,8 @@ LPEPerspectiveEnvelope::resetDefaults(SPItem const* item) { Effect::resetDefaults(item); original_bbox(SP_LPE_ITEM(item)); - setDefaults(); resetGrid(); + setDefaults(); } void diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index 36ab6b547..c6787aae1 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -28,7 +28,7 @@ LPEdoEffectStackTest::LPEdoEffectStackTest(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&path) ); point.set_oncanvas_looks(SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR, 0x00ff0000); - point.param_set_and_write_new_value(point); + point.param_setValue(point,true); } LPEdoEffectStackTest::~LPEdoEffectStackTest() diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index 1d48bda8d..4c4d2cd9c 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -15,8 +15,6 @@ #include "verbs.h" #include "knotholder.h" #include <glibmm/i18n.h> -#include "ui/tools-switch.h" -#include "ui/tools/node-tool.h" // needed for on-canvas editting: #include "desktop.h" @@ -28,7 +26,9 @@ namespace LivePathEffect { PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, const gchar *htip, Geom::Point default_value) - : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value) + : Parameter(label, tip, key, wr, effect), + defvalue(default_value), + knoth(NULL) { knot_shape = SP_KNOT_SHAPE_DIAMOND; knot_mode = SP_KNOT_MODE_XOR; @@ -45,19 +45,34 @@ PointParam::~PointParam() void PointParam::param_set_default() { - param_setValue(defvalue); + param_setValue(defvalue,true); +} + +Geom::Point +PointParam::param_get_default() const{ + return defvalue; } void -PointParam::param_set_and_write_default() +PointParam::param_update_default(Geom::Point newpoint) { - param_set_and_write_new_value(defvalue); + defvalue = newpoint; } void -PointParam::param_update_default(Geom::Point newpoint) +PointParam::param_setValue(Geom::Point newpoint, bool write) { - this->defvalue = newpoint; + *dynamic_cast<Geom::Point *>( this ) = newpoint; + if(write){ + Inkscape::SVGOStringStream os; + os << newpoint; + gchar * str = g_strdup(os.str().c_str()); + param_write_to_repr(str); + g_free(str); + } + if(knoth){ + knoth->update_knots(); + } } bool @@ -84,6 +99,12 @@ PointParam::param_getSVGValue() const return str; } +void +PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +{ + param_setValue( (*this) * postmul, true); +} + Gtk::Widget * PointParam::param_newWidget() { @@ -110,36 +131,6 @@ PointParam::param_newWidget() } void -PointParam::param_setValue(Geom::Point newpoint) -{ - *dynamic_cast<Geom::Point *>( this ) = newpoint; - if(SP_ACTIVE_DESKTOP){ - SPDesktop* desktop = SP_ACTIVE_DESKTOP; - if (tools_isactive( desktop, TOOLS_NODES)) { - Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>( desktop->event_context); - nt->update_helperpath(); - } - } -} - -void -PointParam::param_set_and_write_new_value (Geom::Point newpoint) -{ - Inkscape::SVGOStringStream os; - os << newpoint; - gchar * str = g_strdup(os.str().c_str()); - param_write_to_repr(str); - g_free(str); -} - -void -PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) -{ - param_set_and_write_new_value( (*this) * postmul ); -} - - -void PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { knot_shape = shape; @@ -150,7 +141,7 @@ PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint class PointParamKnotHolderEntity : public KnotHolderEntity { public: PointParamKnotHolderEntity(PointParam *p) { this->pparam = p; } - virtual ~PointParamKnotHolderEntity() {} + virtual ~PointParamKnotHolderEntity() { this->pparam->knoth = NULL;} virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); virtual Geom::Point knot_get() const; @@ -175,8 +166,11 @@ PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &or s = A; } } - pparam->param_setValue(s); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + pparam->param_setValue(s, true); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); + } } Geom::Point @@ -191,7 +185,10 @@ PointParamKnotHolderEntity::knot_click(guint state) if (state & GDK_CONTROL_MASK) { if (state & GDK_MOD1_MASK) { this->pparam->param_set_default(); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); + } } } } @@ -199,6 +196,7 @@ PointParamKnotHolderEntity::knot_click(guint state) void PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { + knoth = knotholder; PointParamKnotHolderEntity *e = new PointParamKnotHolderEntity(this); // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index 95854ea52..471fbc993 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -38,14 +38,10 @@ public: bool param_readSVGValue(const gchar * strvalue); gchar * param_getSVGValue() const; inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); } - - void param_setValue(Geom::Point newpoint); + void param_setValue(Geom::Point newpoint, bool write = false); void param_set_default(); - void param_set_and_write_default(); + Geom::Point param_get_default() const; void param_update_default(Geom::Point newpoint); - - void param_set_and_write_new_value(Geom::Point newpoint); - virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); @@ -57,9 +53,8 @@ public: private: PointParam(const PointParam&); PointParam& operator=(const PointParam&); - Geom::Point defvalue; - + KnotHolder *knoth; SPKnotShapeType knot_shape; SPKnotModeType knot_mode; guint32 knot_color; diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 885fedafa..932a3a1b7 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -95,6 +95,10 @@ void SPGenericEllipse::build(SPDocument *document, Inkscape::XML::Node *repr) std::cerr << "SPGenericEllipse::build() unknown defined type." << std::endl; } + // std::cout << " cx: " << cx.write() << std::endl; + // std::cout << " cy: " << cy.write() << std::endl; + // std::cout << " rx: " << rx.write() << std::endl; + // std::cout << " ry: " << ry.write() << std::endl; SPShape::build(document, repr); } @@ -103,29 +107,41 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value) // There are multiple ways to set internal cx, cy, rx, and ry (via SVG attributes or Sodipodi // attributes) thus we don't want to unset them if a read fails (e.g., when we explicitly clear // an attribute by setting it to NULL). + + // We must update the SVGLengths immediately or nodes may be misplaced after they are moved. + double const w = viewport.width(); + double const h = viewport.height(); + double const d = hypot(w, h) / sqrt(2); // diagonal + double const em = style->font_size.computed; + double const ex = em * 0.5; + SVGLength t; switch (key) { case SP_ATTR_CX: case SP_ATTR_SODIPODI_CX: if( t.read(value) ) cx = t; + cx.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_CY: case SP_ATTR_SODIPODI_CY: if( t.read(value) ) cy = t; + cy.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_RX: case SP_ATTR_SODIPODI_RX: - if( t.read(value) && t.value > 0.0 ) this->rx = t; + if( t.read(value) && t.value > 0.0 ) rx = t; + rx.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_RY: case SP_ATTR_SODIPODI_RY: - if( t.read(value) && t.value > 0.0 ) this->ry = t; + if( t.read(value) && t.value > 0.0 ) ry = t; + ry.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -133,6 +149,8 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value) if( t.read(value) && t.value > 0.0 ) { this->ry = this->rx = t; } + rx.update( em, ex, d ); + ry.update( em, ex, d ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -196,7 +214,7 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I // << ")" << std::endl; GenericEllipseType new_type = SP_GENERIC_ELLIPSE_UNDEFINED; - if (this->_isSlice() || hasPathEffect() ) { + if (_isSlice() || hasPathEffect() ) { new_type = SP_GENERIC_ELLIPSE_ARC; } else if ( rx.computed == ry.computed ) { new_type = SP_GENERIC_ELLIPSE_CIRCLE; @@ -246,10 +264,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I } // std::cout << " type: " << g_quark_to_string( repr->code() ) << std::endl; - // std::cout << " cx: " << cx.computed - // << " cy: " << cy.computed - // << " rx: " << rx.computed - // << " ry: " << ry.computed << std::endl; + // std::cout << " cx: " << cx.write() << " " << cx.computed + // << " cy: " << cy.write() << " " << cy.computed + // << " rx: " << rx.write() << " " << rx.computed + // << " ry: " << ry.write() << " " << ry.computed << std::endl; switch ( type ) { case SP_GENERIC_ELLIPSE_UNDEFINED: @@ -264,17 +282,17 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I if (flags & SP_OBJECT_WRITE_EXT) { repr->setAttribute("sodipodi:type", "arc"); - sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx.computed); - sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy.computed); - sp_repr_set_svg_double(repr, "sodipodi:rx", this->rx.computed); - sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed); + sp_repr_set_svg_length(repr, "sodipodi:cx", cx); + sp_repr_set_svg_length(repr, "sodipodi:cy", cy); + sp_repr_set_svg_length(repr, "sodipodi:rx", rx); + sp_repr_set_svg_length(repr, "sodipodi:ry", ry); // write start and end only if they are non-trivial; otherwise remove - if (this->_isSlice()) { - sp_repr_set_svg_double(repr, "sodipodi:start", this->start); - sp_repr_set_svg_double(repr, "sodipodi:end", this->end); + if (_isSlice()) { + sp_repr_set_svg_double(repr, "sodipodi:start", start); + sp_repr_set_svg_double(repr, "sodipodi:end", end); - repr->setAttribute("sodipodi:open", (!this->_closed) ? "true" : NULL); + repr->setAttribute("sodipodi:open", (!_closed) ? "true" : NULL); } else { repr->setAttribute("sodipodi:end", NULL); repr->setAttribute("sodipodi:start", NULL); @@ -283,13 +301,13 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I } // write d= - this->set_elliptical_path_attribute(repr); + set_elliptical_path_attribute(repr); break; case SP_GENERIC_ELLIPSE_CIRCLE: - sp_repr_set_svg_double(repr, "cx", this->cx.computed); - sp_repr_set_svg_double(repr, "cy", this->cy.computed); - sp_repr_set_svg_double(repr, "r", this->rx.computed); + sp_repr_set_svg_length(repr, "cx", cx); + sp_repr_set_svg_length(repr, "cy", cy); + sp_repr_set_svg_length(repr, "r", rx); repr->setAttribute("rx", NULL ); repr->setAttribute("ry", NULL ); repr->setAttribute("sodipodi:cx", NULL ); @@ -304,10 +322,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I break; case SP_GENERIC_ELLIPSE_ELLIPSE: - sp_repr_set_svg_double(repr, "cx", this->cx.computed); - sp_repr_set_svg_double(repr, "cy", this->cy.computed); - sp_repr_set_svg_double(repr, "rx", this->rx.computed); - sp_repr_set_svg_double(repr, "ry", this->ry.computed); + sp_repr_set_svg_length(repr, "cx", cx); + sp_repr_set_svg_length(repr, "cy", cy); + sp_repr_set_svg_length(repr, "rx", rx); + sp_repr_set_svg_length(repr, "ry", ry); repr->setAttribute("r", NULL ); repr->setAttribute("sodipodi:cx", NULL ); repr->setAttribute("sodipodi:cy", NULL ); @@ -324,11 +342,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I std::cerr << "SPGenericEllipse::write: unknown type." << std::endl; } - this->set_shape(); // evaluate SPCurve + set_shape(); // evaluate SPCurve SPShape::write(xml_doc, repr, flags); - // std::cout << "SPGenericEllipse::write: Exit: " << g_quark_to_string(repr->code()) << "\n" << std::endl; return repr; } @@ -339,8 +356,8 @@ const char *SPGenericEllipse::displayName() const case SP_GENERIC_ELLIPSE_UNDEFINED: case SP_GENERIC_ELLIPSE_ARC: - if (this->_isSlice()) { - if (this->_closed) { + if (_isSlice()) { + if (_closed) { return _("Segment"); } else { return _("Arc"); @@ -480,11 +497,11 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform) } if (this->rx._set) { - this->rx = this->rx.computed * sw; + this->rx.scale( sw ); } if (this->ry._set) { - this->ry = this->ry.computed * sh; + this->ry.scale( sh ); } /* Find start in item coords */ @@ -628,10 +645,10 @@ bool SPGenericEllipse::set_elliptical_path_attribute(Inkscape::XML::Node *repr) void SPGenericEllipse::position_set(gdouble x, gdouble y, gdouble rx, gdouble ry) { - this->cx.computed = x; - this->cy.computed = y; - this->rx.computed = rx; - this->ry.computed = ry; + this->cx = x; + this->cy = y; + this->rx = rx; + this->ry = ry; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 0c65bbaed..55857dacf 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -843,7 +843,7 @@ void SPGroup::update_patheffect(bool write) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj && lpeobj->get_lpe()) { - lpeobj->get_lpe()->doBeforeEffect(this); + lpeobj->get_lpe()->doBeforeEffect_impl(this); } } diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 5d181b80a..8c99e9bcf 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -75,18 +75,6 @@ static SPItemView* sp_item_view_list_remove(SPItemView *list, SPItem::SPItem() : SPObject() { - this->sensitive = 0; - this->clip_ref = NULL; - this->avoidRef = NULL; - this->_is_evaluated = false; - this->stop_paint = 0; - this->_evaluated_status = StatusUnknown; - this->bbox_valid = 0; - this->freeze_stroke_width = false; - this->transform_center_x = 0; - this->transform_center_y = 0; - this->display = NULL; - this->mask_ref = NULL; sensitive = TRUE; bbox_valid = FALSE; @@ -96,12 +84,13 @@ SPItem::SPItem() : SPObject() { transform_center_x = 0; transform_center_y = 0; + freeze_stroke_width = false; + _is_evaluated = true; _evaluated_status = StatusUnknown; transform = Geom::identity(); - doc_bbox = Geom::OptRect(); - freeze_stroke_width = false; + // doc_bbox = Geom::OptRect(); display = NULL; @@ -670,54 +659,56 @@ void SPItem::stroke_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) } } -void SPItem::update(SPCtx* /*ctx*/, guint flags) { - SPItem *item = this; - SPItem* object = item; +void SPItem::update(SPCtx* ctx, guint flags) { -// SPObject::onUpdate(ctx, flags); + SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); - // any of the modifications defined in sp-object.h might change bbox, + // Any of the modifications defined in sp-object.h might change bbox, // so we invalidate it unconditionally - item->bbox_valid = FALSE; + bbox_valid = FALSE; + + viewport = ictx->viewport; // Cache viewport - if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) { + if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | + SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG) ) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { - v->arenaitem->setTransform(item->transform); + for (SPItemView *v = display; v != NULL; v = v->next) { + v->arenaitem->setTransform(transform); } } - SPClipPath *clip_path = item->clip_ref ? item->clip_ref->getObject() : NULL; - SPMask *mask = item->mask_ref ? item->mask_ref->getObject() : NULL; + SPClipPath *clip_path = clip_ref ? clip_ref->getObject() : NULL; + SPMask *mask = mask_ref ? mask_ref->getObject() : NULL; if ( clip_path || mask ) { - Geom::OptRect bbox = item->geometricBounds(); + Geom::OptRect bbox = geometricBounds(); if (clip_path) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { + for (SPItemView *v = display; v != NULL; v = v->next) { clip_path->setBBox(v->arenaitem->key(), bbox); } } if (mask) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { + for (SPItemView *v = display; v != NULL; v = v->next) { mask->sp_mask_set_bbox(v->arenaitem->key(), bbox); } } } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { - v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(object->style->opacity.value)); - v->arenaitem->setAntialiasing(object->style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES); - v->arenaitem->setIsolation( object->style->isolation.value ); - v->arenaitem->setBlendMode( object->style->mix_blend_mode.value ); - v->arenaitem->setVisible(!item->isHidden()); + for (SPItemView *v = display; v != NULL; v = v->next) { + v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(style->opacity.value)); + v->arenaitem->setAntialiasing(style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES); + v->arenaitem->setIsolation( style->isolation.value ); + v->arenaitem->setBlendMode( style->mix_blend_mode.value ); + v->arenaitem->setVisible(!isHidden()); } } } /* Update bounding box in user space, used for filter and objectBoundingBox units */ - if (item->style->filter.set && item->display) { - Geom::OptRect item_bbox = item->geometricBounds(); - SPItemView *itemview = item->display; + if (style->filter.set && display) { + Geom::OptRect item_bbox = geometricBounds(); + SPItemView *itemview = display; do { if (itemview->arenaitem) itemview->arenaitem->setItemBounds(item_bbox); @@ -725,8 +716,8 @@ void SPItem::update(SPCtx* /*ctx*/, guint flags) { } // Update libavoid with item geometry (for connector routing). - if (item->avoidRef) - item->avoidRef->handleSettingChange(); + if (avoidRef) + avoidRef->handleSettingChange(); } void SPItem::modified(unsigned int /*flags*/) diff --git a/src/sp-item.h b/src/sp-item.h index b9d71c551..bdc6a0ad9 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -145,6 +145,7 @@ public: Geom::Affine transform; mutable Geom::OptRect doc_bbox; + Geom::Rect viewport; // Cache viewport information SPClipPathReference *clip_ref; SPMaskReference *mask_ref; diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index f059ab531..12d85b3ed 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -263,7 +263,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) { } if (!SP_IS_GROUP(this)) { lpe->doAfterEffect(this); - } + } } } } diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index 30571a8dd..e17d7373c 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -52,22 +52,30 @@ void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) { void SPRect::set(unsigned key, gchar const *value) { /* fixme: We need real error processing some time */ + // We must update the SVGLengths immediately or nodes may be misplaced after they are moved. + double const w = viewport.width(); + double const h = viewport.height(); + double const em = style->font_size.computed; + double const ex = em * 0.5; + switch (key) { case SP_ATTR_X: - this->x.readOrUnset(value); - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x.readOrUnset(value); + this->x.update( ex, em, w ); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_Y: - this->y.readOrUnset(value); - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y.readOrUnset(value); + this->y.update( ex, em, h ); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_WIDTH: if (!this->width.read(value) || this->width.value < 0.0) { this->width.unset(); } - + this->width.update( ex, em, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -75,7 +83,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->height.read(value) || this->height.value < 0.0) { this->height.unset(); } - + this->height.update( ex, em, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -83,7 +91,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->rx.read(value) || this->rx.value <= 0.0) { this->rx.unset(); } - + this->rx.update( ex, em, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -91,7 +99,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->ry.read(value) || this->ry.value <= 0.0) { this->ry.unset(); } - + this->ry.update( ex, em, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -129,19 +137,19 @@ Inkscape::XML::Node * SPRect::write(Inkscape::XML::Document *xml_doc, Inkscape:: repr = xml_doc->createElement("svg:rect"); } - sp_repr_set_svg_double(repr, "width", this->width.computed); - sp_repr_set_svg_double(repr, "height", this->height.computed); + sp_repr_set_svg_length(repr, "width", this->width); + sp_repr_set_svg_length(repr, "height", this->height); if (this->rx._set) { - sp_repr_set_svg_double(repr, "rx", this->rx.computed); + sp_repr_set_svg_length(repr, "rx", this->rx); } if (this->ry._set) { - sp_repr_set_svg_double(repr, "ry", this->ry.computed); + sp_repr_set_svg_length(repr, "ry", this->ry); } - sp_repr_set_svg_double(repr, "x", this->x.computed); - sp_repr_set_svg_double(repr, "y", this->y.computed); + sp_repr_set_svg_length(repr, "x", this->x); + sp_repr_set_svg_length(repr, "y", this->y); this->set_shape(); // evaluate SPCurve SPShape::write(xml_doc, repr, flags); @@ -235,29 +243,29 @@ void SPRect::set_shape() { /* fixme: Think (Lauris) */ void SPRect::setPosition(gdouble x, gdouble y, gdouble width, gdouble height) { - this->x.computed = x; - this->y.computed = y; - this->width.computed = width; - this->height.computed = height; + this->x = x; + this->y = y; + this->width = width; + this->height = height; this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } void SPRect::setRx(bool set, gdouble value) { - this->rx._set = set; + this->rx._set = set; if (set) { - this->rx.computed = value; + this->rx = value; } this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } void SPRect::setRy(bool set, gdouble value) { - this->ry._set = set; + this->ry._set = set; if (set) { - this->ry.computed = value; + this->ry = value; } this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -289,16 +297,16 @@ Geom::Affine SPRect::set_transform(Geom::Affine const& xform) { ret[3] = 1.0; } - /* fixme: Would be nice to preserve units here */ - this->width = this->width.computed * sw; - this->height = this->height.computed * sh; + /* Preserve units */ + this->width.scale( sw ); + this->height.scale( sh ); if (this->rx._set) { - this->rx = this->rx.computed * sw; + this->rx.scale( sw ); } if (this->ry._set) { - this->ry = this->ry.computed * sh; + this->ry.scale( sh ); } /* Find start in item coords */ @@ -336,15 +344,12 @@ gdouble SPRect::vectorStretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform void SPRect::setVisibleRx(gdouble rx) { if (rx == 0) { - this->rx.computed = 0; - this->rx._set = false; + this->rx.unset(); } else { - this->rx.computed = rx / SPRect::vectorStretch( + this->rx = rx / SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), this->i2doc_affine()); - - this->rx._set = true; } this->updateRepr(); @@ -352,15 +357,12 @@ void SPRect::setVisibleRx(gdouble rx) { void SPRect::setVisibleRy(gdouble ry) { if (ry == 0) { - this->ry.computed = 0; - this->ry._set = false; + this->ry.unset(); } else { - this->ry.computed = ry / SPRect::vectorStretch( + this->ry = ry / SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), this->i2doc_affine()); - - this->ry._set = true; } this->updateRepr(); @@ -418,37 +420,33 @@ void SPRect::compensateRxRy(Geom::Affine xform) { // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform if ((this->rx._set && !this->ry._set) || (this->ry._set && !this->rx._set)) { gdouble r = MAX(this->rx.computed, this->ry.computed); - this->rx.computed = r / eX; - this->ry.computed = r / eY; + this->rx = r / eX; + this->ry = r / eY; } else { - this->rx.computed = this->rx.computed / eX; - this->ry.computed = this->ry.computed / eY; + this->rx = this->rx.computed / eX; + this->ry = this->ry.computed / eY; } // Note that a radius may end up larger than half-side if the rect is scaled down; // that's ok because this preserves the intended radii in case the rect is enlarged again, // and set_shape will take care of trimming too large radii when generating d= - - this->rx._set = this->ry._set = true; } void SPRect::setVisibleWidth(gdouble width) { - this->width.computed = width / SPRect::vectorStretch( + this->width = width / SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), this->i2doc_affine()); - this->width._set = true; - this->updateRepr(); + this->updateRepr(); } void SPRect::setVisibleHeight(gdouble height) { - this->height.computed = height / SPRect::vectorStretch( + this->height = height / SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), this->i2doc_affine()); - this->height._set = true; this->updateRepr(); } diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 8bb3e9897..46279cbce 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -1727,7 +1727,9 @@ void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool if ( !updating ) { // delete original, apply the transform to the offset + const char *n_id = item->getRepr()->attribute("id"); item->deleteObject(false); + repr->setAttribute("id", n_id); nitem->doWriteTransform(repr, transform); } diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index ea235b2e4..edbc59c36 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -14,6 +14,7 @@ #include <cstring> #include <string> #include <glib.h> +#include <iostream> #include "svg.h" #include "stringstream.h" @@ -462,6 +463,51 @@ unsigned int sp_svg_length_read_ldd(gchar const *str, SVGLength::Unit *unit, dou return r; } +std::string const SVGLength::write() +{ + return sp_svg_length_write_with_units(*this); +} + +void SVGLength::set(SVGLength::Unit u, float v) +{ + _set = true; + unit = u; + Glib::ustring hack("px"); + switch( unit ) { + case NONE: + case PX: + case EM: + case EX: + case PERCENT: + break; + case PT: + hack = "pt"; + break; + case PC: + hack = "pc"; + break; + case MM: + hack = "pt"; + break; + case CM: + hack = "pt"; + break; + case INCH: + hack = "pt"; + break; + case FOOT: + hack = "pt"; + break; + case MITRE: + hack = "m"; + break; + default: + break; + } + value = v; + computed = Inkscape::Util::Quantity::convert(v, hack, "px"); +} + void SVGLength::set(SVGLength::Unit u, float v, float c) { _set = true; @@ -478,6 +524,12 @@ void SVGLength::unset(SVGLength::Unit u, float v, float c) computed = c; } +void SVGLength::scale(double scale) +{ + value *= scale; + computed *= scale; +} + void SVGLength::update(double em, double ex, double scale) { if (unit == EM) { diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 1e6b4c96c..84056dd5f 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -57,9 +57,13 @@ public: bool read(char const *str); void readOrUnset(char const *str, Unit u = NONE, float v = 0, float c = 0); bool readAbsolute(char const *str); - void set(Unit u, float v, float c); + std::string const write(); + // To set 'v' use '=' + void set(Unit u, float v); // Sets computed value based on u and v. + void set(Unit u, float v, float c); // Sets all three values. void unset(Unit u = NONE, float v = 0, float c = 0); - void update(double em, double ex, double scale); + void scale(double scale); // Scales length (value, computed), leaving unit alone. + void update(double em, double ex, double scale); // Updates computed value }; #endif // SEEN_SP_SVG_LENGTH_H diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index f324f285d..c381ed755 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -1473,6 +1473,7 @@ void DocumentProperties::update() } _page_sizer.setDim(Inkscape::Util::Quantity(doc_w, doc_w_unit), Inkscape::Util::Quantity(doc_h, doc_h_unit)); _page_sizer.updateFitMarginsUI(nv->getRepr()); + _page_sizer.updateScaleUI(); //-----------------------------------------------------------guide page @@ -1655,6 +1656,8 @@ void DocumentProperties::onRemoveGrid() } /** Callback for document unit change. */ +/* This should not effect anything in the SVG tree (other than "inkscape:document-units"). + This should only effect values displayed in the GUI. */ void DocumentProperties::onDocUnitChange() { SPDocument *doc = SP_ACTIVE_DOCUMENT; @@ -1680,6 +1683,8 @@ void DocumentProperties::onDocUnitChange() os << doc_unit->abbr; repr->setAttribute("inkscape:document-units", os.str().c_str()); + _page_sizer.updateScaleUI(); + // Disable changing of SVG Units. The intent here is to change the units in the UI, not the units in SVG. // This code should be moved (and fixed) once we have an "SVG Units" setting that sets what units are used in SVG data. #if 0 diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp index c3bc2d52c..0a6c792dc 100644 --- a/src/ui/object-edit.cpp +++ b/src/ui/object-edit.cpp @@ -154,12 +154,9 @@ RectKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*orig 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 - s[Geom::X], 0.0, temp); - rect->rx._set = rect->ry._set = true; - + rect->rx = rect->ry = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp); } else { - rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0); - rect->rx._set = true; + rect->rx = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0); } update_knot(); @@ -207,20 +204,17 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig 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(s[Geom::Y] - rect->y.computed, 0.0, temp); - rect->ry._set = rect->rx._set = true; + rect->rx = rect->ry = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp); } else { if (!rect->rx._set || rect->rx.computed == 0) { - rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, - 0.0, - MIN(rect->height.computed / 2.0, rect->width.computed / 2.0)); + rect->ry = 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(s[Geom::Y] - rect->y.computed, - 0.0, - rect->height.computed / 2.0); + rect->ry = CLAMP(s[Geom::Y] - rect->y.computed, + 0.0, + rect->height.computed / 2.0); } - - rect->ry._set = true; } update_knot(); @@ -250,12 +244,10 @@ static void sp_rect_clamp_radii(SPRect *rect) { // clamp rounding radii so that they do not exceed width/height if (2 * rect->rx.computed > rect->width.computed) { - rect->rx.computed = 0.5 * rect->width.computed; - rect->rx._set = true; + rect->rx = 0.5 * rect->width.computed; } if (2 * rect->ry.computed > rect->height.computed) { - rect->ry.computed = 0.5 * rect->height.computed; - rect->ry._set = true; + rect->ry = 0.5 * rect->height.computed; } } @@ -298,16 +290,16 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig + minx / ratio, 0); + rect->height = 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)), state); minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig, 0); + rect->height = MAX(h_orig, 0); } - rect->width.computed = MAX(w_orig + minx, 0); + rect->width = MAX(w_orig + minx, 0); } else { // snap to vertical or diagonal @@ -317,27 +309,24 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig + miny * ratio, 0); + rect->width = 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)), state); // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig, 0); + rect->width = MAX(w_orig, 0); } - rect->height.computed = MAX(h_orig + miny, 0); + rect->height = MAX(h_orig + miny, 0); } - rect->width._set = rect->height._set = true; - } else { // move freely s = snap_knot_position(p, state); - 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; + rect->width = MAX(s[Geom::X] - rect->x.computed, 0); + rect->height = MAX(s[Geom::Y] - rect->y.computed, 0); } sp_rect_clamp_radii(rect); @@ -394,19 +383,19 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //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); + rect->y = MIN(origin[Geom::Y] + minx / ratio, opposite_y); + rect->height = 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)), state); minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->y.computed = MIN(origin[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig, 0); + rect->y = MIN(origin[Geom::Y], opposite_y); + rect->height = MAX(h_orig, 0); } - rect->x.computed = MIN(s[Geom::X], opposite_x); - rect->width.computed = MAX(w_orig - minx, 0); + rect->x = MIN(s[Geom::X], opposite_x); + rect->width = MAX(w_orig - minx, 0); } else { // snap to vertical or diagonal if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) { @@ -415,34 +404,31 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin // Dead assignment: Value stored to 'minx' is never read //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); + rect->x = MIN(origin[Geom::X] + miny * ratio, opposite_x); + rect->width = 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)), state); // Dead assignment: Value stored to 'minx' is never read //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->x = MIN(origin[Geom::X], opposite_x); + rect->width = MAX(w_orig, 0); } - rect->y.computed = MIN(s[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig - miny, 0); + rect->y = MIN(s[Geom::Y], opposite_y); + rect->height = MAX(h_orig - miny, 0); } - rect->width._set = rect->height._set = rect->x._set = rect->y._set = true; - } else { // move freely s = snap_knot_position(p, state); 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[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; + rect->x = MIN(s[Geom::X], opposite_x); + rect->y = MIN(s[Geom::Y], opposite_y); + rect->width = MAX(w_orig - minx, 0); + rect->height = MAX(h_orig - miny, 0); } sp_rect_clamp_radii(rect); @@ -917,10 +903,10 @@ ArcKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p, state); - ge->rx.computed = fabs( ge->cx.computed - s[Geom::X] ); + ge->rx = fabs( ge->cx.computed - s[Geom::X] ); if ( state & GDK_CONTROL_MASK ) { - ge->ry.computed = ge->rx.computed; + ge->ry = ge->rx.computed; } item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -942,7 +928,7 @@ ArcKnotHolderEntityRX::knot_click(unsigned int state) g_assert(ge != NULL); if (state & GDK_CONTROL_MASK) { - ge->ry.computed = ge->rx.computed; + ge->ry = ge->rx.computed; ge->updateRepr(); } } @@ -955,10 +941,10 @@ ArcKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p, state); - ge->ry.computed = fabs( ge->cy.computed - s[Geom::Y] ); + ge->ry = fabs( ge->cy.computed - s[Geom::Y] ); if ( state & GDK_CONTROL_MASK ) { - ge->rx.computed = ge->ry.computed; + ge->rx = ge->ry.computed; } item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -980,7 +966,7 @@ ArcKnotHolderEntityRY::knot_click(unsigned int state) g_assert(ge != NULL); if (state & GDK_CONTROL_MASK) { - ge->rx.computed = ge->ry.computed; + ge->rx = ge->ry.computed; ge->updateRepr(); } } diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 790270d91..ec7d10e13 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -439,39 +439,41 @@ static bool sp_spray_recursive(SPDesktop *desktop, } i++; } - SPDocument *doc = parent_item->document; - Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = parent_item->getRepr(); - Inkscape::XML::Node *parent = old_repr->parent(); - - Geom::OptRect a = parent_item->documentVisualBounds(); - if (a) { - if (_fid <= population) { // Rules the population of objects sprayed - // Duplicates the parent item - Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); - parent->appendChild(copy); - SPObject *new_obj = doc->getObjectByRepr(copy); - item_copied = dynamic_cast<SPItem *>(new_obj); - - // Move around the cursor - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); - - Geom::Point center = parent_item->getCenter(); - sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); - sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); - sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); - sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); - - // Union and duplication - selection->clear(); - selection->add(item_copied); - if (unionResult) { // No need to add the very first item (initialized with NULL). - selection->add(unionResult); + if (parent_item) { + SPDocument *doc = parent_item->document; + Inkscape::XML::Document* xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *old_repr = parent_item->getRepr(); + Inkscape::XML::Node *parent = old_repr->parent(); + + Geom::OptRect a = parent_item->documentVisualBounds(); + if (a) { + if (_fid <= population) { // Rules the population of objects sprayed + // Duplicates the parent item + Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + parent->appendChild(copy); + SPObject *new_obj = doc->getObjectByRepr(copy); + item_copied = dynamic_cast<SPItem *>(new_obj); + + // Move around the cursor + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + + Geom::Point center = parent_item->getCenter(); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); + sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); + sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + + // Union and duplication + selection->clear(); + selection->add(item_copied); + if (unionResult) { // No need to add the very first item (initialized with NULL). + selection->add(unionResult); + } + sp_selected_path_union_skip_undo(selection, selection->desktop()); + selection->add(parent_item); + Inkscape::GC::release(copy); + did = true; } - sp_selected_path_union_skip_undo(selection, selection->desktop()); - selection->add(parent_item); - Inkscape::GC::release(copy); - did = true; } } #endif diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index 8c3b44bf5..8e647ebb4 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -26,6 +26,7 @@ #include <cmath> #include <string> #include <string.h> +#include <sstream> #include <vector> #include <glibmm/i18n.h> @@ -240,6 +241,8 @@ PageSizer::PageSizer(Registry & _wr) _marginRight( _("Ri_ght:"), _("Right margin"), "fit-margin-right", _wr), _marginBottom( _("Botto_m:"), _("Bottom margin"), "fit-margin-bottom", _wr), _lockMarginUpdate(false), + _scaleX(_("Scale _x:"), _("Scale X"), "scale-x", _wr), + _lockScaleUpdate(false), _widgetRegistry(&_wr) { // set precision of scalar entry boxes @@ -250,6 +253,8 @@ PageSizer::PageSizer(Registry & _wr) _marginLeft.setDigits(5); _marginRight.setDigits(5); _marginBottom.setDigits(5); + _scaleX.setDigits(5); + _scaleX.setRange( 0.00001, 100000 ); _wr.setUpdating (false); //# Set up the Paper Size combo box @@ -318,6 +323,7 @@ PageSizer::PageSizer(Registry & _wr) } _wr.setUpdating (false); + //## Set up custom size frame _customFrame.set_label(_("Custom size")); pack_start (_customFrame, false, false, 0); @@ -419,6 +425,34 @@ PageSizer::PageSizer(Registry & _wr) _fitPageButton.set_label(_("_Resize page to drawing or selection")); _fitPageButton.set_tooltip_text(_("Resize the page to fit the current selection, or the entire drawing if there is no selection")); + _scaleFrame.set_label(_("Scale")); + pack_start (_scaleFrame, false, false, 0); + _scaleFrame.add(_scaleTable); + + _scaleTable.set_border_width(4); + +#if WITH_GTKMM_3_0 + _scaleTable.set_row_spacing(4); + _scaleTable.set_column_spacing(4); + + _dimensionWidth.set_hexpand(); + _dimensionWidth.set_vexpand(); + _scaleTable.attach(_scaleX, 0, 0, 1, 1); + + _dimensionUnits.set_hexpand(); + _dimensionUnits.set_vexpand(); + _scaleTable.attach(_scaleLabel, 1, 0, 1, 1); +#else + _scaleTable.resize(2, 1); + _scaleTable.set_row_spacings(4); + _scaleTable.set_col_spacings(4); + _scaleTable.attach(_scaleX, 0,1, 0,1); + _scaleTable.attach(_scaleLabel, 1,2, 0,1); +#endif + + _wr.setUpdating (true); + updateScaleUI(); + _wr.setUpdating (false); } @@ -444,7 +478,7 @@ PageSizer::init () _changedh_connection = _dimensionHeight.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed)); _changedu_connection = _dimensionUnits.getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &PageSizer::on_units_changed)); _fitPageButton.signal_clicked().connect(sigc::mem_fun(*this, &PageSizer::fire_fit_canvas_to_selection_or_drawing)); - + _changeds_connection = _scaleX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_scale_changed)); show_all_children(); } @@ -512,6 +546,7 @@ PageSizer::setDim (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h, bool _dimensionHeight.setUnit(h.unit->abbr); _dimensionHeight.setValue (h.quantity); + _paper_size_list_connection.unblock(); _landscape_connection.unblock(); _portrait_connection.unblock(); @@ -701,6 +736,60 @@ PageSizer::on_landscape() } } + +/** + * Update scale widgets + */ +void +PageSizer::updateScaleUI() +{ + + if (_lockScaleUpdate) { + return; + } + + static bool _called = false; + if (_called) { + return; + } + + _called = true; + + _changeds_connection.block(); + + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt) { + SPDocument *doc = dt->getDocument(); + Geom::Scale scale = doc->getDocumentScale(); + + SPNamedView *nv = dt->getNamedView(); + + std::stringstream ss; + ss << _("User units per ") << nv->display_units->abbr << "." ; + _scaleLabel.set_text( ss.str() ); + + double scaleX_inv = + Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units ); + if( scaleX_inv > 0 ) { + _scaleX.setValue(1.0/scaleX_inv); + } else { + // Should never happen + std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleX_inv << std::endl; + _scaleX.setValue(1.0); + } + + } else { + // Should never happen + std::cerr << "PageSizer::updateScaleUI(): No active desktop." << std::endl; + _scaleLabel.set_text( "Unknown scale" ); + } + + _changeds_connection.unblock(); + + _called = false; +} + + /** * Callback for the dimension widgets */ @@ -722,6 +811,32 @@ PageSizer::on_units_changed() true, false); } +/** + * Callback for scale widgets + */ +void +PageSizer::on_scale_changed() +{ + if (_widgetRegistry->isUpdating()) return; + + double value = _scaleX.getValue(); + if( value > 0 ) { + + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt) { + SPDocument *doc = dt->getDocument(); + SPNamedView *nv = dt->getNamedView(); + + double scaleX_inv = Inkscape::Util::Quantity(1.0/value, nv->display_units ).value("px"); + + _lockScaleUpdate = true; + doc->setDocumentScale( 1.0/scaleX_inv ); + _lockScaleUpdate = false; + DocumentUndo::done(doc, SP_VERB_NONE, _("Set page scale")); + } + } +} + } // namespace Widget } // namespace UI } // namespace Inkscape diff --git a/src/ui/widget/page-sizer.h b/src/ui/widget/page-sizer.h index bed117e5a..f9a72d9f3 100644 --- a/src/ui/widget/page-sizer.h +++ b/src/ui/widget/page-sizer.h @@ -169,6 +169,11 @@ public: */ void updateFitMarginsUI(Inkscape::XML::Node *nv_repr); + /** + * Updates the scale widgets. (Just changes the values of the ui widgets.) + */ + void updateScaleUI(); + protected: /** @@ -250,12 +255,26 @@ protected: Gtk::Button _fitPageButton; bool _lockMarginUpdate; + // Document scale + Gtk::Frame _scaleFrame; +#if WITH_GTKMM_3_0 + Gtk::Grid _scaleTable; +#else + Gtk::Table _scaleTable; +#endif + + Gtk::Label _scaleLabel; + RegisteredScalar _scaleX; + bool _lockScaleUpdate; + //callback void on_value_changed(); void on_units_changed(); + void on_scale_changed(); sigc::connection _changedw_connection; sigc::connection _changedh_connection; sigc::connection _changedu_connection; + sigc::connection _changeds_connection; Registry *_widgetRegistry; diff --git a/src/widgets/box3d-toolbar.cpp b/src/widgets/box3d-toolbar.cpp index 26e914070..31b897ced 100644 --- a/src/widgets/box3d-toolbar.cpp +++ b/src/widgets/box3d-toolbar.cpp @@ -193,15 +193,15 @@ static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObj Inkscape::GC::anchor(persp_repr); sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl); sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl); - } - SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); + SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - box3d_resync_toolbar(persp_repr, tbl); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); + box3d_resync_toolbar(persp_repr, tbl); + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + } } } diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 12280ea5a..7c5d2d6fc 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -32,6 +32,7 @@ #include <2geom/point.h> #include "svg/stringstream.h" #include "svg/css-ostringstream.h" +#include "svg/svg-length.h" #include "xml/repr.h" #include "xml/repr-sorting.h" @@ -502,6 +503,20 @@ unsigned int sp_repr_set_svg_double(Inkscape::XML::Node *repr, gchar const *key, return true; } +/** + * For attributes where an exponent is allowed. + * + * Not suitable for property attributes. + */ +unsigned int sp_repr_set_svg_length(Inkscape::XML::Node *repr, gchar const *key, SVGLength &val) +{ + g_return_val_if_fail(repr != NULL, FALSE); + g_return_val_if_fail(key != NULL, FALSE); + + repr->setAttribute(key, val.write()); + return true; +} + unsigned sp_repr_set_point(Inkscape::XML::Node *repr, gchar const *key, Geom::Point const & val) { g_return_val_if_fail(repr != NULL, FALSE); diff --git a/src/xml/repr.h b/src/xml/repr.h index e1d7fdfd6..c3ba40e45 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -30,6 +30,7 @@ #define SP_DC_NS_URI "http://purl.org/dc/elements/1.1/" class SPCSSAttr; +class SVGLength; namespace Inkscape { namespace IO { @@ -115,6 +116,7 @@ unsigned sp_repr_set_boolean(Inkscape::XML::Node *repr, char const *key, unsigne unsigned sp_repr_set_int(Inkscape::XML::Node *repr, char const *key, int val); unsigned sp_repr_set_css_double(Inkscape::XML::Node *repr, char const *key, double val); unsigned sp_repr_set_svg_double(Inkscape::XML::Node *repr, char const *key, double val); +unsigned sp_repr_set_svg_length(Inkscape::XML::Node *repr, char const *key, SVGLength &val); unsigned sp_repr_set_point(Inkscape::XML::Node *repr, char const *key, Geom::Point const & val); unsigned sp_repr_get_point(Inkscape::XML::Node *repr, char const *key, Geom::Point *val); |
