diff options
| author | Liam P. White <inkscapebrony@gmail.com> | 2014-07-24 21:21:30 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebrony@gmail.com> | 2014-07-24 21:21:30 +0000 |
| commit | f33396b871f4e4273bf131195dcaa2ebcb3163b8 (patch) | |
| tree | 5bdc7e523e724799007f06cb63ec74ff97195a68 /src | |
| parent | Fix crash bug when exporting PNG from CLI (diff) | |
| parent | Read HSL color (CSS Color Module Level 3). (diff) | |
| download | inkscape-f33396b871f4e4273bf131195dcaa2ebcb3163b8.tar.gz inkscape-f33396b871f4e4273bf131195dcaa2ebcb3163b8.zip | |
Update to experimental r13440
(bzr r13341.5.13)
Diffstat (limited to 'src')
59 files changed, 3059 insertions, 862 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47b181522..3dcbb8e94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ set(sp_SRC sp-root.cpp sp-script.cpp sp-shape.cpp + sp-solid-color.cpp sp-spiral.cpp sp-star.cpp sp-stop.cpp @@ -147,6 +148,7 @@ set(sp_SRC sp-root.h sp-script.h sp-shape.h + sp-solid-color.h sp-spiral.h sp-star.h sp-stop.h diff --git a/src/Makefile.am b/src/Makefile.am index bb34047a8..282797a50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -220,7 +220,7 @@ endif # someone updates the BZR working directory. inkscape-version.cpp: $(inkscape_version_deps) VER_PREFIX="$(VERSION)";\ - VER_BZRREV=" r`bzr revno --tree`"; \ + VER_BZRREV=" r`bzr revno --tree $(top_srcdir)`"; \ if test ! -z "`bzr status -S -V $(srcdir)`"; then \ VER_CUSTOM=" custom"; \ fi; \ diff --git a/src/Makefile_insert b/src/Makefile_insert index 9ac08a822..2f28233d5 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -192,6 +192,7 @@ ink_common_sources += \ sp-root.cpp sp-root.h \ sp-script.cpp sp-script.h \ sp-shape.cpp sp-shape.h \ + sp-solid-color.cpp sp-solid-color.h \ sp-spiral.cpp sp-spiral.h \ sp-star.cpp sp-star.h \ sp-stop.cpp sp-stop.h \ diff --git a/src/attributes.cpp b/src/attributes.cpp index ee2a80fd3..da7b25f03 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -475,6 +475,8 @@ static SPStyleProp const props[] = { {SP_PROP_MARKER_START, "marker-start"}, {SP_PROP_PAINT_ORDER, "paint-order" }, {SP_PROP_SHAPE_RENDERING, "shape-rendering"}, + {SP_PROP_SOLID_COLOR, "solid-color"}, + {SP_PROP_SOLID_OPACITY, "solid-opacity"}, {SP_PROP_STROKE, "stroke"}, {SP_PROP_STROKE_DASHARRAY, "stroke-dasharray"}, {SP_PROP_STROKE_DASHOFFSET, "stroke-dashoffset"}, diff --git a/src/attributes.h b/src/attributes.h index b8843fcb7..82e7ca8a6 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -476,6 +476,8 @@ enum SPAttributeEnum { SP_PROP_MARKER_START, SP_PROP_PAINT_ORDER, /* SVG2 */ SP_PROP_SHAPE_RENDERING, + SP_PROP_SOLID_COLOR, + SP_PROP_SOLID_OPACITY, SP_PROP_STROKE, SP_PROP_STROKE_DASHARRAY, SP_PROP_STROKE_DASHOFFSET, diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index a5e7eaa94..dfccb63bf 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -213,8 +213,6 @@ void Box3DSide::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { - sp_lpe_item_apply_to_mask(this); - sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 099816bce..25aea6f13 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -83,8 +83,7 @@ void FilterBlend::render_cairo(FilterSlot &slot) case BLEND_LIGHTEN: cairo_set_operator(out_ct, CAIRO_OPERATOR_LIGHTEN); break; -#ifdef WITH_CSSBLEND - // NEW + // New in CSS Compositing and Blending Level 1 case BLEND_OVERLAY: cairo_set_operator(out_ct, CAIRO_OPERATOR_OVERLAY); break; @@ -118,7 +117,6 @@ void FilterBlend::render_cairo(FilterSlot &slot) case BLEND_LUMINOSITY: cairo_set_operator(out_ct, CAIRO_OPERATOR_HSL_LUMINOSITY); break; -#endif case BLEND_NORMAL: default: @@ -167,15 +165,12 @@ void FilterBlend::set_input(int input, int slot) { void FilterBlend::set_mode(FilterBlendMode mode) { if (mode == BLEND_NORMAL || mode == BLEND_MULTIPLY || mode == BLEND_SCREEN || mode == BLEND_DARKEN || - mode == BLEND_LIGHTEN -#ifdef WITH_CSSBLEND - || mode == BLEND_OVERLAY || + mode == BLEND_LIGHTEN || mode == BLEND_OVERLAY || mode == BLEND_COLORDODGE || mode == BLEND_COLORBURN || mode == BLEND_HARDLIGHT || mode == BLEND_SOFTLIGHT || mode == BLEND_DIFFERENCE || mode == BLEND_EXCLUSION || mode == BLEND_HUE || mode == BLEND_SATURATION || mode == BLEND_COLOR || mode == BLEND_LUMINOSITY -#endif ) { _blend_mode = mode; diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 0a2927d87..c0504993b 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -28,7 +28,6 @@ enum FilterBlendMode { BLEND_SCREEN, BLEND_DARKEN, BLEND_LIGHTEN, -#ifdef WITH_CSSBLEND // New in CSS Compositing and Blending Level 1 BLEND_OVERLAY, BLEND_COLORDODGE, @@ -41,7 +40,6 @@ enum FilterBlendMode { BLEND_SATURATION, BLEND_COLOR, BLEND_LUMINOSITY, -#endif BLEND_ENDMODE, }; diff --git a/src/file.cpp b/src/file.cpp index be2c8ff2c..7f1872ca2 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -669,7 +669,7 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri, sp_ui_error_dialog(text); g_free(text); g_free(safeUri); - return FALSE; + return false; } catch (Inkscape::Extension::Output::file_read_only &e) { gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str()); gchar *text = g_strdup_printf(_("File %s is write protected. Please remove write protection and try again."), safeUri); @@ -677,7 +677,7 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri, sp_ui_error_dialog(text); g_free(text); g_free(safeUri); - return FALSE; + return false; } catch (Inkscape::Extension::Output::save_failed &e) { gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str()); gchar *text = g_strdup_printf(_("File %s could not be saved."), safeUri); @@ -685,15 +685,15 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri, sp_ui_error_dialog(text); g_free(text); g_free(safeUri); - return FALSE; + return false; } catch (Inkscape::Extension::Output::save_cancelled &e) { SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved.")); - return FALSE; + return false; } catch (Inkscape::Extension::Output::no_overwrite &e) { return sp_file_save_dialog(parentWindow, doc, save_method); } catch (...) { SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved.")); - return FALSE; + return false; } if (SP_ACTIVE_DESKTOP) { diff --git a/src/filter-enums.cpp b/src/filter-enums.cpp index 7ee57f7fa..09a1a7614 100644 --- a/src/filter-enums.cpp +++ b/src/filter-enums.cpp @@ -53,7 +53,6 @@ const EnumData<Inkscape::Filters::FilterBlendMode> BlendModeData[Inkscape::Filte {Inkscape::Filters::BLEND_SCREEN, _("Screen"), "screen"}, {Inkscape::Filters::BLEND_DARKEN, _("Darken"), "darken"}, {Inkscape::Filters::BLEND_LIGHTEN, _("Lighten"), "lighten"}, -#ifdef WITH_CSSBLEND // New in Compositing and Blending Level 1 {Inkscape::Filters::BLEND_OVERLAY, _("Overlay"), "overlay"}, {Inkscape::Filters::BLEND_COLORDODGE, _("Color Dodge"), "color-dodge"}, @@ -66,10 +65,13 @@ const EnumData<Inkscape::Filters::FilterBlendMode> BlendModeData[Inkscape::Filte {Inkscape::Filters::BLEND_SATURATION, _("Saturation"), "saturation"}, {Inkscape::Filters::BLEND_COLOR, _("Color"), "color"}, {Inkscape::Filters::BLEND_LUMINOSITY, _("Luminosity"), "luminosity"} -#endif }; +#ifdef WITH_CSSBLEND const EnumDataConverter<Inkscape::Filters::FilterBlendMode> BlendModeConverter(BlendModeData, Inkscape::Filters::BLEND_ENDMODE); - +#else +// Disable new blend modes in GUI until widely implemented. +const EnumDataConverter<Inkscape::Filters::FilterBlendMode> BlendModeConverter(BlendModeData, Inkscape::Filters::BLEND_OVERLAY); +#endif const EnumData<Inkscape::Filters::FilterColorMatrixType> ColorMatrixTypeData[Inkscape::Filters::COLORMATRIX_ENDTYPE] = { {Inkscape::Filters::COLORMATRIX_MATRIX, _("Matrix"), "matrix"}, diff --git a/src/filters/blend.cpp b/src/filters/blend.cpp index 5c78f4f9f..fd5a9871e 100644 --- a/src/filters/blend.cpp +++ b/src/filters/blend.cpp @@ -96,23 +96,18 @@ static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value case 's': if (strncmp(value, "screen", 6) == 0) return Inkscape::Filters::BLEND_SCREEN; -#ifdef WITH_CSSBLEND if (strncmp(value, "saturation", 6) == 0) return Inkscape::Filters::BLEND_SATURATION; -#endif break; case 'd': if (strncmp(value, "darken", 6) == 0) return Inkscape::Filters::BLEND_DARKEN; -#ifdef WITH_CSSBLEND if (strncmp(value, "difference", 10) == 0) return Inkscape::Filters::BLEND_DIFFERENCE; -#endif break; case 'l': if (strncmp(value, "lighten", 7) == 0) return Inkscape::Filters::BLEND_LIGHTEN; -#ifdef WITH_CSSBLEND if (strncmp(value, "luminosity", 10) == 0) return Inkscape::Filters::BLEND_LUMINOSITY; break; @@ -137,7 +132,6 @@ static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value case 'e': if (strncmp(value, "exclusion", 10) == 0) return Inkscape::Filters::BLEND_EXCLUSION; -#endif default: std::cout << "Inkscape::Filters::FilterBlendMode: Unimplemented mode: " << value << std::endl; // do nothing by default @@ -244,7 +238,6 @@ Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XM mode = "darken"; break; case Inkscape::Filters::BLEND_LIGHTEN: mode = "lighten"; break; -#ifdef WITH_CSSBLEND // New case Inkscape::Filters::BLEND_OVERLAY: mode = "overlay"; break; @@ -268,7 +261,6 @@ Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XM mode = "color"; break; case Inkscape::Filters::BLEND_LUMINOSITY: mode = "luminosity"; break; -#endif default: mode = 0; } diff --git a/src/knotholder.h b/src/knotholder.h index 3632635f5..dc2300105 100644 --- a/src/knotholder.h +++ b/src/knotholder.h @@ -28,6 +28,7 @@ class Node; } namespace LivePathEffect { class PowerStrokePointArrayParamKnotHolderEntity; +class FilletPointArrayParamKnotHolderEntity; } } @@ -60,6 +61,7 @@ public: friend class ShapeEditor; friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity; + friend class Inkscape::LivePathEffect::FilletPointArrayParamKnotHolderEntity; protected: diff --git a/src/libavoid/connector.cpp b/src/libavoid/connector.cpp index 8dcb66f2d..b8c99a48c 100644 --- a/src/libavoid/connector.cpp +++ b/src/libavoid/connector.cpp @@ -442,11 +442,11 @@ void ConnRef::makeActive(void) void ConnRef::makeInactive(void) { - COLA_ASSERT(_active); - - // Remove from connRefs list. - _router->connRefs.erase(_pos); - _active = false; + if (_active) { + // Remove from connRefs list. + _router->connRefs.erase(_pos); + _active = false; + } } @@ -553,8 +553,12 @@ void ConnRef::unInitialise(void) void ConnRef::removeFromGraph(void) { - _srcVert->removeFromGraph(); - _dstVert->removeFromGraph(); + if (_srcVert) { + _srcVert->removeFromGraph(); + } + if (_dstVert) { + _dstVert->removeFromGraph(); + } } diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 5d365bb21..a4d35b339 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -14,6 +14,7 @@ set(live_effects_SRC lpe-envelope.cpp lpe-envelope-perspective.cpp lpe-extrude.cpp + lpe-fillet-chamfer.cpp lpe-gears.cpp lpe-interpolate.cpp lpe-knot.cpp @@ -48,6 +49,7 @@ set(live_effects_SRC parameter/array.cpp parameter/bool.cpp + parameter/filletchamferpointarray.cpp parameter/parameter.cpp parameter/path.cpp parameter/originalpath.cpp @@ -77,6 +79,7 @@ set(live_effects_SRC lpe-dynastroke.h lpe-envelope.h lpe-extrude.h + lpe-fillet-chamfer.h lpe-gears.h lpe-interpolate.h lpe-knot.h @@ -112,6 +115,7 @@ set(live_effects_SRC parameter/array.h parameter/bool.h + parameter/filletchamferpointarray.h parameter/enum.h parameter/parameter.h parameter/path-reference.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index c47003747..263b33b3c 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -32,6 +32,8 @@ ink_common_sources += \ live_effects/lpe-curvestitch.h \ live_effects/lpe-constructgrid.cpp \ live_effects/lpe-constructgrid.h \ + live_effects/lpe-fillet-chamfer.cpp \ + live_effects/lpe-fillet-chamfer.h \ live_effects/lpe-gears.cpp \ live_effects/lpe-gears.h \ live_effects/lpe-interpolate.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 4d1c1d8c1..942ef5891 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -54,6 +54,7 @@ enum EffectType { POWERSTROKE, CLONE_ORIGINAL, ENVELOPE_PERSPECTIVE, + FILLET_CHAMFER, INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan) }; diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index e622ca420..0e9f92d09 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -49,6 +49,7 @@ #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" #include "live_effects/lpe-envelope-perspective.h" +#include "live_effects/lpe-fillet-chamfer.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -107,7 +108,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {TEXT_LABEL, N_("Text label"), "text_label"}, #endif /* 0.46 */ - {BEND_PATH, N_("Bend"), "bend_path"}, + {BEND_PATH, N_("Bend"), "bend_path"}, {GEARS, N_("Gears"), "gears"}, {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, @@ -121,13 +122,15 @@ const Util::EnumData<EffectType> LPETypeData[] = { {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, {SKETCH, N_("Sketch"), "sketch"}, {RULER, N_("Ruler"), "ruler"}, -/* 0.49 */ - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, - {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, +/* 0.91 */ + {POWERSTROKE, N_("Power stroke"), "powerstroke"}, + {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, {BSPLINE, N_("BSpline"), "bspline"}, - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + // TRANSLATORS: "Envelope Perspective" should be equivalent to "perspective transformation" + {ENVELOPE_PERSPECTIVE, N_("Envelope Perspective"), "envelope-perspective"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -263,6 +266,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case ENVELOPE_PERSPECTIVE: neweffect = static_cast<Effect*> ( new LPEEnvelopePerspective(lpeobj) ); break; + case FILLET_CHAMFER: + neweffect = static_cast<Effect*> ( new LPEFilletChamfer(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 247496167..0a5d8eca5 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -8,10 +8,13 @@ # include <config.h> #endif -#if WITH_GLIBMM_2_32 +#if WITH_GLIBMM_2_32 && HAVE_GLIBMM_THREADS_H # include <glibmm/threads.h> #endif +#include <2geom/bezier-curve.h> +#include <2geom/point.h> + #include <gtkmm/box.h> #include <gtkmm/entry.h> #include <gtkmm/box.h> @@ -21,10 +24,7 @@ #include <glib.h> #include <glibmm/i18n.h> - #include "display/curve.h" -#include <2geom/bezier-curve.h> -#include <2geom/point.h> #include "helper/geom-curves.h" #include "live_effects/lpe-bspline.h" #include "live_effects/lpeobject.h" @@ -48,7 +48,8 @@ #include "display/sp-canvas.h" #include <typeinfo> #include <vector> -// For handling un-continuous paths: + +// For handling non-contiguous paths: #include "message-stack.h" #include "inkscape.h" #include "desktop.h" @@ -58,320 +59,303 @@ using Inkscape::DocumentUndo; namespace Inkscape { namespace LivePathEffect { -LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) - : Effect(lpeobject), - // initialise your parameters here: - //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, - //Geom::Point(100,100)), - steps(_("Steps whith CTRL:"), - _("Change number of steps whith CTRL pressed"), "steps", &wr, this, - 2), - ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), - "ignoreCusp", &wr, this, true), - onlySelected(_("Change only selected nodes:"), - _("Change only selected nodes"), "onlySelected", &wr, this, - false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", - &wr, this, 0.3334) { - registerParameter(dynamic_cast<Parameter *>(&weight)); - registerParameter(dynamic_cast<Parameter *>(&steps)); - registerParameter(dynamic_cast<Parameter *>(&ignoreCusp)); - registerParameter(dynamic_cast<Parameter *>(&onlySelected)); - weight.param_set_range(0.0000, 1); - weight.param_set_increments(0.1, 0.1); - weight.param_set_digits(4); - steps.param_set_range(1, 10); - steps.param_set_increments(1, 1); - steps.param_set_digits(0); +LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), + ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), + onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) +{ + registerParameter(&weight); + registerParameter(&steps); + registerParameter(&ignoreCusp); + registerParameter(&onlySelected); + + weight.param_set_range(0.0000, 1); + weight.param_set_increments(0.1, 0.1); + weight.param_set_digits(4); + + steps.param_set_range(1, 10); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); } LPEBSpline::~LPEBSpline() {} -void LPEBSpline::createAndApply(const char *name, SPDocument *doc, - SPItem *item) { - if (!SP_IS_SHAPE(item)) { - g_warning("LPE BSpline can only be applied to shapes (not groups)."); - } else { - // Path effect definition - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); - repr->setAttribute("effect", name); - - doc->getDefs()->getRepr() - ->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute - const gchar *repr_id = repr->attribute("id"); - Inkscape::GC::release(repr); - - gchar *href = g_strdup_printf("#%s", repr_id); - SP_LPE_ITEM(item)->addPathEffect(href, true); - g_free(href); - } -} - -void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 1) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); - - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { - //Si está vacÃo... - if (path_it->empty()) - continue; - //Itreadores - - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = - ++(path_it->begin()); // outgoing curve - Geom::Path::const_iterator curve_endit = - path_it->end_default(); // this determines when the loop has to stop - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point previousNode(0, 0); - Geom::Point node(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); - Geom::D2<Geom::SBasis> SBasisIn; - Geom::D2<Geom::SBasis> SBasisOut; - Geom::D2<Geom::SBasis> SBasisHelper; - Geom::CubicBezier const *cubic = NULL; - if (path_it->closed()) { - // if the path is closed, maybe we have to stop a bit earlier because the - // closing line segment has zerolength. - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirÃan en tres segmentos iguales el path - //recto de entrada y de salida - SPCurve *in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - if (cubic) { - SBasisIn = in->first_segment()->toSBasis(); - pointAt1 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[1], *in->first_segment())); - pointAt2 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[2], *in->first_segment())); - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - in->reset(); - delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve *out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[2], *out->first_segment())); - ; - nextPointAt3 = out->first_segment()->finalPoint(); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de - //principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, node); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); - nextPointAt3 = out->first_segment()->finalPoint(); +void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) +{ + if (!SP_IS_SHAPE(item)) { + g_warning("LPE BSpline can only be applied to shapes (not groups)."); } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //Si está cerrada la curva, la cerramos sobre el valor guardado - //previamente - //Si no finalizamos en el punto final - Geom::Point startNode = path_it->begin()->initialPoint(); - if (path_it->closed()) { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - Geom::D2<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin()); - if (cubic) { - lineHelper->moveto(SBasisStart.valueAt( - Geom::nearest_point((*cubic)[1], *start->first_segment()))); - } else { - lineHelper->moveto(start->first_segment()->initialPoint()); - } - start->reset(); - delete start; - - SPCurve *end = new SPCurve(); - end->moveto(curve_it1->initialPoint()); - end->lineto(curve_it1->finalPoint()); - Geom::D2<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis(); - //Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve - //const*>(&*curve_endit); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - if (cubic) { - lineHelper->lineto(SBasisEnd.valueAt( - Geom::nearest_point((*cubic)[2], *end->first_segment()))); - } else { - lineHelper->lineto(end->first_segment()->finalPoint()); - } - end->reset(); - delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(nextPointAt1, nextPointAt2, startNode); - nCurve->move_endpoints(startNode, startNode); - } else { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - startNode = start->first_segment()->initialPoint(); - start->reset(); - delete start; - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(startNode, nextPointAt3); - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + // Path effect definition + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); + repr->setAttribute("effect", name); + + doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute + const gchar *repr_id = repr->attribute("id"); + Inkscape::GC::release(repr); + + gchar *href = g_strdup_printf("#%s", repr_id); + SP_LPE_ITEM(item)->addPathEffect(href, true); + g_free(href); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; - } } -Gtk::Widget *LPEBSpline::newWidget() { - // use manage here, because after deletion of Effect object, others might - // still be pointing to this widget. - Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); - - vbox->set_border_width(5); - std::vector<Parameter *>::iterator it = param_vector.begin(); - while (it != param_vector.end()) { - if ((*it)->widget_is_visible) { - Parameter *param = *it; - Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); - if (param->param_key == "weight"){ - Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); - Gtk::Button *defaultWeight = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); - defaultWeight->signal_clicked() - .connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); - buttons->pack_start(*defaultWeight, true, true, 2); - Gtk::Button *makeCusp = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->signal_clicked() - .connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); - buttons->pack_start(*makeCusp, true, true, 2); - vbox->pack_start(*buttons, true, true, 2); - } - if (param->param_key == "weight" || param->param_key == "steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = - Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed() - .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); - if (widg){ - Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); - entryWidg->set_width_chars(6); +void LPEBSpline::doEffect(SPCurve *curve) +{ + if (curve->get_segment_count() < 1) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + //Si está vacÃo... + if (path_it->empty()) + continue; + //Itreadores + + Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::const_iterator curve_it2 = + ++(path_it->begin()); // outgoing curve + Geom::Path::const_iterator curve_endit = + path_it->end_default(); // this determines when the loop has to stop + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point previousNode(0, 0); + Geom::Point node(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2<Geom::SBasis> SBasisIn; + Geom::D2<Geom::SBasis> SBasisOut; + Geom::D2<Geom::SBasis> SBasisHelper; + Geom::CubicBezier const *cubic = NULL; + if (path_it->closed()) { + // if the path is closed, maybe we have to stop a bit earlier because the + // closing line segment has zerolength. + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirÃan en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + SBasisIn = in->first_segment()->toSBasis(); + pointAt1 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[1], *in->first_segment())); + pointAt2 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[2], *in->first_segment())); + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + in->reset(); + delete in; + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + SPCurve *out = new SPCurve(); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[2], *out->first_segment())); + ; + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + SPCurve *lineHelper = new SPCurve(); + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de + //principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); + nCurve->curveto(pointAt1, pointAt2, node); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); } - } - if (param->param_key == "onlySelected") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); - } - if (param->param_key == "ignoreCusp") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); - } - Glib::ustring *tip = param->param_getTooltip(); - if (widg) { - vbox->pack_start(*widg, true, true, 2); - if (tip) { - widg->set_tooltip_text(*tip); + out->reset(); + delete out; + //Si está cerrada la curva, la cerramos sobre el valor guardado + //previamente + //Si no finalizamos en el punto final + Geom::Point startNode = path_it->begin()->initialPoint(); + if (path_it->closed()) { + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + Geom::D2<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis(); + SPCurve *lineHelper = new SPCurve(); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin()); + if (cubic) { + lineHelper->moveto(SBasisStart.valueAt( + Geom::nearest_point((*cubic)[1], *start->first_segment()))); + } else { + lineHelper->moveto(start->first_segment()->initialPoint()); + } + start->reset(); + delete start; + + SPCurve *end = new SPCurve(); + end->moveto(curve_it1->initialPoint()); + end->lineto(curve_it1->finalPoint()); + Geom::D2<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis(); + + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + lineHelper->lineto(SBasisEnd.valueAt( + Geom::nearest_point((*cubic)[2], *end->first_segment()))); + } else { + lineHelper->lineto(end->first_segment()->finalPoint()); + } + end->reset(); + delete end; + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + startNode = SBasisHelper.valueAt(0.5); + nCurve->curveto(nextPointAt1, nextPointAt2, startNode); + nCurve->move_endpoints(startNode, startNode); } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + startNode = start->first_segment()->initialPoint(); + start->reset(); + delete start; + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(startNode, nextPointAt3); } - } + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; } +} + +Gtk::Widget *LPEBSpline::newWidget() +{ + // use manage here, because after deletion of Effect object, others might + // still be pointing to this widget. + Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); + + vbox->set_border_width(5); + std::vector<Parameter *>::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter *param = *it; + Gtk::Widget *widg = Gtk::manage(param->param_newWidget()); + if (param->param_key == "weight") { + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true, 0)); + + Gtk::Button *defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); + defaultWeight->signal_clicked().connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); + buttons->pack_start(*defaultWeight, true, true, 2); + + Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->signal_clicked().connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); + buttons->pack_start(*makeCusp, true, true, 2); + + vbox->pack_start(*buttons, true, true, 2); + } + if (param->param_key == "weight" || param->param_key == "steps") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); + + if (widg) { + Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); + entryWidg->set_width_chars(6); + } + } - ++it; - } - return dynamic_cast<Gtk::Widget *>(vbox); + Glib::ustring *tip = param->param_getTooltip(); + if (widg) { + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + return vbox; } -void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { +void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) +{ weight.param_set_value(0.3334); changeWeight(0.3334); Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widgWeight); @@ -380,7 +364,8 @@ void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { entryWidg->set_text("0.3334"); } -void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { +void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) +{ weight.param_set_value(0.0000); changeWeight(0.0000); Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widgWeight); @@ -389,348 +374,353 @@ void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { entryWidg->set_text("0.0000"); } -void LPEBSpline::toWeight() { changeWeight(weight); } - -void LPEBSpline::changeWeight(double weightValue) { - SPDesktop *desktop = INKSCAPE.active_desktop(); - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList *items = (GSList *)selection->itemList(); - SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; - SPPath *path = SP_PATH(item); - SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve, weightValue); - gchar *str = sp_svg_write_path(curve->get_pathvector()); - path->getRepr()->setAttribute("inkscape:original-d", str); - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - nt->desktop->updateNow(); - } - g_free(str); - curve->unref(); - desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, - _("Modified the weight of the BSpline")); +void LPEBSpline::toWeight() +{ + changeWeight(weight); } -bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) { - using Geom::X; - using Geom::Y; - - if (points.size() > 0) { - for (std::vector<Geom::Point>::iterator i = points.begin(); - i != points.end(); ++i) { - Geom::Point p = *i; - if (Geom::are_near(p, nodePoint, 0.0001)) { - return true; - } else { - } +void LPEBSpline::changeWeight(double weightValue) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList *items = (GSList *)selection->itemList(); + SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; + SPPath *path = SP_PATH(item); + SPCurve *curve = path->get_curve_for_edit(); + LPEBSpline::doBSplineFromWidget(curve, weightValue); + gchar *str = sp_svg_write_path(curve->get_pathvector()); + path->getRepr()->setAttribute("inkscape:original-d", str); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + nt->desktop->updateNow(); } - } - return false; + g_free(str); + curve->unref(); + desktop->clearWaitingCursor(); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of a BSpline")); } -void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { - using Geom::X; - using Geom::Y; - SPDesktop *desktop = INKSCAPE.active_desktop(); - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = - nt->_selected_nodes->allPoints(); - points.clear(); - std::vector<Geom::Point>::iterator pbegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = - selection.begin(); - i != selection.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); - pbegin = points.begin(); - points.insert(pbegin, desktop->doc2dt(n->position())); - } - } - } - //bool hasNodesSelected = LPEBspline::hasNodesSelected(); - if (curve->get_segment_count() < 1) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); - - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { - //Si está vacÃo... - if (path_it->empty()) - continue; - //Itreadores - - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = - ++(path_it->begin()); // outgoing curve - Geom::Path::const_iterator curve_endit = - path_it->end_default(); // this determines when the loop has to stop - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point pointAt0(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point pointAt3(0, 0); - Geom::Point nextPointAt0(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); - Geom::D2<Geom::SBasis> SBasisIn; - Geom::D2<Geom::SBasis> SBasisOut; - Geom::CubicBezier const *cubic = NULL; - if (path_it->closed()) { - // if the path is closed, maybe we have to stop a bit earlier because the - // closing line segment has zerolength. - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirÃan en tres segmentos iguales el path - //recto de entrada y de salida - SPCurve *in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - pointAt0 = in->first_segment()->initialPoint(); - pointAt3 = in->first_segment()->finalPoint(); - SBasisIn = in->first_segment()->toSBasis(); - if (!onlySelected) { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); - } - } else { - pointAt1 = in->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); +bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) +{ + using Geom::X; + using Geom::Y; + + if (points.size() > 0) { + for (std::vector<Geom::Point>::iterator i = points.begin(); + i != points.end(); ++i) { + Geom::Point p = *i; + if (Geom::are_near(p, nodePoint, 0.0001)) { + return true; + } else { } - } else { - pointAt2 = in->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } + return false; +} + +void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) +{ + using Geom::X; + using Geom::Y; + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nt->_selected_nodes->allPoints(); + points.clear(); + std::vector<Geom::Point>::iterator pbegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); + pbegin = points.begin(); + points.insert(pbegin, desktop->doc2dt(n->position())); } - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } + //bool hasNodesSelected = LPEBspline::hasNodesSelected(); + if (curve->get_segment_count() < 1) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + //Si está vacÃo... + if (path_it->empty()) + continue; + //Itreadores + + Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::const_iterator curve_it2 = + ++(path_it->begin()); // outgoing curve + Geom::Path::const_iterator curve_endit = + path_it->end_default(); // this determines when the loop has to stop + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point pointAt0(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point pointAt3(0, 0); + Geom::Point nextPointAt0(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2<Geom::SBasis> SBasisIn; + Geom::D2<Geom::SBasis> SBasisOut; + Geom::CubicBezier const *cubic = NULL; + if (path_it->closed()) { + // if the path is closed, maybe we have to stop a bit earlier because the + // closing line segment has zerolength. + 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(); } - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } } - } else { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - if (nodeIsSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); - } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirÃan en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + pointAt0 = in->first_segment()->initialPoint(); + pointAt3 = in->first_segment()->finalPoint(); + SBasisIn = in->first_segment()->toSBasis(); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.0000) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + } } else { - pointAt1 = (*cubic)[1]; + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = (*cubic)[1]; + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = (*cubic)[2]; + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.000) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(weightValue); + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + } } - } else { - pointAt1 = in->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - if (nodeIsSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); - } + in->reset(); + delete in; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + nCurve->curveto(pointAt1, pointAt2, pointAt3); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt0 = out->first_segment()->initialPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } } else { - pointAt2 = (*cubic)[2]; + if (!ignoreCusp && weightValue != 0.0000) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } - } else { - pointAt2 = in->first_segment()->finalPoint(); - } } else { - if (!ignoreCusp && weightValue != 0.000) { - if (nodeIsSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, + nextPointAt1[Y] + 0.0001); + } + } else { + nextPointAt1 = (*cubic)[1]; + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, + nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = (*cubic)[2]; + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } } else { - pointAt1 = in->first_segment()->initialPoint(); + if (!ignoreCusp && weightValue != 0.0000) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } - if (nodeIsSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(weightValue); - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); - } else { - pointAt2 = in->first_segment()->finalPoint(); - } - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - } - } - in->reset(); - delete in; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva - nCurve->curveto(pointAt1, pointAt2, pointAt3); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt0 = out->first_segment()->initialPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - if (!onlySelected) { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } - } - } else { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, - nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = (*cubic)[1]; - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, - nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = (*cubic)[2]; - } + out->reset(); + delete out; + //Aberiguamos la ultima parte de la curva correspondiente al último + //segmento + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + if (path_it->closed()) { + nCurve->curveto(nextPointAt1, nextPointAt2, + path_it->begin()->initialPoint()); + nCurve->move_endpoints(path_it->begin()->initialPoint(), + path_it->begin()->initialPoint()); } else { - nextPointAt2 = out->first_segment()->finalPoint(); + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); } - } - } - out->reset(); - delete out; - //Aberiguamos la ultima parte de la curva correspondiente al último - //segmento - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - if (path_it->closed()) { - nCurve->curveto(nextPointAt1, nextPointAt2, - path_it->begin()->initialPoint()); - nCurve->move_endpoints(path_it->begin()->initialPoint(), - path_it->begin()->initialPoint()); - } else { - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; - } } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index aff4ce812..f37741a4a 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -15,44 +15,40 @@ namespace Inkscape { namespace LivePathEffect { class LPEBSpline : public Effect { - public: - LPEBSpline(LivePathEffectObject *lpeobject); - virtual ~LPEBSpline(); - - virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); - - virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } - - virtual void doEffect(SPCurve *curve); - - virtual void doBSplineFromWidget(SPCurve *curve, double value); - - virtual bool nodeIsSelected(Geom::Point nodePoint); - - virtual Gtk::Widget *newWidget(); + LPEBSpline(LivePathEffectObject *lpeobject); + virtual ~LPEBSpline(); - virtual void changeWeight(double weightValue); + virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); + virtual LPEPathFlashType pathFlashType() const { + return SUPPRESS_FLASH; + } + virtual void doEffect(SPCurve *curve); - virtual void toDefaultWeight(Gtk::Widget *widgWeight); + void doBSplineFromWidget(SPCurve *curve, double value); + bool nodeIsSelected(Geom::Point nodePoint); - virtual void toMakeCusp(Gtk::Widget *widgWeight); + virtual Gtk::Widget *newWidget(); - virtual void toWeight(); + void changeWeight(double weightValue); + void toDefaultWeight(Gtk::Widget *widgWeight); + void toMakeCusp(Gtk::Widget *widgWeight); + void toWeight(); - ScalarParam steps; + // TODO make this private + ScalarParam steps; private: - std::vector<Geom::Point> points; - BoolParam ignoreCusp; - BoolParam onlySelected; - ScalarParam weight; + std::vector<Geom::Point> points; + BoolParam ignoreCusp; + BoolParam onlySelected; + ScalarParam weight; - LPEBSpline(const LPEBSpline &); - LPEBSpline &operator=(const LPEBSpline &); + LPEBSpline(const LPEBSpline &); + LPEBSpline &operator=(const LPEBSpline &); }; -}; //namespace LivePathEffect -}; //namespace Inkscape +} //namespace LivePathEffect +} //namespace Inkscape #endif diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index a16ed7ab5..d9bf20752 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -29,17 +29,29 @@ using namespace Geom; namespace Inkscape { namespace LivePathEffect { +enum DeformationType { + DEFORMATION_ENVELOPE, + DEFORMATION_PERSPECTIVE +}; + +static const Util::EnumData<unsigned> DeformationTypeData[] = { + {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"}, + {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"} +}; + +static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData)); + LPEEnvelopePerspective::LPEEnvelopePerspective(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: - perspective(_("Perspective"), _("Perspective"), "Perspective", &wr, this, false), - Up_Left_Point(_("Top Left:"), _("Top Left - Ctrl+Alt+Click to reset"), "Up_Left_Point", &wr, this), - Up_Right_Point(_("Top Right:"), _("Top Right - Ctrl+Alt+Click to reset"), "Up_Right_Point", &wr, this), - Down_Left_Point(_("Down Left:"), _("Down Left - Ctrl+Alt+Click to reset"), "Down_Left_Point", &wr, this), - Down_Right_Point(_("Down Right:"), _("Down Right - Ctrl+Alt+Click to reset"), "Down_Right_Point", &wr, this) + deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_ENVELOPE), + Up_Left_Point(_("Top Left"), _("Top Left - Ctrl+Alt+Click to reset"), "Up_Left_Point", &wr, this), + Up_Right_Point(_("Top Right"), _("Top Right - Ctrl+Alt+Click to reset"), "Up_Right_Point", &wr, this), + Down_Left_Point(_("Down Left"), _("Down Left - Ctrl+Alt+Click to reset"), "Down_Left_Point", &wr, this), + Down_Right_Point(_("Down Right"), _("Down Right - Ctrl+Alt+Click to reset"), "Down_Right_Point", &wr, this) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&perspective)); + registerParameter( dynamic_cast<Parameter *>(&deform_type)); registerParameter( dynamic_cast<Parameter *>(&Up_Left_Point) ); registerParameter( dynamic_cast<Parameter *>(&Up_Right_Point) ); registerParameter( dynamic_cast<Parameter *>(&Down_Left_Point) ); @@ -54,7 +66,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { using Geom::X; using Geom::Y; double projmatrix[3][3]; - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ std::vector<Geom::Point> handles(4); handles[0] = Down_Left_Point; handles[1] = Up_Left_Point; @@ -144,7 +156,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { curve_endit = path_it->end_open(); } } - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix)); }else{ nCurve->moveto(project_point(curve_it1->initialPoint())); @@ -159,7 +171,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt2 = curve_it1->finalPoint(); } pointAt3 = curve_it1->finalPoint(); - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ pointAt1 = project_point(pointAt1,projmatrix); pointAt2 = project_point(pointAt2,projmatrix); pointAt3 = project_point(pointAt3,projmatrix); @@ -181,7 +193,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt2 = curve_it1->finalPoint(); } pointAt3 = curve_it1->finalPoint(); - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ pointAt1 = project_point(pointAt1,projmatrix); pointAt2 = project_point(pointAt2,projmatrix); pointAt3 = project_point(pointAt3,projmatrix); @@ -191,7 +203,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt3 = project_point(pointAt3); } nCurve->curveto(pointAt1, pointAt2, pointAt3); - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ nCurve->move_endpoints(project_point(path_it->begin()->initialPoint(),projmatrix), pointAt3); }else{ nCurve->move_endpoints(project_point(path_it->begin()->initialPoint()), pointAt3); @@ -251,13 +263,6 @@ LPEEnvelopePerspective::newWidget() vbox->set_border_width(5); 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(Gtk::Stock::CLEAR)); - resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEEnvelopePerspective::resetGrid)); - resetButton->set_size_request(140,45); - vbox->pack_start(*hbox, true,true,2); - hbox->pack_start(*resetButton, false, false,2); std::vector<Parameter *>::iterator it = param_vector.begin(); Gtk::HBox * hboxUpHandles = Gtk::manage(new Gtk::HBox(false,0)); Gtk::HBox * hboxDownHandles = Gtk::manage(new Gtk::HBox(false,0)); @@ -319,6 +324,12 @@ LPEEnvelopePerspective::newWidget() hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); vbox->pack_start(*hboxMiddle, false, true, 2); vbox->pack_start(*hboxDownHandles, true, true, 2); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR)); + resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEEnvelopePerspective::resetGrid)); + resetButton->set_size_request(140,45); + vbox->pack_start(*hbox, true,true,2); + hbox->pack_start(*resetButton, false, false,2); return dynamic_cast<Gtk::Widget *>(vbox); } @@ -411,4 +422,4 @@ LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-envelope-perspective.h b/src/live_effects/lpe-envelope-perspective.h index 6aae33936..0de9a0e35 100644 --- a/src/live_effects/lpe-envelope-perspective.h +++ b/src/live_effects/lpe-envelope-perspective.h @@ -60,7 +60,7 @@ protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); private: - BoolParam perspective; + EnumParam<unsigned> deform_type; PointReseteableParam Up_Left_Point; PointReseteableParam Up_Right_Point; PointReseteableParam Down_Left_Point; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp new file mode 100644 index 000000000..98557196d --- /dev/null +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -0,0 +1,656 @@ +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * Also to Mc- (IRC nick) for his important contribution to find real time + * values based on + * and finaly to Liam P. White for his big help on coding, that save me a lot of hours + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "live_effects/lpe-fillet-chamfer.h" + +#include <2geom/sbasis-to-bezier.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/line.h> + +#include "desktop.h" +#include "display/curve.h" +#include "helper/geom-nodetype.h" +#include "live_effects/parameter/filletchamferpointarray.h" + +// for programmatically updating knots +#include "selection.h" +#include "tools-switch.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/selectable-control-point.h" +#include "ui/tool/node.h" +#include "ui/tools/node-tool.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +using namespace Geom; +namespace Inkscape { +namespace LivePathEffect { + +const double tolerance = 0.001; +const double gapHelper = 0.00001; + +LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this), + hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false), + ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), + only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), + flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), + unit(_("Unit"), _("Unit"), "unit", &wr, this), + radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), + helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) +{ + registerParameter(&fillet_chamfer_values); + registerParameter(&unit); + registerParameter(&radius); + registerParameter(&helper_size); + registerParameter(&flexible); + registerParameter(&ignore_radius_0); + registerParameter(&only_selected); + registerParameter(&hide_knots); + + radius.param_set_range(0., infinity()); + radius.param_set_increments(1, 1); + radius.param_set_digits(4); + helper_size.param_set_range(0, infinity()); + helper_size.param_set_increments(5, 5); + helper_size.param_set_digits(0); +} + +LPEFilletChamfer::~LPEFilletChamfer() {} + +Gtk::Widget *LPEFilletChamfer::newWidget() +{ + // use manage here, because after deletion of Effect object, others might + // still be pointing to this widget. + Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); + + vbox->set_border_width(5); + vbox->set_homogeneous(false); + vbox->set_spacing(2); + std::vector<Parameter *>::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter *param = *it; + Gtk::Widget *widg = param->param_newWidget(); + if (param->param_key == "radius") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet)); + widg = widgRegistered; + if (widg) { + Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalarParameter->get_children(); + Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); + entryWidg->set_width_chars(6); + } + } else if (param->param_key == "flexible") { + Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); + widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); + } else if (param->param_key == "helper_size") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); + } else if (param->param_key == "hide_knots") { + Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); + widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide)); + } else if (param->param_key == "only_selected") { + Gtk::manage(widg); + } else if (param->param_key == "ignore_radius_0") { + Gtk::manage(widg); + } + + Glib::ustring *tip = param->param_getTooltip(); + if (widg) { + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + + Gtk::HBox *filletButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); + fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); + + filletButtonsContainer->pack_start(*fillet, true, true, 2); + Gtk::Button *inverse = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverse->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); + filletButtonsContainer->pack_start(*inverse, true, true, 2); + + Gtk::HBox *chamferButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); + chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + + chamferButtonsContainer->pack_start(*chamfer, true, true, 2); + Gtk::Button *doubleChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer")))); + doubleChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer)); + chamferButtonsContainer->pack_start(*doubleChamfer, true, true, 2); + + vbox->pack_start(*filletButtonsContainer, true, true, 2); + vbox->pack_start(*chamferButtonsContainer, true, true, 2); + + return vbox; +} + +void LPEFilletChamfer::toggleHide() +{ + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + std::vector<Geom::Point> result; + for (std::vector<Point>::const_iterator point_it = filletChamferData.begin(); + point_it != filletChamferData.end(); ++point_it) { + if (hide_knots) { + result.push_back(Point((*point_it)[X], abs((*point_it)[Y]) * -1)); + } else { + result.push_back(Point((*point_it)[X], abs((*point_it)[Y]))); + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); + refreshKnots(); +} + +void LPEFilletChamfer::toggleFlexFixed() +{ + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + std::vector<Geom::Point> result; + unsigned int i = 0; + for (std::vector<Point>::const_iterator point_it = filletChamferData.begin(); + point_it != filletChamferData.end(); ++point_it) { + if (flexible) { + result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]), + (*point_it)[Y])); + } else { + result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]), + (*point_it)[Y])); + } + i++; + } + if (flexible) { + radius.param_set_range(0., 100); + radius.param_set_value(0); + } else { + radius.param_set_range(0., infinity()); + radius.param_set_value(0); + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::updateFillet() +{ + double power = 0; + if (!flexible) { + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), "px") * -1; + } else { + power = radius; + } + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); +} + +void LPEFilletChamfer::fillet() +{ + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 1); +} + +void LPEFilletChamfer::inverse() +{ + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 2); +} + +void LPEFilletChamfer::chamfer() +{ + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 3); +} + +void LPEFilletChamfer::doubleChamfer() +{ + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 4); +} + +void LPEFilletChamfer::refreshKnots() +{ + Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); + fillet_chamfer_values.recalculate_knots(pwd2); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (tools_isactive(desktop, TOOLS_NODES)) { + tools_switch(desktop, TOOLS_SELECT); + tools_switch(desktop, TOOLS_NODES); + } +} + +bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector<Geom::Point> point) +{ + if (point.size() > 0) { + for (std::vector<Geom::Point>::iterator i = point.begin(); i != point.end(); + ++i) { + Geom::Point p = *i; + if (Geom::are_near(p, nodePoint, 2)) { + return true; + } + } + } + return false; +} +void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> const& original_pathv, double power) +{ + std::vector<Geom::Point> point; + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = nodeTool->_selected_nodes->allPoints(); + std::vector<Geom::Point>::iterator pBegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); + pBegin = point.begin(); + point.insert(pBegin, desktop->doc2dt(n->position())); + } + } + } + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + std::vector<Geom::Point> result; + int counter = 0; + for (PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + int pathCounter = 0; + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + double powerend = 0; + while (curve_it1 != curve_endit) { + powerend = power; + if (power > 0) { + powerend = counter + (power / 100); + } + if (ignore_radius_0 && (filletChamferData[counter][X] == 0 || + filletChamferData[counter][X] == counter)) { + powerend = filletChamferData[counter][X]; + } + if (filletChamferData[counter][Y] == 0) { + powerend = filletChamferData[counter][X]; + } + if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), point)) { + powerend = filletChamferData[counter][X]; + } + result.push_back(Point(powerend, filletChamferData[counter][Y])); + ++curve_it1; + ++curve_it2; + counter++; + pathCounter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::doChangeType(std::vector<Geom::Path> const& original_pathv, int type) +{ + std::vector<Geom::Point> point; + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nodeTool = + INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nodeTool->_selected_nodes->allPoints(); + std::vector<Geom::Point>::iterator pBegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); + pBegin = point.begin(); + point.insert(pBegin, desktop->doc2dt(n->position())); + } + } + } + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + std::vector<Geom::Point> result; + int counter = 0; + for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + int pathCounter = 0; + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + while (curve_it1 != curve_endit) { + bool toggle = true; + if (filletChamferData[counter][Y] == 0 || + (ignore_radius_0 && (filletChamferData[counter][X] == 0 || + filletChamferData[counter][X] == counter)) || + (only_selected && + !nodeIsSelected(curve_it1->initialPoint(), point))) { + toggle = false; + } + if (toggle) { + result.push_back(Point(filletChamferData[counter][X], type)); + } else { + result.push_back(filletChamferData[counter]); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + pathCounter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) +{ + if (SP_IS_SHAPE(lpeItem)) { + std::vector<Point> point; + PathVector const &original_pathv = SP_SHAPE(lpeItem)->_curve->get_pathvector(); + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); + for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.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(); + } + } + int counter = 0; + while (curve_it1 != curve_endit) { + Geom::NodeType nodetype; + if (counter == 0) { + if (path_it->closed()) { + nodetype = get_nodetype(path_it->back_default(), *curve_it1); + } else { + nodetype = NODE_NONE; + } + } else { + nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1); + } + if (nodetype == NODE_CUSP) { + point.push_back(Point(0, 1)); + } else { + point.push_back(Point(0, 0)); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(point); + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); + } +} + +void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) +{ + if (SP_IS_SHAPE(lpeItem)) { + fillet_chamfer_values.set_helper_size(helper_size); + fillet_chamfer_values.set_unit(unit.get_abbreviation()); + SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)->get_original_curve() : SP_SHAPE(lpeItem)->getCurve(); + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + if (!filletChamferData.empty() && getKnotsNumber(c) != (int) + filletChamferData.size()) { + PathVector const original_pathv = c->get_pathvector(); + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); + } + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); + } +} + +int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) +{ + int nKnots = c->nodes_in_path(); + PathVector const pv = c->get_pathvector(); + for (std::vector<Geom::Path>::const_iterator path_it = pv.begin(); + path_it != pv.end(); ++path_it) { + if (!(*path_it).closed()) { + nKnots--; + } + } + return nKnots; +} + +void +LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in) +{ + if (!path_in.empty()) { + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0] + .toPwSb()); + } +} + +std::vector<Geom::Path> +LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) +{ + std::vector<Geom::Path> pathvector_out; + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(path_in); + pwd2_in = remove_short_cuts(pwd2_in, .01); + Piecewise<D2<SBasis> > der = derivative(pwd2_in); + Piecewise<D2<SBasis> > n = rot90(unitVector(der)); + fillet_chamfer_values.set_pwd2(pwd2_in, n); + std::vector<Point> filletChamferData = fillet_chamfer_values.data(); + unsigned int counter = 0; + //from http://launchpadlibrarian.net/12692602/rcp.svg + const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); + for (PathVector::const_iterator path_it = path_in.begin(); + path_it != path_in.end(); ++path_it) { + if (path_it->empty()) + continue; + Geom::Path path_out; + 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(); + } + } + unsigned int counterCurves = 0; + while (curve_it1 != curve_endit) { + Coord it1_length = (*curve_it1).length(tolerance); + double time_it1, time_it2, time_it1_B, intpart; + time_it1 = modf( + fillet_chamfer_values.to_time(counter, filletChamferData[counter][X]), + &intpart); + if (filletChamferData[counter][Y] == 0) { + time_it1 = 0; + } + if (path_it->closed() && curve_it2 == curve_endit) { + time_it2 = modf(fillet_chamfer_values.to_time( + counter - counterCurves, + filletChamferData[counter - counterCurves][X]), + &intpart); + } else { + time_it2 = modf(fillet_chamfer_values.to_time( + counter + 1, filletChamferData[counter + 1][X]), + &intpart); + } + double resultLenght = 0; + time_it1_B = 1; + if (path_it->closed() && curve_it2 == curve_endit) { + resultLenght = + it1_length + fillet_chamfer_values.to_len( + counter - counterCurves, + filletChamferData[counter - counterCurves][X]); + } else { + resultLenght = + it1_length + fillet_chamfer_values.to_len( + counter + 1, filletChamferData[counter + 1][X]); + } + if (resultLenght > 0 && time_it2 != 0) { + time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght), + &intpart); + } else { + if (time_it2 == 0) { + time_it1_B = 1; + } else { + time_it1_B = gapHelper; + } + } + if (path_it->closed() && curve_it2 == curve_endit && + filletChamferData[counter - counterCurves][Y] == 0) { + time_it1_B = 1; + time_it2 = 0; + } else if (path_it->size() > counterCurves + 1 && + filletChamferData[counter + 1][Y] == 0) { + time_it1_B = 1; + time_it2 = 0; + } + if (time_it1_B < time_it1) { + time_it1_B = time_it1 + gapHelper; + } + Curve *knotCurve1 = curve_it1->portion(time_it1, time_it1_B); + if (counterCurves > 0) { + knotCurve1->setInitial(path_out.finalPoint()); + } else { + path_out.start((*curve_it1).pointAt(time_it1)); + } + Curve *knotCurve2 = (*path_it).front().portion(time_it2, 1); + if (curve_it2 != curve_endit) { + knotCurve2 = (*curve_it2).portion(time_it2, 1); + } + Point startArcPoint = knotCurve1->finalPoint(); + Point endArcPoint = (*path_it).front().pointAt(time_it2); + if (curve_it2 != curve_endit) { + endArcPoint = (*curve_it2).pointAt(time_it2); + } + double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; + double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; + Geom::CubicBezier const *cubic1 = + dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); + Ray ray1(startArcPoint, curve_it1->finalPoint()); + if (cubic1) { + ray1.setPoints((*cubic1)[2], startArcPoint); + } + Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint; + Geom::CubicBezier const *cubic2 = + dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2); + Ray ray2(curve_it1->finalPoint(), endArcPoint); + if (cubic2) { + ray2.setPoints(endArcPoint, (*cubic2)[1]); + } + Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, + endArcPoint - startArcPoint) < 0; + double angle = angle_between(ray1, ray2, ccwToggle); + double handleAngle = ray1.angle() - angle; + if (ccwToggle) { + handleAngle = ray1.angle() + angle; + } + Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; + handleAngle = ray2.angle() + angle; + if (ccwToggle) { + handleAngle = ray2.angle() - angle; + } + Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); + if (time_it1_B != 1) { + if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) { + path_out.append(*knotCurve1); + } + int type = 0; + if(path_it->closed() && curve_it2 == curve_endit){ + type = abs(filletChamferData[counter - counterCurves][Y]); + } else { + type = abs(filletChamferData[counter + 1][Y]); + } + if (type == 3 || type == 4) { + if (type == 4) { + Geom::Point central = middle_point(startArcPoint, endArcPoint); + LineSegment chamferCenter(central, curve_it1->finalPoint()); + path_out.appendNew<Geom::LineSegment>(chamferCenter.pointAt(0.5)); + } + path_out.appendNew<Geom::LineSegment>(endArcPoint); + } else if (type == 2) { + path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, + endArcPoint); + } else { + path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); + } + } else { + path_out.append(*knotCurve1); + } + if (path_it->closed() && curve_it2 == curve_endit) { + path_out.close(); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + counterCurves++; + } + pathvector_out.push_back(path_out); + } + return pathvector_out; +} + +}; //namespace LivePathEffect +}; /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offset:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h new file mode 100644 index 000000000..420425650 --- /dev/null +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -0,0 +1,87 @@ +#ifndef INKSCAPE_LPE_FILLET_CHAMFER_H +#define INKSCAPE_LPE_FILLET_CHAMFER_H + +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of hours + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glibmm/threads.h> + +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/unit.h" + +#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/effect.h" + +namespace Inkscape { +namespace LivePathEffect { + + +class LPEFilletChamfer : public Effect { +public: + LPEFilletChamfer(LivePathEffectObject *lpeobject); + virtual ~LPEFilletChamfer(); + + virtual std::vector<Geom::Path> doEffect_path(std::vector<Geom::Path> const &path_in); + + virtual void doOnApply(SPLPEItem const *lpeItem); + virtual void doBeforeEffect(SPLPEItem const *lpeItem); + virtual void adjustForNewPath(std::vector<Geom::Path> const &path_in); + virtual Gtk::Widget* newWidget(); + + int getKnotsNumber(SPCurve const *c); + void toggleHide(); + void toggleFlexFixed(); + void chamfer(); + void fillet(); + void doubleChamfer(); + void inverse(); + void updateFillet(); + void doUpdateFillet(std::vector<Geom::Path> const& original_pathv, double power); + void doChangeType(std::vector<Geom::Path> const& original_pathv, int type); + bool nodeIsSelected(Geom::Point nodePoint, std::vector<Geom::Point> points); + void refreshKnots(); + + FilletChamferPointArrayParam fillet_chamfer_values; + +private: + + BoolParam hide_knots; + BoolParam ignore_radius_0; + BoolParam only_selected; + BoolParam flexible; + UnitParam unit; + ScalarParam radius; + ScalarParam helper_size; + + LPEFilletChamfer(const LPEFilletChamfer &); + LPEFilletChamfer &operator=(const LPEFilletChamfer &); + +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index d010e75a2..1a02375cd 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -1,9 +1,9 @@ -#define INKSCAPE_LPE_SIMPLIFY_C /* * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gtkmm/box.h> -#include <gtkmm/entry.h> + +#include <gtkmm.h> + #include "live_effects/lpe-simplify.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" @@ -19,7 +19,7 @@ #include <2geom/d2.h> #include <2geom/generic-rect.h> #include <2geom/interval.h> - +#include "ui/icon-names.h" namespace Inkscape { namespace LivePathEffect { @@ -29,10 +29,14 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), - nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false), - handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false), - simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false), - simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false) + nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")) { registerParameter(dynamic_cast<Parameter *>(&steps)); registerParameter(dynamic_cast<Parameter *>(&threshold)); @@ -41,7 +45,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) registerParameter(dynamic_cast<Parameter *>(&handles)); registerParameter(dynamic_cast<Parameter *>(&simplifyindividualpaths)); registerParameter(dynamic_cast<Parameter *>(&simplifyJustCoalesce)); - threshold.param_set_range(0., Geom::infinity()); + threshold.param_set_range(0.0001, Geom::infinity()); threshold.param_set_increments(0.0001, 0.0001); threshold.param_set_digits(6); steps.param_set_range(0, 100); diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index 1026cf11c..1137ef34b 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -22,6 +22,8 @@ ink_common_sources += \ live_effects/parameter/originalpath.h \ live_effects/parameter/powerstrokepointarray.cpp \ live_effects/parameter/powerstrokepointarray.h \ + live_effects/parameter/filletchamferpointarray.cpp \ + live_effects/parameter/filletchamferpointarray.h \ live_effects/parameter/text.cpp \ live_effects/parameter/text.h \ live_effects/parameter/togglebutton.cpp \ diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index fafb1beca..b45eeb0b3 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -4,7 +4,7 @@ /* * Inkscape::LivePathEffectParameters * -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp new file mode 100644 index 000000000..457b68dd2 --- /dev/null +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -0,0 +1,656 @@ +/* + * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <2geom/piecewise.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/sbasis-geometric.h> + +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "knotholder.h" +#include "sp-lpe-item.h" +#include "selection.h" + +// needed for on-canvas editting: +#include "desktop.h" +#include "live_effects/lpeobject.h" +#include "helper/geom-nodetype.h" +#include "helper/geom-curves.h" +#include "ui/tools/node-tool.h" + +// TODO due to internal breakage in glibmm headers, +// this has to be included last. +#include <glibmm/i18n.h> + +using namespace Geom; + +namespace Inkscape { + +namespace LivePathEffect { + +FilletChamferPointArrayParam::FilletChamferPointArrayParam( + const Glib::ustring &label, const Glib::ustring &tip, + const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr, + Effect *effect) + : ArrayParam<Point>(label, tip, key, wr, effect, 0) +{ + knot_shape = SP_KNOT_SHAPE_DIAMOND; + knot_mode = SP_KNOT_MODE_XOR; + knot_color = 0x00ff0000; +} + +FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {} + +Gtk::Widget *FilletChamferPointArrayParam::param_newWidget() +{ + return NULL; + /* + Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = + Gtk::manage( + new Inkscape::UI::Widget::RegisteredTransformedPoint( + param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() + ) ); + // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Affine transf = desktop->doc2dt(); + pointwdg->setTransform(transf); + pointwdg->setValue( *this ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Change point parameter")); + + Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); + static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); + static_cast<Gtk::HBox*>(hbox)->show_all_children(); + + return dynamic_cast<Gtk::Widget *> (hbox); + */ +} + +void +FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul, + bool /*set*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if (prefs->getBool("/options/transform/rectcorners", true) && + _vector[1][X] <= 0) { + std::vector<Geom::Point> result; + for (std::vector<Point>::const_iterator point_it = _vector.begin(); + point_it != _vector.end(); ++point_it) { + Coord A = + (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2); + result.push_back(Point(A, (*point_it)[Y])); + } + param_set_and_write_new_value(result); + } + + // param_set_and_write_new_value( (*this) * postmul ); +} + +/** call this method to recalculate the controlpoints such that they stay at the + * same location relative to the new path. Useful after adding/deleting nodes to + * the path.*/ +void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( + Piecewise<D2<SBasis> > const &pwd2_in) +{ + if (!last_pwd2.empty()) { + PathVector const pathv = + path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); + PathVector last_pathv = + path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001); + std::vector<Point> result; + unsigned long counter = 0; + unsigned long counterPaths = 0; + unsigned long counterCurves = 0; + long offset = 0; + long offsetPaths = 0; + Geom::NodeType nodetype; + for (PathVector::const_iterator path_it = pathv.begin(); + path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + counterPaths++; + counter++; + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + counterCurves = 0; + while (curve_it1 != curve_endit) { + //if start a path get node type + if (counterCurves == 0) { + if (path_it->closed()) { + if (path_it->back_closed().isDegenerate()) { + nodetype = get_nodetype(path_it->back_open(), *curve_it1); + } else { + nodetype = get_nodetype(path_it->back_closed(), *curve_it1); + } + } else { + nodetype = NODE_NONE; + } + } else { + //check node type also whith straight lines because get_nodetype + //return non cusp node in a node inserted inside a straight line + //todo: if the path remove some nodes whith the result of a straight + //line but with handles, the node inserted into dont fire the knot + // because is not handle as cusp node by get_nodetype function + bool this_is_line = true; + bool next_is_line = is_straight_curve(*curve_it1); + this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); + if (this_is_line || next_is_line) { + nodetype = NODE_CUSP; + } + } + if (last_pathv.size() > pathv.size() || + (last_pathv[counterPaths].size() > counter - offset && + !are_near(curve_it1->initialPoint(), + last_pathv[counterPaths][counter - offset].initialPoint(), + 0.1))) { + if (last_pathv.size() > counterPaths && curve_it2 == curve_endit) { + if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) { + offset = abs(last_pathv[counterPaths].size() - + pathv[counterPaths].size()); + } else if (last_pathv[counterPaths].size() > + pathv[counterPaths].size()) { + offset = (abs(last_pathv[counterPaths].size() - + pathv[counterPaths].size())) * -1; + } else { + offset = 0; + } + offsetPaths += offset; + offset = offsetPaths; + } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() && + counter - offset <= last_pathv[counterPaths].size() && + are_near(curve_it1->initialPoint(), + last_pathv[counterPaths].finalPoint(), 0.1) && + !last_pathv[counterPaths].closed()) { + long e = counter - offset + 1; + std::vector<Point> tmp = _vector; + for (unsigned long i = + last_pathv[counterPaths].size() + counter - offset; + i > counterCurves - offset + 1; i--) { + + if (tmp[i - 1][X] > 0) { + double fractpart, intpart; + fractpart = modf(tmp[i - 1][X], &intpart); + _vector[e] = Point(e + fractpart, tmp[i - 1][Y]); + } else { + _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]); + } + e++; + } + //delete temp vector + std::vector<Point>().swap(tmp); + if (last_pathv.size() > counterPaths) { + last_pathv[counterPaths] = last_pathv[counterPaths].reverse(); + } + } else { + if (last_pathv.size() > counterPaths) { + if (last_pathv[counterPaths].size() < + pathv[counterPaths].size()) { + offset++; + } else if (last_pathv[counterPaths].size() > + pathv[counterPaths].size()) { + offset--; + continue; + } + } else { + offset++; + } + } + double xPos = 0; + if (_vector[1][X] > 0) { + xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + } + if (nodetype == NODE_CUSP) { + result.push_back(Point(xPos, 1)); + } else { + result.push_back(Point(xPos, 0)); + } + } else { + double xPos = _vector[counter - offset][X]; + if (_vector.size() <= (unsigned)(counter - offset)) { + if (_vector[1][X] > 0) { + xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + } else { + xPos = 0; + } + } + if (nodetype == NODE_CUSP) { + double vectorY = _vector[counter - offset][Y]; + if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) { + vectorY = 1; + } + result.push_back(Point(xPos, vectorY)); + } else { + if (_vector[1][X] < 0) { + xPos = 0; + } + result.push_back(Point(floor(xPos), 0)); + } + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + counterCurves++; + } + counterPaths++; + } + _vector = result; + write_to_SVG(); + } +} + +void FilletChamferPointArrayParam::recalculate_knots( + Piecewise<D2<SBasis> > const &pwd2_in) +{ + bool change = false; + PathVector pathv = path_from_piecewise(pwd2_in, 0.001); + if (!pathv.empty()) { + std::vector<Point> result; + int counter = 0; + int counterCurves = 0; + Geom::NodeType nodetype; + for (PathVector::const_iterator path_it = pathv.begin(); + path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + counter++; + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + counterCurves = 0; + while (curve_it1 != curve_endit) { + //if start a path get node type + if (counterCurves == 0) { + if (path_it->closed()) { + if (path_it->back_closed().isDegenerate()) { + nodetype = get_nodetype(path_it->back_open(), *curve_it1); + } else { + nodetype = get_nodetype(path_it->back_closed(), *curve_it1); + } + } else { + nodetype = NODE_NONE; + } + } else { + bool this_is_line = true; + bool next_is_line = is_straight_curve(*curve_it1); + this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); + if (this_is_line || next_is_line) { + nodetype = NODE_CUSP; + } + } + if (nodetype == NODE_CUSP) { + double vectorY = _vector[counter][Y]; + if (vectorY == 0) { + vectorY = 1; + change = true; + } + result.push_back(Point(_vector[counter][X], vectorY)); + } else { + double xPos = floor(_vector[counter][X]); + if (_vector[1][X] < 0) { + xPos = 0; + } + double vectorY = _vector[counter][Y]; + if (vectorY != 0) { + change = true; + } + result.push_back(Point(xPos, 0)); + } + ++curve_it1; + ++curve_it2; + if (curve_it2 != curve_endit) { + counter++; + } + counterCurves++; + } + } + if (change) { + _vector = result; + write_to_SVG(); + } + } +} + +void FilletChamferPointArrayParam::set_pwd2( + Piecewise<D2<SBasis> > const &pwd2_in, + Piecewise<D2<SBasis> > const &pwd2_normal_in) +{ + last_pwd2 = pwd2_in; + last_pwd2_normal = pwd2_normal_in; +} + +void FilletChamferPointArrayParam::set_helper_size(int hs) +{ + helper_size = hs; +} + +void FilletChamferPointArrayParam::set_unit(const gchar *abbr) +{ + unit = abbr; +} + +void FilletChamferPointArrayParam::updateCanvasIndicators() +{ + std::vector<Point> ts = data(); + hp.clear(); + unsigned int i = 0; + Piecewise<D2<SBasis> > const &n = get_pwd2_normal(); + for (std::vector<Point>::const_iterator point_it = ts.begin(); + point_it != ts.end(); ++point_it) { + double Xvalue = to_time(i, (*point_it)[X]); + double XPlusValue = to_time(i, -helper_size) - i; + if (Xvalue == i) { + i++; + continue; + } + Point canvas_point = last_pwd2.valueAt(Xvalue) + 0 * n.valueAt(Xvalue); + Point start_point = last_pwd2.valueAt(Xvalue + XPlusValue) + + helper_size * n.valueAt(Xvalue + XPlusValue); + Point end_point = last_pwd2.valueAt(Xvalue + XPlusValue) - + helper_size * n.valueAt(Xvalue + XPlusValue); + Geom::Path arrow; + arrow.start(start_point); + arrow.appendNew<Geom::LineSegment>(canvas_point); + arrow.appendNew<Geom::LineSegment>(end_point); + hp.push_back(arrow); + i++; + } +} + +void FilletChamferPointArrayParam::addCanvasIndicators( + SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + hp_vec.push_back(hp); +} + +double FilletChamferPointArrayParam::len_to_time(int index, double len) +{ + double t = 0; + if (last_pwd2.size() > (unsigned) index) { + if (len != 0) { + if (last_pwd2[index][0].degreesOfFreedom() != 2) { + Piecewise<D2<SBasis> > u; + u.push_cut(0); + u.push(last_pwd2[index], 1); + std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len)); + if (t_roots.size() > 0) { + t = t_roots[0]; + } + } else { + double lenghtPart = 0; + if (last_pwd2.size() > (unsigned) index) { + lenghtPart = length(last_pwd2[index], EPSILON); + } + if (std::abs(len) < lenghtPart && lenghtPart != 0) { + t = std::abs(len) / lenghtPart; + } + } + } + t = double(index) + t; + } else { + t = double(last_pwd2.size() - 1); + } + + return t; +} + +double FilletChamferPointArrayParam::time_to_len(int index, double time) +{ + double intpart; + double len = 0; + time = modf(time, &intpart); + double lenghtPart = 0; + if (last_pwd2.size() <= (unsigned) index || time == 0) { + return len; + } + if (last_pwd2[index][0].degreesOfFreedom() != 2) { + Piecewise<D2<SBasis> > u; + u.push_cut(0); + u.push(last_pwd2[index], 1); + u = portion(u, 0, time); + return length(u, 0.001) * -1; + } + lenghtPart = length(last_pwd2[index], EPSILON); + return (time * lenghtPart) * -1; +} + +double FilletChamferPointArrayParam::to_time(int index, double A) +{ + if (A > 0) { + return A; + } else { + return len_to_time(index, A); + } +} + +double FilletChamferPointArrayParam::to_len(int index, double A) +{ + if (A > 0) { + return time_to_len(index, A); + } else { + return A; + } +} + +void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, + SPKnotModeType mode, + guint32 color) +{ + knot_shape = shape; + knot_mode = mode; + knot_color = color; +} +/* +class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam +*p, unsigned int index); + virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} + + virtual void knot_set(Point const &p, Point const &origin, guint state); + virtual Point knot_get() const; + virtual void knot_click(guint state); + virtual void knot_doubleclicked(guint state); + + /Checks whether the index falls within the size of the parameter's vector/ + bool valid_index(unsigned int index) const { + return (_pparam->_vector.size() > index); + }; + +private: + FilletChamferPointArrayParam *_pparam; + unsigned int _index; +}; +/*/ + +FilletChamferPointArrayParamKnotHolderEntity:: +FilletChamferPointArrayParamKnotHolderEntity( + FilletChamferPointArrayParam *p, unsigned int index) + : _pparam(p), _index(index) {} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, + Point const &origin, + guint state) +{ + using namespace Geom; + + if (!valid_index(_index)) { + return; + } + /// @todo how about item transforms??? + Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2(); + //todo: add snapping + //Geom::Point const s = snap_knot_position(p, state); + double t = nearest_point(p, pwd2[_index]); + if (t == 1) { + t = 0.9999; + } + t += _index; + + if (_pparam->_vector.at(_index)[X] <= 0) { + _pparam->_vector.at(_index) = + Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]); + } else { + _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]); + } + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const +{ + using namespace Geom; + + if (!valid_index(_index)) { + return Point(infinity(), infinity()); + } + + Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2(); + + double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]); + Point canvas_point = pwd2.valueAt(time_it); + + _pparam->updateCanvasIndicators(); + return canvas_point; + +} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) +{ + if (state & GDK_CONTROL_MASK) { + using namespace Geom; + double type = _pparam->_vector.at(_index)[Y] + 1; + if (type > 4) { + type = 1; + } + _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); + _pparam->param_set_and_write_new_value(_pparam->_vector); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + const gchar *tip; + if (type == 3) { + tip = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else if (type == 2) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else if (type == 1) { + tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else { + tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } + this->knot->tip = g_strdup(tip); + this->knot->show(); + //} + } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) { + Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), + _pparam->_vector.at(_index).y()); + Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( + this->desktop, offset, this, _pparam->unit); + } + +} + +void +FilletChamferPointArrayParamKnotHolderEntity::knot_doubleclicked(guint state) +{ + //todo: fill the double click dialog whith this parameters in the added file + //src/ui/dialog/lpe-fillet-chamfer-properties.cpp(.h) + //My idea for when have enought time is: + //label whith radius in percent + //label whith radius in size -maybe handle units- + //entry whith actual radius -in flexible % mode or fixed -?px- + //2 radio options to switch entry from fixed or flexible, also update the + //entry + //Checkbox or two radios to swith fillet or chamfer + +} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( + Geom::Point offset) +{ + _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y()); + this->parent_holder->knot_ungrabbed_handler(this->knot, 0); +} + +void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPDesktop *desktop, + SPItem *item) +{ + recalculate_knots(get_pwd2()); + for (unsigned int i = 0; i < _vector.size(); ++i) { + if (_vector[i][Y] <= 0) { + continue; + } + const gchar *tip; + if (_vector[i][Y] == 3) { + tip = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else if (_vector[i][Y] == 2) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else if (_vector[i][Y] == 1) { + tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } else { + tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, " + "<b>Shift+click</b> open dialog"); + } + FilletChamferPointArrayParamKnotHolderEntity *e = + new FilletChamferPointArrayParamKnotHolderEntity(this, i); + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), + knot_shape, knot_mode, knot_color); + knotholder->add(e); + } + updateCanvasIndicators(); +} + +} /* namespace LivePathEffect */ + +} /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h new file mode 100644 index 000000000..93d6e9f4c --- /dev/null +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -0,0 +1,117 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H + +/* + * Inkscape::LivePathEffectParameters + * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> +#include <2geom/point.h> + +#include "live_effects/parameter/array.h" + +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class FilletChamferPointArrayParamKnotHolderEntity; + +class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> { +public: + FilletChamferPointArrayParam(const Glib::ustring &label, + const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, + Effect *effect); + virtual ~FilletChamferPointArrayParam(); + + virtual Gtk::Widget *param_newWidget(); + + virtual void param_transform_multiply(Geom::Affine const &postmul, + bool /*set*/); + + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, + guint32 color); + virtual double to_time(int index, double A); + virtual double to_len(int index, double A); + virtual double len_to_time(int index, double len); + virtual double time_to_len(int index, double time); + virtual void set_helper_size(int hs); + virtual void set_unit(const gchar *abbr); + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, + std::vector<Geom::PathVector> &hp_vec); + virtual bool providesKnotHolderEntities() const { + return true; + } + virtual void updateCanvasIndicators(); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, + SPItem *item); + + void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in, + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in); + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const { + return last_pwd2; + } + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const { + return last_pwd2_normal; + } + + void recalculate_controlpoints_for_new_pwd2( + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in); + void recalculate_knots( + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in); + friend class FilletChamferPointArrayParamKnotHolderEntity; + +private: + FilletChamferPointArrayParam(const FilletChamferPointArrayParam &); + FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &); + + SPKnotShapeType knot_shape; + SPKnotModeType knot_mode; + guint32 knot_color; + int helper_size; + const gchar *unit; + Geom::PathVector hp; + + Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2; + Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal; +}; + +class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p, + unsigned int index); + virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, + guint state); + virtual Geom::Point knot_get() const; + virtual void knot_click(guint state); + virtual void knot_doubleclicked(guint state); + virtual void knot_set_offset(Geom::Point offset); + + /*Checks whether the index falls within the size of the parameter's vector*/ + bool valid_index(unsigned int index) const { + return (_pparam->_vector.size() > index); + } + ; + +private: + FilletChamferPointArrayParam *_pparam; + unsigned int _index; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index a5de2169e..7732eee76 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -43,6 +43,15 @@ Parameter::param_write_to_repr(const char * svgd) param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } + +// In gtk2, this wasn't an issue; we could toss around +// G_MAXDOUBLE and not worry about size allocations. But +// in gtk3, it is an issue: it allocates widget size for the maxmium +// value you pass to it, leading to some insane lengths. +// If you need this to be more, please be conservative about it. +const double SCALARPARAM_G_MAXDOUBLE = 10000000000; + + /*########################################### * REAL PARAM */ @@ -51,8 +60,8 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), - min(-G_MAXDOUBLE), - max(G_MAXDOUBLE), + min(-SCALARPARAM_G_MAXDOUBLE), + max(SCALARPARAM_G_MAXDOUBLE), integer(false), defvalue(default_value), digits(2), @@ -108,8 +117,22 @@ ScalarParam::param_set_value(gdouble val) void ScalarParam::param_set_range(gdouble min, gdouble max) { - this->min = min; - this->max = max; + // if you look at client code, you'll see that many effects + // has a tendency to set an upper range of Geom::infinity(). + // Once again, in gtk2, this is not a problem. But in gtk3, + // widgets get allocated the amount of size they ask for, + // leading to excessively long widgets. + + if (min >= -SCALARPARAM_G_MAXDOUBLE) { + this->min = min; + } else { + this->min = -SCALARPARAM_G_MAXDOUBLE; + } + if (max <= SCALARPARAM_G_MAXDOUBLE) { + this->max = max; + } else { + this->max = SCALARPARAM_G_MAXDOUBLE; + } param_set_value(value); // reset value to see whether it is in ranges } diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index fecdfeda8..647986da6 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -176,7 +176,10 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const Piecewise<D2<SBasis> > const & n = _pparam->get_pwd2_normal(); Point offset_point = _pparam->_vector.at(_index); - + if (offset_point[X] > pwd2.size() || offset_point[X] < 0) { + g_warning("Broken powerstroke point at %f, I won't try to add that", offset_point[X]); + return Geom::Point(infinity(), infinity()); + } Point canvas_point = pwd2.valueAt(offset_point[X]) + offset_point[Y] * n.valueAt(offset_point[X]); return canvas_point; } diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index 03238f935..5658d238f 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -5,6 +5,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <gtkmm.h> +#include <glibmm/i18n.h> + #include "ui/widget/registered-widget.h" #include "live_effects/parameter/togglebutton.h" #include "live_effects/effect.h" @@ -14,7 +17,6 @@ #include "inkscape.h" #include "verbs.h" #include "helper-fns.h" -#include <glibmm/i18n.h> namespace Inkscape { @@ -22,13 +24,20 @@ namespace LivePathEffect { ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value ) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) + Effect* effect, bool default_value, const Glib::ustring& inactive_label, + char const * icon_active, char const * icon_inactive, + Inkscape::IconSize icon_size) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), + inactiveLabel(inactive_label), iconActive(icon_active), iconInactive(icon_inactive), iconSize(icon_size) { + checkwdg = NULL; } ToggleButtonParam::~ToggleButtonParam() { + if (_toggled_connection.connected()) { + _toggled_connection.disconnect(); + } } void @@ -54,7 +63,11 @@ ToggleButtonParam::param_getSVGValue() const Gtk::Widget * ToggleButtonParam::param_newWidget() { - Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage( + if (_toggled_connection.connected()) { + _toggled_connection.disconnect(); + } + + checkwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredToggleButton( param_label, param_tooltip, param_key, @@ -62,18 +75,81 @@ ToggleButtonParam::param_newWidget() false, param_effect->getRepr(), param_effect->getSPDoc()) ); - + GtkWidget * boxButton = gtk_hbox_new (false, 0); + GtkWidget * labelButton = gtk_label_new (""); + if (!param_label.empty()) { + if(value || inactiveLabel.empty()){ + gtk_label_set_text(GTK_LABEL(labelButton), param_label.c_str()); + }else{ + gtk_label_set_text(GTK_LABEL(labelButton), inactiveLabel.c_str()); + } + } + gtk_widget_show(labelButton); + if ( iconActive ) { + if(!iconInactive){ + iconInactive = iconActive; + } + gtk_widget_show(boxButton); + GtkWidget *iconButton = sp_icon_new(iconSize, iconActive); + if(!value){ + iconButton = sp_icon_new(iconSize, iconInactive); + } + gtk_widget_show(iconButton); + gtk_box_pack_start (GTK_BOX(boxButton), iconButton, false, false, 1); + if (!param_label.empty()) { + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); + } + }else{ + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); + } + checkwdg->add(*Gtk::manage(Glib::wrap(boxButton))); checkwdg->setActive(value); checkwdg->setProgrammatically = false; checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); - return dynamic_cast<Gtk::Widget *> (checkwdg); + _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); + + return checkwdg; +} + +void +ToggleButtonParam::refresh_button() +{ + if(!checkwdg){ + return; + } + Gtk::Widget * boxButton = checkwdg->get_child(); + if(!boxButton){ + return; + } + GList * childs = gtk_container_get_children(GTK_CONTAINER(boxButton->gobj())); + guint totalWidgets = g_list_length (childs); + if (!param_label.empty()) { + if(value || inactiveLabel.empty()){ + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), param_label.c_str()); + }else{ + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), inactiveLabel.c_str()); + } + } + if ( iconActive ) { + GdkPixbuf * iconPixbuf = sp_pixbuf_new( iconSize, iconActive ); + if(!value){ + iconPixbuf = sp_pixbuf_new( iconSize, iconInactive); + } + gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), iconPixbuf); + } } void ToggleButtonParam::param_setValue(bool newvalue) { value = newvalue; + refresh_button(); +} + +void +ToggleButtonParam::toggled() { + _signal_toggled.emit(); } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h index 9b1c71185..4e545bcfd 100644 --- a/src/live_effects/parameter/togglebutton.h +++ b/src/live_effects/parameter/togglebutton.h @@ -2,22 +2,27 @@ #define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H /* - * Inkscape::LivePathEffectParameters - * -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Copyright (C) Jabiertxo Arraiza Cenoz 2014 * * Released under GNU GPL, read the file 'COPYING' for more information */ #include <glib.h> +#include <sigc++/connection.h> +#include <sigc++/signal.h> #include "live_effects/parameter/parameter.h" +#include "icon-size.h" +#include "ui/widget/registered-widget.h" namespace Inkscape { namespace LivePathEffect { - +/** + * class ToggleButtonParam: + * represents a Gtk::ToggleButton as a Live Path Effect parameter + */ class ToggleButtonParam : public Parameter { public: ToggleButtonParam( const Glib::ustring& label, @@ -25,7 +30,11 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - bool default_value = false); + bool default_value = false, + const Glib::ustring& inactive_label = "", + char const * icon_active = NULL, + char const * icon_inactive = NULL, + Inkscape::IconSize icon_size = Inkscape::ICON_SIZE_SMALL_TOOLBAR); virtual ~ToggleButtonParam(); virtual Gtk::Widget * param_newWidget(); @@ -39,13 +48,25 @@ public: bool get_value() const { return value; }; inline operator bool() const { return value; }; + + sigc::signal<void>& signal_toggled() { return _signal_toggled; } + virtual void toggled(); private: ToggleButtonParam(const ToggleButtonParam&); ToggleButtonParam& operator=(const ToggleButtonParam&); + void refresh_button(); bool value; bool defvalue; + const Glib::ustring inactiveLabel; + const char * iconActive; + const char * iconInactive; + Inkscape::IconSize iconSize; + Inkscape::UI::Widget::RegisteredToggleButton * checkwdg; + + sigc::signal<void> _signal_toggled; + sigc::connection _toggled_connection; }; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 1ee75e381..8837fbdb1 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3950,10 +3950,6 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) { // Collect all clipped paths and masks within a single group Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc); - if(copy->attribute("inkscape:original-d")) - { - copy->setAttribute("d", copy->attribute("inkscape:original-d")); - } items_to_move = g_slist_prepend(items_to_move, copy); } diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 428e0e3dd..cda59e057 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -467,8 +467,6 @@ void SPGenericEllipse::set_shape() bool success = this->performPathEffect(c_lpe); if (success) { - sp_lpe_item_apply_to_mask(this); - sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index b3db0c1d7..2cfe97db8 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -778,31 +778,17 @@ void SPGroup::update_patheffect(bool write) { } } - -void -sp_gslist_update_by_clip_or_mask(GSList *item_list,SPItem * item) -{ - if(item->mask_ref->getObject()) { - SPObject * clipormask = item->mask_ref->getObject()->firstChild(); - item_list = g_slist_append(item_list,clipormask); - } - if(item->clip_ref->getObject()) { - SPObject * clipormask = item->clip_ref->getObject()->firstChild(); - item_list = g_slist_append(item_list,clipormask); - } -} - static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { - GSList *item_list = sp_item_group_item_list(group); - sp_gslist_update_by_clip_or_mask(item_list,group); - for ( GSList *iter = item_list; iter; iter = iter->next ) { + GSList const *item_list = sp_item_group_item_list(SP_GROUP(group)); + + for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); + if (SP_IS_GROUP(subitem)) { sp_group_perform_patheffect(SP_GROUP(subitem), topgroup, write); } else if (SP_IS_SHAPE(subitem)) { - sp_gslist_update_by_clip_or_mask(item_list,SP_ITEM(subitem)); SPCurve * c = NULL; if (SP_IS_PATH(subitem)) { @@ -813,17 +799,9 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) // only run LPEs when the shape has a curve defined if (c) { - if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { - c->transform(i2anc_affine(group, topgroup)); - } else { - c->transform(i2anc_affine(subitem, topgroup)); - } + c->transform(i2anc_affine(subitem, topgroup)); SP_LPE_ITEM(topgroup)->performPathEffect(c); - if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { - c->transform(i2anc_affine(group, topgroup).inverse()); - } else { - c->transform(i2anc_affine(subitem, topgroup).inverse()); - } + c->transform(i2anc_affine(subitem, topgroup).inverse()); SP_SHAPE(subitem)->setCurve(c, TRUE); if (write) { @@ -831,7 +809,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) gchar *str = sp_svg_write_path(c->get_pathvector()); repr->setAttribute("d", str); #ifdef GROUP_VERBOSE - g_message("sp_group_perform_patheffect writes 'd' attribute"); +g_message("sp_group_perform_patheffect writes 'd' attribute"); #endif g_free(str); } diff --git a/src/sp-item-group.h b/src/sp-item-group.h index adec35571..2004a72b8 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -88,7 +88,7 @@ public: void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true); -void sp_gslist_update_by_clip_or_mask(GSList *item_list, SPItem * item); + GSList *sp_item_group_item_list (SPGroup *group); SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const gchar *name); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 9e2eff6bb..439e44508 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -340,22 +340,6 @@ static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) { g_return_if_fail(lpeitem != NULL); - SPMask * mask = lpeitem->mask_ref->getObject(); - - if (mask) - { - if (SPLPEItem* maskChild = dynamic_cast<SPLPEItem*>(mask->firstChild())) { - sp_lpe_item_create_original_path_recursive(maskChild); - } - } - - SPClipPath * clipPath = lpeitem->clip_ref->getObject(); - if (clipPath) - { - if (SPLPEItem* clipChild = dynamic_cast<SPLPEItem*>(clipPath->firstChild())) { - sp_lpe_item_create_original_path_recursive(clipChild); - } - } if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -377,23 +361,6 @@ static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) { g_return_if_fail(lpeitem != NULL); - SPMask * mask = lpeitem->mask_ref->getObject(); - - if (mask) - { - if (SPLPEItem* maskChild = dynamic_cast<SPLPEItem*>(mask->firstChild())) { - sp_lpe_item_cleanup_original_path_recursive(maskChild); - } - } - - SPClipPath * clipPath = lpeitem->clip_ref->getObject(); - if (clipPath) - { - if (SPLPEItem* clipChild = dynamic_cast<SPLPEItem*>(clipPath->firstChild())) { - sp_lpe_item_cleanup_original_path_recursive(clipChild); - } - } - if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -639,6 +606,9 @@ bool SPLPEItem::hasPathEffectRecursive() const } } +//The next 3 functions are because the revert of the bug 1241902 +//for the moment not used + void sp_lpe_item_apply_to_clippath(SPItem * item) { diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 9d88ec732..d1fb850e1 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -325,8 +325,6 @@ g_message("sp_path_update_patheffect"); bool success = this->performPathEffect(curve); if (success && write) { - sp_lpe_item_apply_to_mask(this); - sp_lpe_item_apply_to_clippath(this); // could also do this->getRepr()->updateRepr(); but only the d attribute needs updating. #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect writes 'd' attribute"); diff --git a/src/sp-solid-color.cpp b/src/sp-solid-color.cpp new file mode 100644 index 000000000..1f606d176 --- /dev/null +++ b/src/sp-solid-color.cpp @@ -0,0 +1,97 @@ +/** @file + * @solid color class. + */ +/* Authors: + * Tavmjong Bah <tavjong@free.fr> + * + * Copyright (C) 2014 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "sp-solid-color.h" + +#include "attributes.h" +#include "style.h" +#include "xml/repr.h" + +#include "sp-factory.h" +#include "sp-item.h" +#include "style-internal.h" + +namespace { + SPObject* createSolidColor() { + return new SPSolidColor(); + } + + bool solidColorRegistered = SPFactory::instance().registerObject("svg:solidColor", createSolidColor); +} + + +/* + * Solid Color + */ +SPSolidColor::SPSolidColor() : SPPaintServer() { +} + +SPSolidColor::~SPSolidColor() { +} + +void SPSolidColor::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPPaintServer::build(doc, repr); + + this->readAttr( "style" ); + this->readAttr( "solid-color" ); + this->readAttr( "solid-opacity" ); +} + +/** + * Virtual build: set solidcolor attributes from its associated XML node. + */ + +void SPSolidColor::set(unsigned int key, const gchar* value) { + + if (SP_ATTRIBUTE_IS_CSS(key)) { + sp_style_read_from_object(this->style, this); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } else { + SPPaintServer::set(key, value); + } +} + +/** + * Virtual set: set attribute to value. + */ + +Inkscape::XML::Node* SPSolidColor::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:solidColor"); + } + + SPObject::write(xml_doc, repr, flags); + + return repr; +} + +cairo_pattern_t* SPSolidColor::pattern_new(cairo_t * /*ct*/, Geom::OptRect const &bbox, double opacity) { + + SPIColor *c = &(this->style->solid_color); + cairo_pattern_t *cp = cairo_pattern_create_rgba ( c->value.color.v.c[0], c->value.color.v.c[1], c->value.color.v.c[2], SP_SCALE24_TO_FLOAT(this->style->solid_opacity.value) * opacity ); + + return cp; +} + + +/** + * Virtual write: write object attributes to repr. + */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-solid-color.h b/src/sp-solid-color.h new file mode 100644 index 000000000..0ff09762e --- /dev/null +++ b/src/sp-solid-color.h @@ -0,0 +1,46 @@ +#ifndef SEEN_SP_SOLIDCOLOR_H +#define SEEN_SP_SOLIDCOLOR_H + +/** \file + * SPSolidColor: SVG <solidColor> implementation. + */ +/* + * Authors: Tavmjong Bah + * Copyright (C) 2012 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> +#include "color.h" +#include "sp-paint-server.h" + +#define SP_SOLIDCOLOR(obj) (dynamic_cast<SPSolidColor*>((SPObject*)obj)) +#define SP_IS_SOLIDCOLOR(obj) (dynamic_cast<const SPSolidColor*>((SPObject*)obj) != NULL) + +/** Gradient SolidColor. */ +class SPSolidColor : public SPPaintServer { +public: + SPSolidColor(); + virtual ~SPSolidColor(); + + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void set(unsigned int key, const gchar* value); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); +}; + +#endif /* !SEEN_SP_SOLIDCOLOR_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 8d4a37bf0..9ef73d56d 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -385,8 +385,6 @@ void SPSpiral::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { - sp_lpe_item_apply_to_mask(this); - sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 170a863b5..eac33ed7b 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -465,8 +465,6 @@ void SPStar::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { - sp_lpe_item_apply_to_mask(this); - sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } diff --git a/src/style.cpp b/src/style.cpp index c6a98e7f4..3691a3e48 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -153,6 +153,10 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : color_interpolation( "color-interpolation", enum_color_interpolation, SP_CSS_COLOR_INTERPOLATION_SRGB), color_interpolation_filters("color-interpolation-filters", enum_color_interpolation, SP_CSS_COLOR_INTERPOLATION_LINEARRGB), + // Solid color properties + solid_color( "solid-color" ), // SPIColor + solid_opacity( "solid-opacity", SP_SCALE24_MAX ), + // Fill properties fill( "fill" ), // SPIPaint fill_opacity( "fill-opacity", SP_SCALE24_MAX ), @@ -311,6 +315,9 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : _properties.push_back( &color_interpolation ); _properties.push_back( &color_interpolation_filters ); + _properties.push_back( &solid_color ); + _properties.push_back( &solid_opacity ); + _properties.push_back( &fill ); _properties.push_back( &fill_opacity ); _properties.push_back( &fill_rule ); @@ -390,10 +397,14 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : // _propmap.insert( std::make_pair( color_interpolation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color_interpolation ) ) ); // _propmap.insert( std::make_pair( color_interpolation_filters.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color_interpolation_filters ) ) ); + // _propmap.insert( std::make_pair( solid_color.name, reinterpret_cast<SPIBasePtr>(&SPStyle::solid_color ) ) ); + // _propmap.insert( std::make_pair( solid_opacity.name, reinterpret_cast<SPIBasePtr>(&SPStyle::solid_opacity ) ) ); + // _propmap.insert( std::make_pair( fill.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill ) ) ); // _propmap.insert( std::make_pair( fill_opacity.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill_opacity ) ) ); // _propmap.insert( std::make_pair( fill_rule.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill_rule ) ) ); + // _propmap.insert( std::make_pair( stroke.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke ) ) ); // _propmap.insert( std::make_pair( stroke_width.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_width ) ) ); // _propmap.insert( std::make_pair( stroke_linecap.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_linecap ) ) ); @@ -790,6 +801,12 @@ SPStyle::readIfUnset( gint id, gchar const *val ) { case SP_PROP_COLOR_RENDERING: color_rendering.readIfUnset( val ); break; + case SP_PROP_SOLID_COLOR: + solid_color.readIfUnset( val ); + break; + case SP_PROP_SOLID_OPACITY: + solid_opacity.readIfUnset( val ); + break; case SP_PROP_FILL: fill.readIfUnset( val ); break; @@ -1557,6 +1574,12 @@ sp_style_unset_property_attrs(SPObject *o) if (style->color_interpolation_filters.set) { repr->setAttribute("color-interpolation-filters", NULL); } + if (style->solid_color.set) { + repr->setAttribute("solid-color", NULL); + } + if (style->solid_opacity.set) { + repr->setAttribute("solid-opacity", NULL); + } if (style->fill.set) { repr->setAttribute("fill", NULL); } diff --git a/src/style.h b/src/style.h index 931dcc90e..eb8a3ed91 100644 --- a/src/style.h +++ b/src/style.h @@ -180,6 +180,11 @@ public: /** color-interpolation-filters */ SPIEnum color_interpolation_filters; + /** solid-color */ + SPIColor solid_color; + /** solid-opacity */ + SPIScale24 solid_opacity; + /** fill */ SPIPaint fill; /** fill-opacity */ diff --git a/src/svg/svg-color.cpp b/src/svg/svg-color.cpp index ca94c241f..5108b7702 100644 --- a/src/svg/svg-color.cpp +++ b/src/svg/svg-color.cpp @@ -310,6 +310,59 @@ static guint32 internal_sp_svg_read_color(gchar const *str, gchar const **end_pt *end_ptr = s; } return val; + } else if (strneq(str, "hsl(", 4)) { + + gchar *ptr = (gchar *) str + 4; + + gchar *e; // ptr after read + + double h = g_ascii_strtod(ptr, &e); // Read h (0-360) + if (ptr == e) return def; // Read failed + ptr = e; + + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + if (*ptr != ',') return def; // Need comma + ptr += 1; + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + + double s = g_ascii_strtod(ptr, &e); // Read s (percent) + if (ptr == e) return def; // Read failed + ptr = e; + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + if (*ptr != '%') return def; // Need % + ptr += 1; + + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + if (*ptr != ',') return def; // Need comma + ptr += 1; + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + + double l = g_ascii_strtod(ptr, &e); // Read l (percent) + if (ptr == e) return def; // Read failed + ptr = e; + while (*ptr && g_ascii_isspace(*ptr)) ptr += 1; // Remove any white space + if (*ptr != '%') return def; // Need % + ptr += 1; + + if (end_ptr) { + *end_ptr = ptr; + } + + + // Normalize to 0..1 + h /= 360.0; + s /= 100.0; + l /= 100.0; + + gfloat rgb[3]; + + sp_color_hsl_to_rgb_floatv( rgb, h, s, l ); + + val = static_cast<guint>(floor(CLAMP(rgb[0], 0.0, 1.0) * 255.9999)) << 24; + val |= (static_cast<guint>(floor(CLAMP(rgb[1], 0.0, 1.0) * 255.9999)) << 16); + val |= (static_cast<guint>(floor(CLAMP(rgb[2], 0.0, 1.0) * 255.9999)) << 8); + return val; + } else { gint i; if (colors.empty()) { diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 7d80f1e36..125755c48 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -78,6 +78,7 @@ set(ui_SRC dialog/layers.cpp dialog/livepatheffect-add.cpp dialog/livepatheffect-editor.cpp + dialog/lpe-fillet-chamfer-properties.cpp dialog/memory.cpp dialog/messages.cpp dialog/new-from-template.cpp @@ -198,6 +199,7 @@ set(ui_SRC dialog/layers.h dialog/livepatheffect-add.h dialog/livepatheffect-editor.h + dialog/lpe-fillet-chamfer-properties.h dialog/memory.h dialog/messages.h dialog/new-from-template.h diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index daa8aea22..1bd939707 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -114,4 +114,6 @@ ink_common_sources += \ ui/dialog/undo-history.h \ ui/dialog/xml-tree.cpp \ ui/dialog/xml-tree.h \ + ui/dialog/lpe-fillet-chamfer-properties.cpp \ + ui/dialog/lpe-fillet-chamfer-properties.h \ $(inkboard_dialogs) diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp new file mode 100644 index 000000000..a68c7ee08 --- /dev/null +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -0,0 +1,257 @@ +/** + * From the code of Liam P.White from his Power Stroke Knot dialog + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if GLIBMM_DISABLE_DEPRECATED &&HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + +#include "lpe-fillet-chamfer-properties.h" +#include <boost/lexical_cast.hpp> +#include <gtkmm/stock.h> +#include <glibmm/main.h> +#include <glibmm/i18n.h> +#include "inkscape.h" +#include "desktop.h" +#include "document.h" +#include "document-undo.h" +#include "layer-manager.h" +#include "message-stack.h" +#include "desktop-handles.h" +#include "sp-object.h" +#include "sp-item.h" +#include "verbs.h" +#include "selection.h" +#include "selection-chemistry.h" +#include "ui/icon-names.h" +#include "ui/widget/imagetoggler.h" +#include <cmath> +#include <gtkmm/radiobutton.h> +#include "util/units.h" + +//#include "event-context.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() + : _desktop(NULL), _knotpoint(NULL), _position_visible(false) +{ + Gtk::Box *mainVBox = get_vbox(); + mainVBox->set_homogeneous(false); + _layout_table.set_spacings(4); + _layout_table.resize(2, 2); + + // Layer name widgets + _fillet_chamfer_position_entry.set_activates_default(true); + _fillet_chamfer_position_label.set_label(_("Radius (pixels):")); + _fillet_chamfer_position_label.set_alignment(1.0, 0.5); + + _layout_table.attach(_fillet_chamfer_position_label, 0, 1, 0, 1, Gtk::FILL, + Gtk::FILL); + _layout_table.attach(_fillet_chamfer_position_entry, 1, 2, 0, 1, + Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + _fillet_chamfer_type_fillet.set_label(_("Fillet")); + _fillet_chamfer_type_fillet.set_group(_fillet_chamfer_type_group); + _fillet_chamfer_type_inverse_fillet.set_label(_("Inverse fillet")); + _fillet_chamfer_type_inverse_fillet.set_group(_fillet_chamfer_type_group); + _fillet_chamfer_type_chamfer.set_label(_("Chamfer")); + _fillet_chamfer_type_chamfer.set_group(_fillet_chamfer_type_group); + _fillet_chamfer_type_double_chamfer.set_label(_("Double chamfer")); + _fillet_chamfer_type_double_chamfer.set_group(_fillet_chamfer_type_group); + + mainVBox->pack_start(_layout_table, true, true, 4); + mainVBox->pack_start(_fillet_chamfer_type_fillet, true, true, 4); + mainVBox->pack_start(_fillet_chamfer_type_inverse_fillet, true, true, 4); + mainVBox->pack_start(_fillet_chamfer_type_chamfer, true, true, 4); + mainVBox->pack_start(_fillet_chamfer_type_double_chamfer, true, true, 4); + + // Buttons + _close_button.set_use_stock(true); + _close_button.set_label(Gtk::Stock::CANCEL.id); + _close_button.set_can_default(); + + _apply_button.set_use_underline(true); + _apply_button.set_can_default(); + + _close_button.signal_clicked() + .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close)); + _apply_button.signal_clicked() + .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_apply)); + + signal_delete_event().connect(sigc::bind_return( + sigc::hide(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close)), + true)); + + add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); + add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); + + _apply_button.grab_default(); + + show_all_children(); + + set_focus(_fillet_chamfer_position_entry); +} + +FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog() +{ + + _setDesktop(NULL); +} + +void FilletChamferPropertiesDialog::showDialog( + SPDesktop *desktop, Geom::Point knotpoint, + const Inkscape::LivePathEffect:: + FilletChamferPointArrayParamKnotHolderEntity *pt, + const gchar *unit) +{ + FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog(); + + dialog->_setDesktop(desktop); + dialog->_setUnit(unit); + dialog->_setKnotPoint(knotpoint); + dialog->_setPt(pt); + + dialog->set_title(_("Modify Fillet-Chamfer")); + dialog->_apply_button.set_label(_("_Modify")); + + dialog->set_modal(true); + desktop->setWindowTransient(dialog->gobj()); + dialog->property_destroy_with_parent() = true; + + dialog->show(); + dialog->present(); +} + +void FilletChamferPropertiesDialog::_apply() +{ + std::istringstream i_pos(_fillet_chamfer_position_entry.get_text()); + double d_pos, d_width; + if (i_pos >> d_pos) { + if (_fillet_chamfer_type_fillet.get_active() == true) { + d_width = 1; + } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) { + d_width = 2; + } else if (_fillet_chamfer_type_chamfer.get_active() == true) { + d_width = 3; + } else { + d_width = 4; + } + if (_flexible) { + if (d_pos > 99.99999 || d_pos < 0) { + d_pos = 0; + } + d_pos = _index + (d_pos / 100); + } else { + d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, "px"); + d_pos = d_pos * -1; + } + _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); + } + _close(); +} + +void FilletChamferPropertiesDialog::_close() +{ + _setDesktop(NULL); + destroy_(); + Glib::signal_idle().connect( + sigc::bind_return( + sigc::bind(sigc::ptr_fun(&::operator delete), this), + false + ) + ); +} + +bool FilletChamferPropertiesDialog::_handleKeyEvent(GdkEventKey *event) +{ + return false; +} + +void FilletChamferPropertiesDialog::_handleButtonEvent(GdkEventButton *event) +{ + if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) { + _apply(); + } +} + +void FilletChamferPropertiesDialog::_setKnotPoint(Geom::Point knotpoint) +{ + double position; + if (knotpoint.x() > 0) { + double intpart; + position = modf(knotpoint[Geom::X], &intpart) * 100; + _flexible = true; + _index = intpart; + _fillet_chamfer_position_label.set_label(_("Position (%):")); + } else { + _flexible = false; + std::string posConcat = + std::string(_("Position (")) + std::string(unit) + std::string(")"); + _fillet_chamfer_position_label.set_label(_(posConcat.c_str())); + position = knotpoint[Geom::X] * -1; + position = Inkscape::Util::Quantity::convert(position, "px", unit); + } + std::ostringstream s; + s.imbue(std::locale::classic()); + s << position; + _fillet_chamfer_position_entry.set_text(s.str()); + if (knotpoint.y() == 1) { + _fillet_chamfer_type_fillet.set_active(true); + } else if (knotpoint.y() == 2) { + _fillet_chamfer_type_inverse_fillet.set_active(true); + } else if (knotpoint.y() == 3) { + _fillet_chamfer_type_chamfer.set_active(true); + } else if (knotpoint.y() == 1) { + _fillet_chamfer_type_double_chamfer.set_active(true); + } +} + +void FilletChamferPropertiesDialog::_setPt( + const Inkscape::LivePathEffect:: + FilletChamferPointArrayParamKnotHolderEntity *pt) +{ + _knotpoint = const_cast< + Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>( + pt); +} + +void FilletChamferPropertiesDialog::_setUnit(const gchar *abbr) +{ + unit = abbr; +} + +void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop) +{ + if (desktop) { + Inkscape::GC::anchor(desktop); + } + if (_desktop) { + Inkscape::GC::release(_desktop); + } + _desktop = desktop; +} + +} // namespace +} // namespace +} // namespace + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h new file mode 100644 index 000000000..d3e859bff --- /dev/null +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h @@ -0,0 +1,104 @@ +/** + * + * From the code of Liam P.White from his Power Stroke Knot dialog + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H +#define INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H + +#include <2geom/point.h> +#include <gtkmm.h> +#include "live_effects/parameter/filletchamferpointarray.h" + +class SPDesktop; + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +class FilletChamferPropertiesDialog : public Gtk::Dialog { +public: + FilletChamferPropertiesDialog(); + virtual ~FilletChamferPropertiesDialog(); + + Glib::ustring getName() const { + return "LayerPropertiesDialog"; + } + + static void showDialog(SPDesktop *desktop, Geom::Point knotpoint, + const Inkscape::LivePathEffect:: + FilletChamferPointArrayParamKnotHolderEntity *pt, + const gchar *unit); + +protected: + + SPDesktop *_desktop; + Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity * + _knotpoint; + + Gtk::Label _fillet_chamfer_position_label; + Gtk::Entry _fillet_chamfer_position_entry; + Gtk::RadioButton::Group _fillet_chamfer_type_group; + Gtk::RadioButton _fillet_chamfer_type_fillet; + Gtk::RadioButton _fillet_chamfer_type_inverse_fillet; + Gtk::RadioButton _fillet_chamfer_type_chamfer; + Gtk::RadioButton _fillet_chamfer_type_double_chamfer; + + Gtk::Table _layout_table; + bool _position_visible; + double _index; + + Gtk::Button _close_button; + Gtk::Button _apply_button; + + sigc::connection _destroy_connection; + + static FilletChamferPropertiesDialog &_instance() { + static FilletChamferPropertiesDialog instance; + return instance; + } + + void _setDesktop(SPDesktop *desktop); + void _setPt(const Inkscape::LivePathEffect:: + FilletChamferPointArrayParamKnotHolderEntity *pt); + void _setUnit(const gchar *abbr); + void _apply(); + void _close(); + bool _flexible; + const gchar *unit; + void _setKnotPoint(Geom::Point knotpoint); + void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); + + bool _handleKeyEvent(GdkEventKey *event); + void _handleButtonEvent(GdkEventButton *event); + + friend class Inkscape::LivePathEffect:: + FilletChamferPointArrayParamKnotHolderEntity; + +private: + FilletChamferPropertiesDialog( + FilletChamferPropertiesDialog const &); // no copy + FilletChamferPropertiesDialog &operator=( + FilletChamferPropertiesDialog const &); // no assign +}; + +} // namespace +} // namespace +} // namespace + +#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: +// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 +// : diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index 1328372c6..569a8e154 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -53,6 +53,7 @@ public: void insertNodesAtExtrema(ExtremumType extremum); void insertNodes(); + void alertLPE(); void duplicateNodes(); void joinNodes(); void breakNodes(); @@ -104,7 +105,7 @@ private: } void _commit(CommitEvent cps); - void _done(gchar const *reason, bool alert_LPE = false); + void _done(gchar const *reason, bool alert_LPE = true); void _doneWithCleanup(gchar const *reason, bool alert_LPE = false); guint32 _getOutlineColor(ShapeRole role); diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 3beeed049..01cff5ad7 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -11,6 +11,7 @@ */ #include "live_effects/lpe-powerstroke.h" +#include "live_effects/lpe-fillet-chamfer.h" #include <string> #include <sstream> #include <deque> @@ -1300,11 +1301,20 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) _spcurve->set_pathvector(pathv); if (alert_LPE) { /// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming? - if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) { - PathEffectList effect_list = _path->getEffectList(); - LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() ); - if (lpe_pwr) { - lpe_pwr->adjustForNewPath(pathv); + if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){ + Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE); + if(thisEffect){ + LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe()); + if (lpe_pwr) { + lpe_pwr->adjustForNewPath(pathv); + } + } + thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER); + if(thisEffect){ + LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe()); + if (lpe_fll) { + lpe_fll->adjustForNewPath(pathv); + } } } } diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 0d8a2668b..56bcbef0d 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -958,40 +958,42 @@ void PenTool::_lastpointToCurve() { // avoid that if the "red_curve" contains only two points ( rect ), it doesn't stop here. if (this->npoints != 5 && !this->spiro && !this->bspline) return; - Geom::CubicBezier const * cubic; - this->p[1] = this->red_curve->last_segment()->initialPoint() + (1./3)* (Geom::Point)(this->red_curve->last_segment()->finalPoint() - this->red_curve->last_segment()->initialPoint()); + + this->p[1] = this->red_curve->last_segment()->initialPoint() + (1./3.)*(this->red_curve->last_segment()->finalPoint() - this->red_curve->last_segment()->initialPoint()); //modificate the last segment of the green curve so it creates the type of node we need - if(this->spiro||this->bspline){ - if(!this->green_curve->is_empty()){ + if (this->spiro||this->bspline) { + if (!this->green_curve->is_empty()) { Geom::Point A(0,0); Geom::Point B(0,0); Geom::Point C(0,0); Geom::Point D(0,0); - SPCurve * previous = new SPCurve(); - cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() ); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() ); //We obtain the last segment 4 points in the previous curve if ( cubic ){ A = (*cubic)[0]; B = (*cubic)[1]; - if(this->spiro){ - C = this->p[0] + (Geom::Point)(this->p[0] - this->p[1]); - }else - C = this->green_curve->last_segment()->finalPoint() + (1./3)* (Geom::Point)(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint()); + if (this->spiro) { + C = this->p[0] + (this->p[0] - this->p[1]); + } else { + C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint()); + } D = (*cubic)[3]; - }else{ + } else { A = this->green_curve->last_segment()->initialPoint(); B = this->green_curve->last_segment()->initialPoint(); - if(this->spiro) - C = this->p[0] + (Geom::Point)(this->p[0] - this->p[1]); - else - C = this->green_curve->last_segment()->finalPoint() + (1./3)* (Geom::Point)(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint()); + if (this->spiro) { + C = this->p[0] + (this->p[0] - this->p[1]); + } else { + C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint()); + } D = this->green_curve->last_segment()->finalPoint(); } + SPCurve *previous = new SPCurve(); previous->moveto(A); previous->curveto(B, C, D); - if( this->green_curve->get_segment_count() == 1){ + if ( this->green_curve->get_segment_count() == 1) { this->green_curve = previous; - }else{ + } else { //we eliminate the last segment this->green_curve->backspace(); //and we add it again with the recreation @@ -999,7 +1001,7 @@ void PenTool::_lastpointToCurve() { } } //if the last node is an union with another curve - if(this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()){ + if (this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()) { this->_bspline_spiro_start_anchor(false); } } @@ -1242,12 +1244,12 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { } } else { // Reset red curve - Geom::CubicBezier const * cubic = NULL; this->red_curve->reset(); // Destroy topmost green bpath if (this->green_bpaths) { - if (this->green_bpaths->data) + if (this->green_bpaths->data) { sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data)); + } this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data); } // Get last segment @@ -1270,17 +1272,16 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]); } - Geom::Point const pt((this->npoints < 4 - ? (Geom::Point)(crv->finalPoint()) - : this->p[3])); + Geom::Point const pt( (this->npoints < 4) ? crv->finalPoint() : this->p[3] ); this->npoints = 2; // delete the last segment of the green curve if( this->green_curve->get_segment_count() == 1){ this->npoints = 5; if (this->green_bpaths) { - if (this->green_bpaths->data) + if (this->green_bpaths->data) { sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data)); + } this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data); } this->green_curve->reset(); @@ -1289,14 +1290,16 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { } // assign the value of this->p[1] to the oposite of the green line last segment if(this->spiro){ - cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment()); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment()); if ( cubic ) { - this->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2]); + this->p[1] = (*cubic)[3] + (*cubic)[3] - (*cubic)[2]; SP_CTRL(this->c1)->moveto(this->p[0]); } else { this->p[1] = this->p[0]; } } + sp_canvas_item_hide(this->c0); + sp_canvas_item_hide(this->c1); sp_canvas_item_hide(this->cl0); sp_canvas_item_hide(this->cl1); this->state = PenTool::POINT; @@ -1607,8 +1610,7 @@ void PenTool::_bspline_spiro_motion(bool shift){ if(shift) this->p[2] = this->p[3]; }else{ - this->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2] ); - this->p[1] = Geom::Point(this->p[1][X] + 0.005,this->p[1][Y] + 0.005); + this->p[1] = (*cubic)[3] + ((*cubic)[3] - (*cubic)[2] ); } }else{ this->p[1] = this->p[0]; @@ -1659,7 +1661,7 @@ void PenTool::_bspline_spiro_end_anchor_on() C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); C = Geom::Point(C[X] + 0.005,C[Y] + 0.005); }else{ - C = this->p[3] + (Geom::Point)(this->p[3] - this->p[2] ); + C = this->p[3] + this->p[3] - this->p[2]; } if(cubic){ lastSeg->moveto((*cubic)[0]); @@ -2164,7 +2166,7 @@ void PenTool::_finishSegment(Geom::Point const p, guint const state) { pen_last_paraxial_dir = this->nextParaxialDirection(p, this->p[0], state); } - ++this->num_clicks; + ++num_clicks; if (!this->red_curve->is_empty()) { diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 65706a9dc..78988a041 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -56,15 +56,12 @@ const Glib::ustring SimpleFilterModifier::get_blend_mode() if (!(_flags & BLEND)) { return "normal"; } - if (_blend.get_active_row_number() == 5) { + + const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data(); + if (d) { + return _blend.get_active_data()->key; + } else return "normal"; - } else { - const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data(); - if (d) { - return _blend.get_active_data()->key; - } else - return "normal"; - } } void SimpleFilterModifier::set_blend_mode(const int val) diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp index 83da1a6d6..8a81b1c02 100644 --- a/src/ui/widget/registered-widget.cpp +++ b/src/ui/widget/registered-widget.cpp @@ -109,7 +109,7 @@ RegisteredToggleButton::~RegisteredToggleButton() } RegisteredToggleButton::RegisteredToggleButton (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in, char const *active_str, char const *inactive_str) - : RegisteredWidget<Gtk::ToggleButton>(label) + : RegisteredWidget<Gtk::ToggleButton>() , _active_str(active_str) , _inactive_str(inactive_str) { diff --git a/src/widgets/lpe-toolbar.cpp b/src/widgets/lpe-toolbar.cpp index e9e5af912..94d42b5eb 100644 --- a/src/widgets/lpe-toolbar.cpp +++ b/src/widgets/lpe-toolbar.cpp @@ -180,6 +180,7 @@ static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl) { UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setString("/tools/lpetool/unit", unit->abbr); @@ -281,6 +282,7 @@ void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GO tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units); g_object_set_data(holder, "tracker", tracker); Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setString("/tools/lpetool/unit", unit->abbr); diff --git a/src/widgets/node-toolbar.cpp b/src/widgets/node-toolbar.cpp index 53161857a..38e3f4fbd 100644 --- a/src/widgets/node-toolbar.cpp +++ b/src/widgets/node-toolbar.cpp @@ -229,6 +229,7 @@ static void sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tb return; } Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); NodeTool *nt = get_node_tool(); if (!nt || !(nt->_selected_nodes) ||nt->_selected_nodes->empty()) { diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp index e20811de8..8ddaccf64 100644 --- a/src/widgets/paintbucket-toolbar.cpp +++ b/src/widgets/paintbucket-toolbar.cpp @@ -83,6 +83,8 @@ static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl) // Don't adjust the offset value because we're saving the // unit and it'll be correctly handled on load. prefs->setDouble("/tools/paintbucket/offset", (gdouble)gtk_adjustment_get_value(adj)); + + g_return_if_fail(unit != NULL); prefs->setString("/tools/paintbucket/offsetunits", unit->abbr); } diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 6996786e3..c9a09e908 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -87,6 +87,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -180,6 +181,7 @@ static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar con UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); Unit const *unit = tracker->getActiveUnit(); Unit const *doc_unit = sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units; + g_return_if_fail(unit != NULL); gpointer item = g_object_get_data( tbl, "item" ); if (item && SP_IS_RECT(item)) { diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp index db93c1552..18976b329 100644 --- a/src/widgets/select-toolbar.cpp +++ b/src/widgets/select-toolbar.cpp @@ -73,6 +73,7 @@ sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) if ( bbox ) { UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker")); Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); struct { char const *key; double val; } const keyval[] = { { "X", bbox->min()[X] }, @@ -178,6 +179,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) gdouble xrel = 0; gdouble yrel = 0; Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "X" ) ); GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "Y" ) ); |
