diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-style.cpp | 26 | ||||
| -rw-r--r-- | src/extension/internal/cairo-render-context.cpp | 28 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.cpp | 58 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.cpp | 53 | ||||
| -rw-r--r-- | src/extension/internal/javafx-out.cpp | 31 | ||||
| -rw-r--r-- | src/extension/internal/latex-pstricks.cpp | 10 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.cpp | 33 | ||||
| -rw-r--r-- | src/extension/internal/wmf-print.cpp | 49 | ||||
| -rw-r--r-- | src/livarot/PathCutting.cpp | 35 | ||||
| -rw-r--r-- | src/live_effects/lpe-dash-stroke.cpp | 437 | ||||
| -rw-r--r-- | src/live_effects/lpe-dash-stroke.h | 31 | ||||
| -rw-r--r-- | src/object/sp-item.cpp | 5 | ||||
| -rw-r--r-- | src/object/sp-item.h | 2 | ||||
| -rw-r--r-- | src/preferences-skeleton.h | 1 | ||||
| -rw-r--r-- | src/style-internal.cpp | 32 | ||||
| -rw-r--r-- | src/style-internal.h | 6 | ||||
| -rw-r--r-- | src/svg/svg-length.h | 7 | ||||
| -rw-r--r-- | src/ui/dialog/inkscape-preferences.cpp | 6 | ||||
| -rw-r--r-- | src/ui/dialog/inkscape-preferences.h | 4 | ||||
| -rw-r--r-- | src/widgets/dash-selector.cpp | 13 | ||||
| -rw-r--r-- | src/widgets/stroke-style.cpp | 40 |
21 files changed, 619 insertions, 288 deletions
diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index cec6de4d3..564a6209b 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -11,6 +11,9 @@ #include "display/nr-style.h" #include "style.h" +#include "util/units.h" +#include "inkscape.h" +#include "object/sp-namedview.h" #include "object/sp-paint-server.h" #include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!) #include "display/drawing-context.h" @@ -218,10 +221,29 @@ void NRStyle::set(SPStyle *style, SPStyle *context_style) n_dash = style->stroke_dasharray.values.size(); if (n_dash != 0) { - dash_offset = style->stroke_dashoffset.value; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } + Geom::Rect vbox = document->getViewBox(); + if (style->stroke_dashoffset.unit == SVGLength::NONE) { + dash_offset = style->stroke_dashoffset.value; + } else if (style->stroke_dashoffset.unit == SVGLength::PERCENT) { + dash_offset = vbox.width() * style->stroke_dashoffset.value; + } else { + dash_offset = Inkscape::Util::Quantity::convert(style->stroke_dashoffset.computed, "px", display_unit.c_str()); + } dash = new double[n_dash]; for (unsigned int i = 0; i < n_dash; ++i) { - dash[i] = style->stroke_dasharray.values[i]; + if (style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dash[i] = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dash[i] = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dash[i] = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } } } else { dash_offset = 0.0; diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index da0797600..6d2267fde 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -48,7 +48,8 @@ #include "object/sp-pattern.h" #include "object/sp-mask.h" #include "object/sp-clippath.h" - +#include "object/sp-namedview.h" +#include "inkscape.h" #include "util/units.h" #ifdef WIN32 #include "libnrtype/FontFactory.h" // USE_PANGO_WIN32 @@ -1435,10 +1436,31 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p { size_t ndashes = style->stroke_dasharray.values.size(); double* dashes =(double*)malloc(ndashes*sizeof(double)); + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for( unsigned i = 0; i < ndashes; ++i ) { - dashes[i] = style->stroke_dasharray.values[i]; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dashes[i] = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dashes[i] = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dashes[i] = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } + } + double dash_offset = 0; + if (style->stroke_dashoffset.unit == SVGLength::NONE) { + dash_offset = style->stroke_dashoffset.value; + } else if (style->stroke_dashoffset.unit == SVGLength::PERCENT) { + dash_offset = vbox.width() * style->stroke_dashoffset.value ; + } else { + dash_offset = Inkscape::Util::Quantity::convert(style->stroke_dashoffset.computed, "px", display_unit.c_str()); } - cairo_set_dash(_cr, dashes, ndashes, style->stroke_dashoffset.value); + cairo_set_dash(_cr, dashes, ndashes, dash_offset); free(dashes); } else { cairo_set_dash(_cr, nullptr, 0, 0.0); // disable dashing diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index d0556e467..79645466f 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -35,6 +35,7 @@ #include "document.h" #include "object/sp-root.h" #include "object/sp-path.h" +#include "object/sp-namedview.h" #include "print.h" #include "extension/system.h" #include "extension/print.h" @@ -45,9 +46,11 @@ #include "display/drawing-item.h" #include "clear-n_.h" #include "svg/svg.h" +#include "svg/svg-length.h" #include "util/units.h" // even though it is included indirectly by emf-inout.h #include "inkscape.h" // even though it is included indirectly by emf-inout.h + #include "emf-print.h" #include "emf-inout.h" @@ -981,10 +984,24 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) !d->dc[d->level].style.stroke_dasharray.values.empty() ) { tmp_style << "stroke-dasharray:"; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) { if (i) tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dasharray.values[i]; + if(d->dc[d->level].style.stroke_dasharray.values[i].unit == SVGLength::NONE) { + tmp_style << d->dc[d->level].style.stroke_dasharray.values[i].value; + } else if (d->dc[d->level].style.stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + tmp_style << vbox.width() * d->dc[d->level].style.stroke_dasharray.values[i].value; + } else { + tmp_style << Inkscape::Util::Quantity::convert(d->dc[d->level].style.stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } + } tmp_style << ";"; tmp_style << "stroke-dashoffset:0;"; @@ -1097,17 +1114,21 @@ Emf::select_pen(PEMF_CALLBACK_DATA d, int index) int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK); if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) d->dc[d->level].style.stroke_dasharray.values.clear(); + SVGLength svglength; + svglength.read("1"); if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + svglength.read("3"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + svglength.read("1"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } d->dc[d->level].style.stroke_dasharray.set = 1; @@ -1183,7 +1204,9 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) d->dc[d->level].style.stroke_dasharray.values.clear(); for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); - d->dc[d->level].style.stroke_dasharray.values.push_back(dash_length); + SVGLength svglength; + svglength.set(SVGLength::PX, dash_length); + d->dc[d->level].style.stroke_dasharray.values.push_back(svglength); } d->dc[d->level].style.stroke_dasharray.set = 1; } else { @@ -1200,17 +1223,24 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK); if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) d->dc[d->level].style.stroke_dasharray.values.clear(); + SVGLength svglength; if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); + svglength.read("3"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + svglength.read("2"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); + svglength.read("1"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + svglength.read("2"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); + svglength.read("1"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + svglength.read("2"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } d->dc[d->level].style.stroke_dasharray.set = 1; diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 254000db3..459794654 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -38,7 +38,7 @@ #include "helper/geom.h" #include "helper/geom-curves.h" #include "util/units.h" - +#include "inkscape.h" #include "inkscape-version.h" #include "extension/system.h" @@ -55,6 +55,7 @@ #include "object/sp-root.h" #include "object/sp-shape.h" #include "object/sp-clippath.h" +#include "object/sp-namedview.h" #include "style.h" #include "display/cairo-utils.h" @@ -695,17 +696,32 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) } else { unsigned i = 0; while ((linestyle != U_PS_USERSTYLE) && (i < style->stroke_dasharray.values.size())) { - if (style->stroke_dasharray.values[i] > 0.00000001) { + if (style->stroke_dasharray.values[i].computed > 0.00000001) { linestyle = U_PS_USERSTYLE; } i++; } - + if (linestyle == U_PS_USERSTYLE) { + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } n_dash = style->stroke_dasharray.values.size(); dash = new uint32_t[n_dash]; for (i = 0; i < n_dash; i++) { - dash[i] = MAX(1, (uint32_t) round(scale * style->stroke_dasharray.values[i] * PX2WORLD)); + double dashval = 0; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dashval = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dashval = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dashval = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } + dash[i] = MAX(1, (uint32_t) round(scale * dashval * PX2WORLD)); } } } @@ -1455,10 +1471,25 @@ unsigned int PrintEmf::stroke( } tlength = length(tmp_pathpw, 0.1); tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); - + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } // go around the dash array repeatedly until the entire path is consumed (but not beyond). while (slength < tlength) { - elength = slength + style->stroke_dasharray.values[i++]; + SVGLength i1 = style->stroke_dasharray.values[i++]; + double dashval = 0; + if(i1.unit == SVGLength::NONE) { + dashval = i1.value; + } else if (i1.unit == SVGLength::PERCENT) { + dashval = vbox.width() * i1.value; + } else { + dashval = Inkscape::Util::Quantity::convert(i1.computed, "px", display_unit.c_str()); + } + elength = slength + dashval; if (elength > tlength) { elength = tlength; } @@ -1469,7 +1500,15 @@ unsigned int PrintEmf::stroke( first_frag = fragment; } slength = elength; - slength += style->stroke_dasharray.values[i++]; // the gap + SVGLength i2 = style->stroke_dasharray.values[i++]; + if(i2.unit == SVGLength::NONE) { + dashval = i2.value; + } else if (i2.unit == SVGLength::PERCENT) { + dashval = vbox.width() * i2.value; + } else { + dashval = Inkscape::Util::Quantity::convert(i2.computed, "px", display_unit.c_str()); + } + slength += dashval; // the gap if (i >= n_dash) { i = 0; } diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp index ad8fa855d..9b795ea21 100644 --- a/src/extension/internal/javafx-out.cpp +++ b/src/extension/internal/javafx-out.cpp @@ -40,7 +40,9 @@ #include "object/sp-path.h" #include "object/sp-linear-gradient.h" #include "object/sp-radial-gradient.h" +#include "object/sp-namedview.h" #include "style.h" +#include "util/units.h" #include <string> #include <cstdio> @@ -435,15 +437,38 @@ bool JavaFXOutput::doStyle(SPStyle *style) out(" strokeLineJoin: %s\n", getStrokeLineJoin(linejoin).c_str()); out(" strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value)); if (style->stroke_dasharray.set) { + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } + double dash_offset = 0; + if (style->stroke_dashoffset.unit == SVGLength::NONE) { + dash_offset = style->stroke_dashoffset.value; + } else if (style->stroke_dashoffset.unit == SVGLength::PERCENT) { + dash_offset = vbox.width() * style->stroke_dashoffset.value; + } else { + dash_offset = Inkscape::Util::Quantity::convert(style->stroke_dashoffset.computed, "px", display_unit.c_str()); + } if (style->stroke_dashoffset.set) { - out(" strokeDashOffset: %s\n", DSTR(style->stroke_dashoffset.value)); + out(" strokeDashOffset: %s\n", DSTR(dash_offset)); } out(" strokeDashArray: [ "); for(unsigned i = 0; i < style->stroke_dasharray.values.size(); i++ ) { + double dash = 0; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dash = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dash = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dash = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } if (i > 0) { - out(", %.2lf", style->stroke_dasharray.values[i]); + out(", %.2lf", dash); }else { - out(" %.2lf", style->stroke_dasharray.values[i]); + out(" %.2lf", dash); } } out(" ]\n"); diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp index f3bf06708..664ec0310 100644 --- a/src/extension/internal/latex-pstricks.cpp +++ b/src/extension/internal/latex-pstricks.cpp @@ -23,8 +23,10 @@ #include "util/units.h" #include "helper/geom-curves.h" +#include "object/sp-namedview.h" #include "extension/print.h" #include "extension/system.h" +#include "inkscape.h" #include "inkscape-version.h" #include "io/sys.h" #include "latex-pstricks.h" @@ -240,11 +242,17 @@ unsigned int PrintLatex::stroke(Inkscape::Extension::Print * /*mod*/, if (style->stroke_dasharray.set && !style->stroke_dasharray.values.empty()) { os << ",linestyle=dashed,dash="; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (unsigned i = 0; i < style->stroke_dasharray.values.size(); i++) { if ((i)) { os << " "; } - os << style->stroke_dasharray.values[i]; + os << Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); } } diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 72d44e123..a3df20903 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -44,8 +44,10 @@ #include "extension/output.h" #include "display/drawing.h" #include "display/drawing-item.h" +#include "object/sp-namedview.h" #include "clear-n_.h" #include "svg/svg.h" +#include "svg/svg-length.h" #include "util/units.h" // even though it is included indirectly by wmf-inout.h #include "inkscape.h" // even though it is included indirectly by wmf-inout.h @@ -889,10 +891,23 @@ Wmf::output_style(PWMF_CALLBACK_DATA d) !d->dc[d->level].style.stroke_dasharray.values.empty()) { tmp_style << "stroke-dasharray:"; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) { if (i) tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dasharray.values[i]; + if(d->dc[d->level].style.stroke_dasharray.values[i].unit == SVGLength::NONE) { + tmp_style << d->dc[d->level].style.stroke_dasharray.values[i].value; + } else if (d->dc[d->level].style.stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + tmp_style << vbox.width() * d->dc[d->level].style.stroke_dasharray.values[i].value; + } else { + tmp_style << Inkscape::Util::Quantity::convert(d->dc[d->level].style.stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } } tmp_style << ";"; tmp_style << "stroke-dashoffset:0;"; @@ -987,17 +1002,21 @@ Wmf::select_pen(PWMF_CALLBACK_DATA d, int index) int penstyle = (up.Style & U_PS_STYLE_MASK); if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) d->dc[d->level].style.stroke_dasharray.values.clear(); + SVGLength svglength; if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + svglength.read("3"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + svglength.read("1"); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } + svglength.read("1"); if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); - d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); + d->dc[d->level].style.stroke_dasharray.values.push_back( svglength ); } d->dc[d->level].style.stroke_dasharray.set = 1; diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 613ae3f04..dbcfebfc5 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -40,6 +40,7 @@ #include "helper/geom-curves.h" #include "inkscape-version.h" +#include "inkscape.h" #include "util/units.h" @@ -55,6 +56,7 @@ #include "object/sp-linear-gradient.h" #include "object/sp-root.h" #include "object/sp-item.h" +#include "object/sp-namedview.h" #include "splivarot.h" // pieces for union on shapes #include <2geom/svg-path-parser.h> // to get from SVG text to Geom::Path @@ -602,8 +604,23 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) int mark_short=INT_MAX; int mark_long =0; int i; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (i=0;i<n_dash;i++) { - int mark = style->stroke_dasharray.values[i]; + double dashval = 0; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dashval = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dashval = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dashval = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } + int mark = (int)dashval; if (mark>mark_long) { mark_long = mark; } if (mark<mark_short) { mark_short = mark; } } @@ -887,10 +904,25 @@ unsigned int PrintWmf::stroke( } tlength = length(tmp_pathpw, 0.1); tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); - // go around the dash array repeatedly until the entire path is consumed (but not beyond). + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } while (slength < tlength) { - elength = slength + style->stroke_dasharray.values[i++]; + SVGLength i1 = style->stroke_dasharray.values[i++]; + double dashval = 0; + if(i1.unit == SVGLength::NONE) { + dashval = i1.value; + } else if (i1.unit == SVGLength::PERCENT) { + dashval = vbox.width() * i1.value; + } else { + dashval = Inkscape::Util::Quantity::convert(i1.computed, "px", display_unit.c_str()); + } + elength = slength + dashval; if (elength > tlength) { elength = tlength; } @@ -900,8 +932,15 @@ unsigned int PrintWmf::stroke( } else { first_frag = fragment; } - slength = elength; - slength += style->stroke_dasharray.values[i++]; // the gap + SVGLength i2 = style->stroke_dasharray.values[i++]; + if(i2.unit == SVGLength::NONE) { + dashval = i2.value; + } else if (i2.unit == SVGLength::PERCENT) { + dashval = vbox.width() * i2.value; + } else { + dashval = Inkscape::Util::Quantity::convert(i2.computed, "px", display_unit.c_str()); + } + slength += dashval; // the gap if (i >= n_dash) { i = 0; } diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index 3c518c521..b7f736021 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -20,6 +20,9 @@ #include "Path.h" #include "style.h" #include "livarot/path-description.h" +#include "object/sp-namedview.h" +#include "util/units.h" +#include "inkscape.h" #include <2geom/pathvector.h> #include <2geom/point.h> #include <2geom/affine.h> @@ -62,16 +65,42 @@ void Path::DashPolylineFromStyle(SPStyle *style, float scale, float min_len) double dlen = 0.0; // Find total length + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (unsigned i = 0; i < style->stroke_dasharray.values.size(); i++) { - dlen += style->stroke_dasharray.values[i] * scale; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dlen += style->stroke_dasharray.values[i].value * scale; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dlen += vbox.width() * style->stroke_dasharray.values[i].value * scale; + } else { + dlen += Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()) * scale; + } } if (dlen >= min_len) { // Extract out dash pattern (relative positions) - double dash_offset = style->stroke_dashoffset.value * scale; + double dash_offset = 0; + if (style->stroke_dashoffset.unit == SVGLength::NONE) { + dash_offset = style->stroke_dashoffset.value * scale; + } else if (style->stroke_dashoffset.unit == SVGLength::PERCENT) { + dash_offset = vbox.width() * style->stroke_dashoffset.value * scale; + } else { + dash_offset = Inkscape::Util::Quantity::convert(style->stroke_dashoffset.computed * scale, "px", display_unit.c_str()); + } size_t n_dash = style->stroke_dasharray.values.size(); double *dash = g_new(double, n_dash); for (unsigned i = 0; i < n_dash; i++) { - dash[i] = style->stroke_dasharray.values[i] * scale; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dash[i] = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dash[i] = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dash[i] = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } } // Convert relative positions to absolute postions diff --git a/src/live_effects/lpe-dash-stroke.cpp b/src/live_effects/lpe-dash-stroke.cpp index dd30d05a4..dd4efcbc2 100644 --- a/src/live_effects/lpe-dash-stroke.cpp +++ b/src/live_effects/lpe-dash-stroke.cpp @@ -12,28 +12,48 @@ namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData<DashArraymethod> DashArraymethodData[] = { + { DA_LENGHT , N_("Lenght") , "lenght" }, + { DA_PERCENTAGE, N_("Percentage"), "percent" } +}; +static const Util::EnumDataConverter<DashArraymethod> DAConverter(DashArraymethodData, DA_END); + +static const Util::EnumData<DashAdjustArraymethod> DashAdjustArraymethodData[] = { + { DD_NONE , N_("None") , "none" }, + { DD_STRETCH , N_("Stretch") , "stretch" }, + { DD_STRETCH_DASHES , N_("Stretch dashes") , "stretch_dashes" }, + { DD_STRETCH_GAPS , N_("Stretch gaps") , "stretch_gaps" }, + { DD_COMPRESS , N_("Compress") , "compress" }, + { DD_COMPRESS_DASHES , N_("Compress dashes") , "compress_dashes" }, + { DD_COMPRESS_GAPS , N_("Compress gaps") , "compress_gaps" } +}; +static const Util::EnumDataConverter<DashAdjustArraymethod> DDConverter(DashAdjustArraymethodData, DD_END); + LPEDashStroke::LPEDashStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), - numberdashes(_("Number of dashes"), _("Number of dashes"), "numberdashes", &wr, this, 3), - holefactor(_("Hole factor"), _("Hole factor"), "holefactor", &wr, this, 0.0), - splitsegments(_("Use segments"), _("Use segments"), "splitsegments", &wr, this, true), - halfextreme(_("Half start/end"), _("Start and end of each segment has half size"), "halfextreme", &wr, this, true), - unifysegment(_("Unify dashes"), _("Approximately unify the dashes length using the minimal length segment"), "unifysegment", &wr, this, true), - message(_("Info Box"), _("Important messages"), "message", &wr, this, _("Add <b>\"Fill Between Many LPE\"</b> to add fill.")) + unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"), + method(_("Value type:"), _("% or units"),"method", DAConverter, &wr, this, DA_LENGHT), + dash_adjust(_("Adjust"), _("Adjustments for dahes and gaps"), "dash_adjust", DDConverter, &wr, this, DD_NONE), + stroke_dasharray(_("Dash Array"), _("Coma separated values for dashes and holes"), "stroke_dasharray", &wr, this,"1,1"), + stroke_dashoffset(_("Dash offset"), _("Dash offset"), "stroke_dashoffset", &wr, this, 0.0), + stroke_dashcorner(_("Dash corner"), _("Dash corner"), "stroke_dashcorner", &wr, this, 0.0), + message(_("Info Box"), _("Important messages"), "message", &wr, this, _("Add <b>\"Fill Between Many LPE\"</b> to add fill.")) { - registerParameter(&numberdashes); - registerParameter(&holefactor); - registerParameter(&splitsegments); - registerParameter(&halfextreme); - registerParameter(&unifysegment); + registerParameter(&unit); + registerParameter(&method); + registerParameter(&dash_adjust); + registerParameter(&stroke_dasharray); + registerParameter(&stroke_dashoffset); + registerParameter(&stroke_dashcorner); registerParameter(&message); - numberdashes.param_set_range(2, 999999999); - numberdashes.param_set_increments(1, 1); - numberdashes.param_set_digits(0); - holefactor.param_set_range(-0.99999, 0.99999); - holefactor.param_set_increments(0.01, 0.01); - holefactor.param_set_digits(5); + stroke_dashoffset.param_set_range(-999999999, 999999999); + stroke_dashoffset.param_set_increments(1, 1); + stroke_dashoffset.param_set_digits(5); + stroke_dashcorner.param_set_range(-999999999, 999999999); + stroke_dashcorner.param_set_increments(1, 1); + stroke_dashcorner.param_set_digits(5); message.param_set_min_height(30); + stroke_dasharray.param_hide_canvas_text(); } LPEDashStroke::~LPEDashStroke() = default; @@ -75,197 +95,198 @@ LPEDashStroke::timeAtLength(double const A, Geom::Piecewise<Geom::D2<Geom::SBasi Geom::PathVector LPEDashStroke::doEffect_path(Geom::PathVector const & path_in){ Geom::PathVector const pv = pathv_to_linear_and_cubic_beziers(path_in); - Geom::PathVector result; - for (Geom::PathVector::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { - if (path_it->empty()) { - continue; - } - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } - } - size_t numberdashes_fixed = numberdashes; - if(!splitsegments) { - numberdashes_fixed++; - } - size_t numberholes = numberdashes_fixed - 1; - size_t ammount = numberdashes_fixed + numberholes; - if (halfextreme) { - ammount--; - } - double base = 1/(double)ammount; - double globaldash = base * numberdashes_fixed * (1 + holefactor); - if (halfextreme) { - globaldash = base * (numberdashes_fixed - 1) * (1 + holefactor); - } - double globalhole = 1-globaldash; - double dashpercent = globaldash/numberdashes_fixed; - if (halfextreme) { - dashpercent = globaldash/(numberdashes_fixed -1); - } - double holepercent = globalhole/numberholes; - double dashsize_fixed = 0; - double holesize_fixed = 0; - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2 = (*path_it).toPwSb(); - double lenght_pwd2 = length (pwd2); - double minlenght = lenght_pwd2; - if(unifysegment) { - while (curve_it1 != curve_endit) { - double lenght_segment = (*curve_it1).length(); - if (lenght_segment < minlenght) { - minlenght = lenght_segment; - dashsize_fixed = (*curve_it1).length() * dashpercent; - holesize_fixed = (*curve_it1).length() * holepercent; - } - ++curve_it1; - ++curve_it2; - } - curve_it1 = path_it->begin(); - curve_it2 = ++(path_it->begin()); - curve_endit = path_it->end_default(); - } - size_t p_index = 0; - size_t start_index = result.size(); - if(splitsegments) { - while (curve_it1 != curve_endit) { - Geom::Path segment = (*path_it).portion(p_index, p_index + 1); - if(unifysegment) { - double integral; - double fractional = modf((*curve_it1).length()/(dashsize_fixed + holesize_fixed), &integral); - numberdashes_fixed = (size_t)integral + 1; - numberholes = numberdashes_fixed - 1; - ammount = numberdashes_fixed + numberholes; - if (halfextreme) { - ammount--; - } - base = 1/(double)ammount; - globaldash = base * numberdashes_fixed * (1 + holefactor); - if (halfextreme) { - globaldash = base * (numberdashes_fixed - 1) * (1 + holefactor); - } - globalhole = 1-globaldash; - dashpercent = globaldash/numberdashes_fixed; - if (halfextreme) { - dashpercent = globaldash/(numberdashes_fixed -1); - } - holepercent = globalhole/numberholes; - } - double dashsize = (*curve_it1).length() * dashpercent; - double holesize = (*curve_it1).length() * holepercent; - if ((*curve_it1).isLineSegment()) { - if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { - result[result.size()-1].setFinal(segment.initialPoint()); - if (halfextreme) { - result[result.size()-1].append(segment.portion(0.0, dashpercent/2.0)); - } else { - result[result.size()-1].append(segment.portion(0.0, dashpercent)); - } - } else { - if (halfextreme) { - result.push_back(segment.portion(0.0, dashpercent/2.0)); - } else { - result.push_back(segment.portion(0.0, dashpercent)); - } - } - - double start = dashpercent + holepercent; - if (halfextreme) { - start = (dashpercent/2.0) + holepercent; - } - while (start < 1) { - if (start + dashpercent > 1) { - result.push_back(segment.portion(start, 1)); - } else { - result.push_back(segment.portion(start, start + dashpercent)); - } - start += dashpercent + holepercent; - } - } else if (!(*curve_it1).isLineSegment()) { - double start = 0.0; - double end = 0.0; - if (halfextreme) { - end = timeAtLength(dashsize/2.0,segment); - } else { - end = timeAtLength(dashsize,segment); - } - if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { - result[result.size()-1].setFinal(segment.initialPoint()); - result[result.size()-1].append(segment.portion(start, end)); - } else { - result.push_back(segment.portion(start, end)); - } - double startsize = dashsize + holesize; - if (halfextreme) { - startsize = (dashsize/2.0) + holesize; - } - double endsize = startsize + dashsize; - start = timeAtLength(startsize,segment); - end = timeAtLength(endsize,segment); - while (start < 1 && start > 0) { - result.push_back(segment.portion(start, end)); - startsize = endsize + holesize; - endsize = startsize + dashsize; - start = timeAtLength(startsize,segment); - end = timeAtLength(endsize,segment); - } - } - if (curve_it2 == curve_endit) { - if (path_it->closed()) { - Geom::Path end = result[result.size()-1]; - end.setFinal(result[start_index].initialPoint()); - end.append(result[start_index]); - result[start_index] = end; - } - } - p_index ++; - ++curve_it1; - ++curve_it2; - } - } else { - double start = 0.0; - double end = 0.0; - double dashsize = lenght_pwd2 * dashpercent; - double holesize = lenght_pwd2 * holepercent; - if (halfextreme) { - end = timeAtLength(dashsize/2.0,pwd2); - } else { - end = timeAtLength(dashsize,pwd2); - } - result.push_back((*path_it).portion(start, end)); - double startsize = dashsize + holesize; - if (halfextreme) { - startsize = (dashsize/2.0) + holesize; - } - double endsize = startsize + dashsize; - start = timeAtLength(startsize,pwd2); - end = timeAtLength(endsize,pwd2); - while (start < (*path_it).size() && start > 0) { - result.push_back((*path_it).portion(start, end)); - startsize = endsize + holesize; - endsize = startsize + dashsize; - start = timeAtLength(startsize,pwd2); - end = timeAtLength(endsize,pwd2); - } - if (path_it->closed()) { - Geom::Path end = result[result.size()-1]; - end.setFinal(result[start_index].initialPoint()); - end.append(result[start_index]); - result[start_index] = end; - } - } - } - return result; + return pv; +// Geom::PathVector result; +// for (Geom::PathVector::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { +// if (path_it->empty()) { +// continue; +// } +// Geom::Path::const_iterator curve_it1 = path_it->begin(); +// Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); +// Geom::Path::const_iterator curve_endit = path_it->end_default(); +// if (path_it->closed()) { +// const Geom::Curve &closingline = path_it->back_closed(); +// // the closing line segment is always of type +// // Geom::LineSegment. +// if (are_near(closingline.initialPoint(), closingline.finalPoint())) { +// // closingline.isDegenerate() did not work, because it only checks for +// // *exact* zero length, which goes wrong for relative coordinates and +// // rounding errors... +// // the closing line segment has zero-length. So stop before that one! +// curve_endit = path_it->end_open(); +// } +// } +// size_t numberdashes_fixed = numberdashes; +// if(!splitsegments) { +// numberdashes_fixed++; +// } +// size_t numberholes = numberdashes_fixed - 1; +// size_t ammount = numberdashes_fixed + numberholes; +// if (halfextreme) { +// ammount--; +// } +// double base = 1/(double)ammount; +// double globaldash = base * numberdashes_fixed * (1 + holefactor); +// if (halfextreme) { +// globaldash = base * (numberdashes_fixed - 1) * (1 + holefactor); +// } +// double globalhole = 1-globaldash; +// double dashpercent = globaldash/numberdashes_fixed; +// if (halfextreme) { +// dashpercent = globaldash/(numberdashes_fixed -1); +// } +// double holepercent = globalhole/numberholes; +// double dashsize_fixed = 0; +// double holesize_fixed = 0; +// Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2 = (*path_it).toPwSb(); +// double lenght_pwd2 = length (pwd2); +// double minlenght = lenght_pwd2; +// if(unifysegment) { +// while (curve_it1 != curve_endit) { +// double lenght_segment = (*curve_it1).length(); +// if (lenght_segment < minlenght) { +// minlenght = lenght_segment; +// dashsize_fixed = (*curve_it1).length() * dashpercent; +// holesize_fixed = (*curve_it1).length() * holepercent; +// } +// ++curve_it1; +// ++curve_it2; +// } +// curve_it1 = path_it->begin(); +// curve_it2 = ++(path_it->begin()); +// curve_endit = path_it->end_default(); +// } +// size_t p_index = 0; +// size_t start_index = result.size(); +// if(splitsegments) { +// while (curve_it1 != curve_endit) { +// Geom::Path segment = (*path_it).portion(p_index, p_index + 1); +// if(unifysegment) { +// double integral; +// double fractional = modf((*curve_it1).length()/(dashsize_fixed + holesize_fixed), &integral); +// numberdashes_fixed = (size_t)integral + 1; +// numberholes = numberdashes_fixed - 1; +// ammount = numberdashes_fixed + numberholes; +// if (halfextreme) { +// ammount--; +// } +// base = 1/(double)ammount; +// globaldash = base * numberdashes_fixed * (1 + holefactor); +// if (halfextreme) { +// globaldash = base * (numberdashes_fixed - 1) * (1 + holefactor); +// } +// globalhole = 1-globaldash; +// dashpercent = globaldash/numberdashes_fixed; +// if (halfextreme) { +// dashpercent = globaldash/(numberdashes_fixed -1); +// } +// holepercent = globalhole/numberholes; +// } +// double dashsize = (*curve_it1).length() * dashpercent; +// double holesize = (*curve_it1).length() * holepercent; +// if ((*curve_it1).isLineSegment()) { +// if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { +// result[result.size()-1].setFinal(segment.initialPoint()); +// if (halfextreme) { +// result[result.size()-1].append(segment.portion(0.0, dashpercent/2.0)); +// } else { +// result[result.size()-1].append(segment.portion(0.0, dashpercent)); +// } +// } else { +// if (halfextreme) { +// result.push_back(segment.portion(0.0, dashpercent/2.0)); +// } else { +// result.push_back(segment.portion(0.0, dashpercent)); +// } +// } +// +// double start = dashpercent + holepercent; +// if (halfextreme) { +// start = (dashpercent/2.0) + holepercent; +// } +// while (start < 1) { +// if (start + dashpercent > 1) { +// result.push_back(segment.portion(start, 1)); +// } else { +// result.push_back(segment.portion(start, start + dashpercent)); +// } +// start += dashpercent + holepercent; +// } +// } else if (!(*curve_it1).isLineSegment()) { +// double start = 0.0; +// double end = 0.0; +// if (halfextreme) { +// end = timeAtLength(dashsize/2.0,segment); +// } else { +// end = timeAtLength(dashsize,segment); +// } +// if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { +// result[result.size()-1].setFinal(segment.initialPoint()); +// result[result.size()-1].append(segment.portion(start, end)); +// } else { +// result.push_back(segment.portion(start, end)); +// } +// double startsize = dashsize + holesize; +// if (halfextreme) { +// startsize = (dashsize/2.0) + holesize; +// } +// double endsize = startsize + dashsize; +// start = timeAtLength(startsize,segment); +// end = timeAtLength(endsize,segment); +// while (start < 1 && start > 0) { +// result.push_back(segment.portion(start, end)); +// startsize = endsize + holesize; +// endsize = startsize + dashsize; +// start = timeAtLength(startsize,segment); +// end = timeAtLength(endsize,segment); +// } +// } +// if (curve_it2 == curve_endit) { +// if (path_it->closed()) { +// Geom::Path end = result[result.size()-1]; +// end.setFinal(result[start_index].initialPoint()); +// end.append(result[start_index]); +// result[start_index] = end; +// } +// } +// p_index ++; +// ++curve_it1; +// ++curve_it2; +// } +// } else { +// double start = 0.0; +// double end = 0.0; +// double dashsize = lenght_pwd2 * dashpercent; +// double holesize = lenght_pwd2 * holepercent; +// if (halfextreme) { +// end = timeAtLength(dashsize/2.0,pwd2); +// } else { +// end = timeAtLength(dashsize,pwd2); +// } +// result.push_back((*path_it).portion(start, end)); +// double startsize = dashsize + holesize; +// if (halfextreme) { +// startsize = (dashsize/2.0) + holesize; +// } +// double endsize = startsize + dashsize; +// start = timeAtLength(startsize,pwd2); +// end = timeAtLength(endsize,pwd2); +// while (start < (*path_it).size() && start > 0) { +// result.push_back((*path_it).portion(start, end)); +// startsize = endsize + holesize; +// endsize = startsize + dashsize; +// start = timeAtLength(startsize,pwd2); +// end = timeAtLength(endsize,pwd2); +// } +// if (path_it->closed()) { +// Geom::Path end = result[result.size()-1]; +// end.setFinal(result[start_index].initialPoint()); +// end.append(result[start_index]); +// result[start_index] = end; +// } +// } +// } +// return result; } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-dash-stroke.h b/src/live_effects/lpe-dash-stroke.h index c84bd1960..b20b36f63 100644 --- a/src/live_effects/lpe-dash-stroke.h +++ b/src/live_effects/lpe-dash-stroke.h @@ -8,11 +8,31 @@ */ #include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/text.h" +#include "live_effects/parameter/unit.h" #include "live_effects/parameter/message.h" namespace Inkscape { namespace LivePathEffect { +enum DashArraymethod { + DA_LENGHT, + DA_PERCENTAGE, + DA_END +}; + +enum DashAdjustArraymethod { + DD_NONE, + DD_STRETCH, + DD_STRETCH_DASHES, + DD_STRETCH_GAPS, + DD_COMPRESS, + DD_COMPRESS_DASHES, + DD_COMPRESS_GAPS, + DD_END +}; + class LPEDashStroke : public Effect { public: LPEDashStroke(LivePathEffectObject *lpeobject); @@ -22,11 +42,12 @@ public: double timeAtLength(double const A, Geom::Path const &segment); double timeAtLength(double const A, Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2); private: - ScalarParam numberdashes; - ScalarParam holefactor; - BoolParam splitsegments; - BoolParam halfextreme; - BoolParam unifysegment; + UnitParam unit; + EnumParam<DashArraymethod> method; + EnumParam< DashAdjustArraymethod> dash_adjust; + TextParam stroke_dasharray; + ScalarParam stroke_dashoffset; + ScalarParam stroke_dashcorner; MessageParam message; }; diff --git a/src/object/sp-item.cpp b/src/object/sp-item.cpp index ec92c655f..fd27a6e90 100644 --- a/src/object/sp-item.cpp +++ b/src/object/sp-item.cpp @@ -1307,9 +1307,10 @@ void SPItem::adjust_stroke( gdouble ex ) if ( !style->stroke_dasharray.values.empty() ) { for (unsigned i = 0; i < style->stroke_dasharray.values.size(); i++) { - style->stroke_dasharray.values[i] *= ex; + style->stroke_dasharray.values[i].scale(ex); } - style->stroke_dashoffset.value *= ex; + style->stroke_dashoffset.value = style->stroke_dashoffset.value * ex; + style->stroke_dashoffset.computed = style->stroke_dashoffset.computed * ex; } updateRepr(); diff --git a/src/object/sp-item.h b/src/object/sp-item.h index f6a6781e9..9651f9f26 100644 --- a/src/object/sp-item.h +++ b/src/object/sp-item.h @@ -395,7 +395,7 @@ public: virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type) const; virtual void print(SPPrintContext *ctx); - virtual const char* displayName() const; + virtual const char* displayName() const; virtual char* description() const; virtual Inkscape::DrawingItem* show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags); virtual void hide(unsigned int key); diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 2a6083e55..c9479e90e 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -307,6 +307,7 @@ static char const preferences_skeleton[] = " <group id=\"stickyzoom\" value=\"0\"/>\n" " <group id=\"selcue\" value=\"2\"/>\n" " <group id=\"transform\" stroke=\"1\" rectcorners=\"1\" pattern=\"1\" gradient=\"1\" />\n" +" <group id=\"dash\" scale=\"1\" />\n" " <group id=\"kbselection\" inlayer=\"1\" onlyvisible=\"1\" onlysensitive=\"1\" />\n" " <group id=\"selection\" layerdeselect=\"1\" />\n" " <group id=\"createbitmap\"/>\n" diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 429353493..4ed59e82e 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -2034,20 +2034,17 @@ SPIDashArray::read( gchar const *str ) { return; } - // std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("[,\\s]+", str ); + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("[,\\s]+", str ); - gchar *e = nullptr; bool LineSolid = true; - while (e != str && *str != '\0') { - /* TODO: Should allow <length> rather than just a unitless (px) number. */ - double number = g_ascii_strtod(str, (char **) &e); - values.push_back( number ); - if (number > 0.00000001) + for (auto token:tokens) { + SVGLength svglength; + double value = atof(token.c_str()); + if(value > 0.00000001) { LineSolid = false; - if (e != str) { - str = e; } - while (str && *str && !(isalnum(*str) || *str=='.')) str += 1; + svglength.read(token.c_str()); + values.push_back(svglength); } if (LineSolid) { @@ -2074,7 +2071,7 @@ SPIDashArray::write( guint const flags, SPStyleSrc const &style_src_req, SPIBase if (i) { os << ", "; } - os << this->values[i]; + os << this->values[i].write().c_str(); } os << important_str(); os << ";"; @@ -2088,7 +2085,9 @@ SPIDashArray::write( guint const flags, SPStyleSrc const &style_src_req, SPIBase void SPIDashArray::cascade( const SPIBase* const parent ) { if( const SPIDashArray* p = dynamic_cast<const SPIDashArray*>(parent) ) { - if( !set || inherit ) values = p->values; // Always inherits + if( !set || inherit ) { + values = p->values; // Always inherits + } } else { std::cerr << "SPIDashArray::cascade(): Incorrect parent type" << std::endl; } @@ -2112,10 +2111,13 @@ SPIDashArray::merge( const SPIBase* const parent ) { bool SPIDashArray::operator==(const SPIBase& rhs) { if( const SPIDashArray* r = dynamic_cast<const SPIDashArray*>(&rhs) ) { - return values == r->values && SPIBase::operator==(rhs); - } else { - return false; + for (int i = 0;i < values.size(); i++) { + if (values[i] != r->values[i]) { + return false; + } + } } + return SPIBase::operator==(rhs); } diff --git a/src/style-internal.h b/src/style-internal.h index 869f862af..3bc3d3972 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -32,7 +32,7 @@ #include "object/uri.h" #include "svg/svg-icc-color.h" - +#include "svg/svg-length.h" #include "xml/repr.h" @@ -1010,9 +1010,9 @@ public: } - // To do: make private, change double to SVGLength + // To do: make private public: - std::vector<double> values; + std::vector<SVGLength> values; }; /// Filter type internal to SPStyle diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 4663aced4..eecd2f614 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -53,6 +53,13 @@ public: value = computed = v; return v; } + // Check apples being compared to apples + virtual bool operator==(const SVGLength& svglength) const { + return (unit == svglength.unit) && (value == svglength.value); + } + virtual bool operator!=(const SVGLength& svglength) const { + return !(*this == svglength); + } bool read(char const *str); void readOrUnset(char const *str, Unit u = NONE, float v = 0, float c = 0); diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 70ee0a78a..9e6ff92c1 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -1447,6 +1447,12 @@ void InkscapePreferences::initPageBehavior() _("Always store transformation as a transform= attribute on objects")); this->AddPage(_page_transforms, _("Transforms"), iter_behavior, PREFS_PAGE_BEHAVIOR_TRANSFORMS); + + _dash_scale.init ( _("Stroke width change dashes"), "/options/dash/scale", true); + _page_dashes.add_line( false, "", _dash_scale, "", + _("When chage stroke width, scale the dash array")); + + this->AddPage(_page_dashes, _("Dashes"), iter_behavior, PREFS_PAGE_BEHAVIOR_DASHES); // Scrolling options _scroll_wheel.init ( "/options/wheelscroll/value", 0.0, 1000.0, 1.0, 1.0, 40.0, true, false); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index a2f758287..55ea35f63 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -77,6 +77,7 @@ enum { PREFS_PAGE_BEHAVIOR, PREFS_PAGE_BEHAVIOR_SELECTING, PREFS_PAGE_BEHAVIOR_TRANSFORMS, + PREFS_PAGE_BEHAVIOR_DASHES, PREFS_PAGE_BEHAVIOR_SCROLLING, PREFS_PAGE_BEHAVIOR_SNAPPING, PREFS_PAGE_BEHAVIOR_STEPS, @@ -168,6 +169,7 @@ protected: UI::Widget::DialogPage _page_behavior; UI::Widget::DialogPage _page_select; UI::Widget::DialogPage _page_transforms; + UI::Widget::DialogPage _page_dashes; UI::Widget::DialogPage _page_scrolling; UI::Widget::DialogPage _page_snapping; UI::Widget::DialogPage _page_steps; @@ -317,6 +319,8 @@ protected: UI::Widget::PrefRadioButton _trans_optimized; UI::Widget::PrefRadioButton _trans_preserved; + UI::Widget::PrefCheckButton _dash_scale; + UI::Widget::PrefRadioButton _sel_all; UI::Widget::PrefRadioButton _sel_current; UI::Widget::PrefRadioButton _sel_recursive; diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index 37bf08b3d..43f5f66e9 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -27,7 +27,9 @@ #include "preferences.h" #include "display/cairo-utils.h" - +#include "util/units.h" +#include "inkscape.h" +#include "object/sp-namedview.h" #include "style.h" #include "ui/dialog-events.h" @@ -111,7 +113,12 @@ void SPDashSelector::init_dashes() { if (!dash_prefs.empty()) { SPStyle style; dashes = g_new (double *, dash_prefs.size() + 2); // +1 for custom slot, +1 for terminator slot - + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (std::vector<Glib::ustring>::iterator i = dash_prefs.begin(); i != dash_prefs.end(); ++i) { style.readFromPrefs( *i ); @@ -120,7 +127,7 @@ void SPDashSelector::init_dashes() { double *d = dashes[pos]; unsigned i = 0; for (; i < style.stroke_dasharray.values.size(); i++) { - d[i] = style.stroke_dasharray.values[i]; + d[i] = Inkscape::Util::Quantity::convert(style.stroke_dasharray.values[i].computed, "px", display_unit.c_str()); } d[i] = -1; } else { diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 3a5abbca4..74c5e6efc 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -25,6 +25,8 @@ #include "object/sp-rect.h" #include "object/sp-stop.h" #include "object/sp-text.h" +#include "util/units.h" +#include "inkscape.h" #include "svg/svg-color.h" @@ -741,15 +743,38 @@ StrokeStyle::setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style) if (!style->stroke_dasharray.values.empty()) { double d[64]; size_t len = MIN(style->stroke_dasharray.values.size(), 64); + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Geom::Rect vbox = document->getViewBox(); + Glib::ustring display_unit = "px"; + if (nv) { + display_unit = nv->display_units->abbr; + } for (unsigned i = 0; i < len; i++) { + double dash = 0; + if(style->stroke_dasharray.values[i].unit == SVGLength::NONE) { + dash = style->stroke_dasharray.values[i].value; + } else if (style->stroke_dasharray.values[i].unit == SVGLength::PERCENT) { + dash = vbox.width() * style->stroke_dasharray.values[i].value; + } else { + dash = Inkscape::Util::Quantity::convert(style->stroke_dasharray.values[i].computed, "px", display_unit.c_str()); + } if (style->stroke_width.computed != 0) - d[i] = style->stroke_dasharray.values[i] / style->stroke_width.computed; + d[i] = dash / style->stroke_width.computed; else - d[i] = style->stroke_dasharray.values[i]; // is there a better thing to do for stroke_width==0? + d[i] = dash; // is there a better thing to do for stroke_width==0? + } + double dash_offset = 0; + if (style->stroke_dashoffset.unit == SVGLength::NONE) { + dash_offset = style->stroke_dashoffset.value; + } else if (style->stroke_dashoffset.unit == SVGLength::PERCENT) { + dash_offset = vbox.width() * style->stroke_dashoffset.value; + } else { + dash_offset = Inkscape::Util::Quantity::convert(style->stroke_dashoffset.computed, "px", display_unit.c_str()); } dsel->set_dash(len, d, style->stroke_width.computed != 0 ? - style->stroke_dashoffset.value / style->stroke_width.computed : - style->stroke_dashoffset.value); + dash_offset / style->stroke_width.computed : + dash_offset); } else { dsel->set_dash(0, nullptr, 0.0); } @@ -1042,8 +1067,11 @@ StrokeStyle::scaleLine() } /* Set dash */ - setScaledDash(css, ndash, dash, offset, width); - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean scale = prefs->getBool("/options/dash/scale", true); + if (scale) { + setScaledDash(css, ndash, dash, offset, width); + } sp_desktop_apply_css_recursive ((*i), css, true); } |
