diff options
| author | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
|---|---|---|
| committer | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
| commit | 509ca3687330fea576ea67ae6c7f31d16e66b800 (patch) | |
| tree | 9097520c54e355ded9bd0b4d6618af4e8dacdd91 /src/live_effects | |
| parent | updated to latest trunk (diff) | |
| parent | [Bug #1695016] Xaml export misses some radialGradients. (diff) | |
| download | inkscape-509ca3687330fea576ea67ae6c7f31d16e66b800.tar.gz inkscape-509ca3687330fea576ea67ae6c7f31d16e66b800.zip | |
updated to latest trunk
(bzr r14876.2.4)
Diffstat (limited to 'src/live_effects')
128 files changed, 5587 insertions, 3101 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 2728d8fcd..177397c2a 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -27,6 +27,7 @@ set(live_effects_SRC lpe-lattice.cpp lpe-lattice2.cpp lpe-line_segment.cpp + lpe-measure-line.cpp lpe-mirror_symmetry.cpp lpe-offset.cpp lpe-parallel.cpp @@ -59,7 +60,10 @@ set(live_effects_SRC parameter/array.cpp parameter/bool.cpp - parameter/filletchamferpointarray.cpp + parameter/hidden.cpp + parameter/item-reference.cpp + parameter/item.cpp + parameter/originalitem.cpp parameter/originalpath.cpp parameter/originalpatharray.cpp parameter/parameter.cpp @@ -67,8 +71,10 @@ set(live_effects_SRC parameter/path.cpp parameter/point.cpp parameter/powerstrokepointarray.cpp + parameter/satellitesarray.cpp parameter/random.cpp parameter/text.cpp + parameter/fontbutton.cpp parameter/togglebutton.cpp parameter/transformedpoint.cpp parameter/unit.cpp @@ -106,6 +112,7 @@ set(live_effects_SRC lpe-lattice.h lpe-lattice2.h lpe-line_segment.h + lpe-measure-line.h lpe-mirror_symmetry.h lpe-offset.h lpe-parallel.h @@ -139,8 +146,11 @@ set(live_effects_SRC parameter/array.h parameter/bool.h + parameter/hidden.h parameter/enum.h - parameter/filletchamferpointarray.h + parameter/item.h + parameter/item-reference.h + parameter/originalitem.h parameter/originalpath.h parameter/originalpatharray.h parameter/parameter.h @@ -148,8 +158,10 @@ set(live_effects_SRC parameter/path.h parameter/point.h parameter/powerstrokepointarray.h + parameter/satellitesarray.h parameter/random.h parameter/text.h + parameter/fontbutton.h parameter/togglebutton.h parameter/transformedpoint.h parameter/unit.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert deleted file mode 100644 index c03606eb3..000000000 --- a/src/live_effects/Makefile_insert +++ /dev/null @@ -1,117 +0,0 @@ -## Makefile.am fragment sourced by src/Makefile.am. - -ink_common_sources += \ - live_effects/effect.cpp \ - live_effects/effect.h \ - live_effects/effect-enum.h \ - live_effects/lpeobject.cpp \ - live_effects/lpeobject.h \ - live_effects/lpegroupbbox.cpp \ - live_effects/lpegroupbbox.h \ - live_effects/lpeobject-reference.cpp \ - live_effects/lpeobject-reference.h \ - live_effects/lpe-patternalongpath.cpp \ - live_effects/lpe-patternalongpath.h \ - live_effects/lpe-bendpath.cpp \ - live_effects/lpe-bendpath.h \ - live_effects/lpe-dynastroke.cpp \ - live_effects/lpe-dynastroke.h \ - live_effects/lpe-extrude.cpp \ - live_effects/lpe-extrude.h \ - live_effects/lpe-sketch.cpp \ - live_effects/lpe-sketch.h \ - live_effects/lpe-knot.cpp \ - live_effects/lpe-knot.h \ - live_effects/lpe-vonkoch.cpp \ - live_effects/lpe-vonkoch.h \ - live_effects/lpe-rough-hatches.cpp \ - live_effects/lpe-rough-hatches.h \ - live_effects/lpe-curvestitch.cpp \ - 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 \ - live_effects/lpe-interpolate.h \ - live_effects/lpe-interpolate_points.cpp \ - live_effects/lpe-interpolate_points.h \ - live_effects/lpe-test-doEffect-stack.cpp \ - live_effects/lpe-test-doEffect-stack.h \ - live_effects/lpe-bspline.cpp \ - live_effects/lpe-bspline.h \ - live_effects/lpe-lattice.cpp \ - live_effects/lpe-lattice.h \ - live_effects/lpe-lattice2.cpp \ - live_effects/lpe-lattice2.h \ - live_effects/lpe-roughen.cpp \ - live_effects/lpe-roughen.h \ - live_effects/lpe-show_handles.cpp \ - live_effects/lpe-show_handles.h \ - live_effects/lpe-simplify.cpp \ - live_effects/lpe-simplify.h \ - live_effects/lpe-envelope.cpp \ - live_effects/lpe-envelope.h \ - live_effects/lpe-spiro.cpp \ - live_effects/lpe-spiro.h \ - live_effects/lpe-tangent_to_curve.cpp \ - live_effects/lpe-tangent_to_curve.h \ - live_effects/lpe-perp_bisector.cpp \ - live_effects/lpe-perp_bisector.h \ - live_effects/spiro.h \ - live_effects/spiro.cpp \ - live_effects/spiro-converters.h \ - live_effects/spiro-converters.cpp \ - live_effects/lpe-circle_with_radius.cpp \ - live_effects/lpe-circle_with_radius.h \ - live_effects/lpe-perspective_path.cpp \ - live_effects/lpe-perspective_path.h \ - live_effects/lpe-perspective-envelope.cpp \ - live_effects/lpe-perspective-envelope.h \ - live_effects/lpe-mirror_symmetry.cpp \ - live_effects/lpe-mirror_symmetry.h \ - live_effects/lpe-circle_3pts.cpp \ - live_effects/lpe-circle_3pts.h \ - live_effects/lpe-transform_2pts.cpp \ - live_effects/lpe-transform_2pts.h \ - live_effects/lpe-angle_bisector.cpp \ - live_effects/lpe-angle_bisector.h \ - live_effects/lpe-parallel.cpp \ - live_effects/lpe-parallel.h \ - live_effects/lpe-copy_rotate.cpp \ - live_effects/lpe-copy_rotate.h \ - live_effects/lpe-powerstroke.cpp \ - live_effects/lpe-powerstroke.h \ - live_effects/lpe-powerstroke-interpolators.h \ - live_effects/lpe-offset.cpp \ - live_effects/lpe-offset.h \ - live_effects/lpe-clone-original.cpp \ - live_effects/lpe-clone-original.h \ - live_effects/lpe-ruler.cpp \ - live_effects/lpe-ruler.h \ - live_effects/lpe-recursiveskeleton.cpp \ - live_effects/lpe-recursiveskeleton.h \ - live_effects/lpe-text_label.cpp \ - live_effects/lpe-text_label.h \ - live_effects/lpe-path_length.cpp \ - live_effects/lpe-path_length.h \ - live_effects/lpe-line_segment.cpp \ - live_effects/lpe-line_segment.h \ - live_effects/lpe-bounding-box.cpp \ - live_effects/lpe-bounding-box.h \ - live_effects/lpe-attach-path.cpp \ - live_effects/lpe-attach-path.h \ - live_effects/lpe-fill-between-strokes.cpp \ - live_effects/lpe-fill-between-strokes.h \ - live_effects/lpe-fill-between-many.cpp \ - live_effects/lpe-fill-between-many.h \ - live_effects/lpe-ellipse_5pts.cpp \ - live_effects/lpe-ellipse_5pts.h \ - live_effects/lpe-jointype.cpp \ - live_effects/lpe-jointype.h \ - live_effects/lpe-taperstroke.cpp \ - live_effects/lpe-taperstroke.h \ - live_effects/lpe-bool.cpp \ - live_effects/lpe-bool.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 0f770b0ad..71d669bf6 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -16,57 +16,56 @@ namespace LivePathEffect { enum EffectType { BEND_PATH = 0, + GEARS, PATTERN_ALONG_PATH, - FREEHAND_SHAPE, - SKETCH, - ROUGH_HATCHES, + CURVE_STITCH, VONKOCH, KNOT, - GEARS, - CURVE_STITCH, - CIRCLE_WITH_RADIUS, - PERSPECTIVE_PATH, + CONSTRUCT_GRID, SPIRO, - LATTICE, - LATTICE2, - ROUGHEN, - SHOW_HANDLES, - SIMPLIFY, ENVELOPE, - CONSTRUCT_GRID, - PERP_BISECTOR, - TANGENT_TO_CURVE, - MIRROR_SYMMETRY, - CIRCLE_3PTS, - TRANSFORM_2PTS, - ANGLE_BISECTOR, - PARALLEL, - COPY_ROTATE, - OFFSET, - RULER, - BOOLOPS, INTERPOLATE, - INTERPOLATE_POINTS, - TEXT_LABEL, - PATH_LENGTH, - LINE_SEGMENT, - DOEFFECTSTACK_TEST, - BSPLINE, - DYNASTROKE, - RECURSIVE_SKELETON, - EXTRUDE, + ROUGH_HATCHES, + SKETCH, + RULER, POWERSTROKE, CLONE_ORIGINAL, + SIMPLIFY, + LATTICE2, + PERSPECTIVE_ENVELOPE, + INTERPOLATE_POINTS, + TRANSFORM_2PTS, + SHOW_HANDLES, + ROUGHEN, + BSPLINE, + JOIN_TYPE, + TAPER_STROKE, + MIRROR_SYMMETRY, + COPY_ROTATE, + BOOL_OP, ATTACH_PATH, FILL_BETWEEN_STROKES, FILL_BETWEEN_MANY, ELLIPSE_5PTS, BOUNDING_BOX, - JOIN_TYPE, - TAPER_STROKE, - PERSPECTIVE_ENVELOPE, + MEASURE_LINE, FILLET_CHAMFER, - BOOL_OP, + DOEFFECTSTACK_TEST, + ANGLE_BISECTOR, + CIRCLE_WITH_RADIUS, + CIRCLE_3PTS, + DYNASTROKE, + EXTRUDE, + LATTICE, + LINE_SEGMENT, + OFFSET, + PARALLEL, + PATH_LENGTH, + PERP_BISECTOR, + PERSPECTIVE_PATH, + RECURSIVE_SKELETON, + TANGENT_TO_CURVE, + TEXT_LABEL, 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 663fc435a..fe40920e3 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -8,12 +8,11 @@ //#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H -# include "config.h" +#include <config.h> #endif // include effects: #include "live_effects/lpe-patternalongpath.h" -#include "live_effects/effect.h" #include "live_effects/lpe-angle_bisector.h" #include "live_effects/lpe-attach-path.h" #include "live_effects/lpe-bendpath.h" @@ -40,6 +39,7 @@ #include "live_effects/lpe-lattice2.h" #include "live_effects/lpe-lattice.h" #include "live_effects/lpe-line_segment.h" +#include "live_effects/lpe-measure-line.h" #include "live_effects/lpe-mirror_symmetry.h" #include "live_effects/lpe-offset.h" #include "live_effects/lpe-parallel.h" @@ -65,30 +65,19 @@ #include "live_effects/lpe-bool.h" #include "xml/node-event-vector.h" -#include "sp-object.h" -#include "attributes.h" #include "message-stack.h" -#include "desktop.h" -#include "inkscape.h" -#include "document.h" #include "document-private.h" -#include "xml/document.h" -#include <glibmm/i18n.h> #include "ui/tools/pen-tool.h" +#include "ui/tools/node-tool.h" #include "ui/tools-switch.h" #include "knotholder.h" -#include "sp-lpe-item.h" +#include "path-chemistry.h" +#include "xml/sp-css-attr.h" #include "live_effects/lpeobject.h" -#include "live_effects/parameter/parameter.h" -#include <glibmm/ustring.h> +#include <pangomm/layout.h> #include "display/curve.h" - -#include <exception> - -#include <2geom/sbasis-to-bezier.h> -#include <2geom/affine.h> -#include <2geom/pathvector.h> - +#include <stdio.h> +#include <string.h> namespace Inkscape { @@ -96,64 +85,66 @@ namespace LivePathEffect { const Util::EnumData<EffectType> LPETypeData[] = { // {constant defined in effect-enum.h, N_("name of your effect"), "name of your effect in SVG"} -#ifdef LPE_ENABLE_TEST_EFFECTS - {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, - {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, - {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"}, - {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"}, - {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"}, - {EXTRUDE, N_("Extrude"), "extrude"}, - {LATTICE, N_("Lattice Deformation"), "lattice"}, - {LINE_SEGMENT, N_("Line Segment"), "line_segment"}, - {OFFSET, N_("Offset"), "offset"}, - {PARALLEL, N_("Parallel"), "parallel"}, - {PATH_LENGTH, N_("Path length"), "path_length"}, - {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, - {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, - {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, - {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, - {TEXT_LABEL, N_("Text label"), "text_label"}, - {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, -#endif /* 0.46 */ - {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"}, + {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"}, /* 0.47 */ - {VONKOCH, N_("VonKoch"), "vonkoch"}, - {KNOT, N_("Knot"), "knot"}, - {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"}, - {SPIRO, N_("Spiro spline"), "spiro"}, - {ENVELOPE, N_("Envelope Deformation"), "envelope"}, - {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"}, - {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, - {SKETCH, N_("Sketch"), "sketch"}, - {RULER, N_("Ruler"), "ruler"}, + {VONKOCH, N_("VonKoch"), "vonkoch"}, + {KNOT, N_("Knot"), "knot"}, + {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"}, + {SPIRO, N_("Spiro spline"), "spiro"}, + {ENVELOPE, N_("Envelope Deformation"), "envelope"}, + {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"}, + {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, + {SKETCH, N_("Sketch"), "sketch"}, + {RULER, N_("Ruler"), "ruler"}, /* 0.91 */ - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, - {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, + {POWERSTROKE, N_("Power stroke"), "powerstroke"}, + {CLONE_ORIGINAL, N_("Clone original"), "clone_original"}, /* 0.92 */ - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, - {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, - {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, - {SHOW_HANDLES, N_("Show handles"), "show_handles"}, - {ROUGHEN, N_("Roughen"), "roughen"}, - {BSPLINE, N_("BSpline"), "bspline"}, - {JOIN_TYPE, N_("Join type"), "join_type"}, - {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, - {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, - {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, //TODO:Wrong name with "-" + {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, + {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, + {SHOW_HANDLES, N_("Show handles"), "show_handles"}, + {ROUGHEN, N_("Roughen"), "roughen"}, + {BSPLINE, N_("BSpline"), "bspline"}, + {JOIN_TYPE, N_("Join type"), "join_type"}, + {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, + {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, + {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, /* Ponyscape -> Inkscape 0.92*/ - {ATTACH_PATH, N_("Attach path"), "attach_path"}, - {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, - {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, - {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, - {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, -/* MSoegtrop */ - {BOOL_OP, N_("Boolean operation"), "bool_op"}, + {BOOL_OP, N_("Boolean operation"), "bool_op"}, + {ATTACH_PATH, N_("Attach path"), "attach_path"}, + {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, + {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, + {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, + {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, +/* 9.93 */ + {MEASURE_LINE, N_("Measure Line"), "measure_line"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, +#ifdef LPE_ENABLE_TEST_EFFECTS + {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, + {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, + {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"}, + {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"}, + {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"}, + {EXTRUDE, N_("Extrude"), "extrude"}, + {LATTICE, N_("Lattice Deformation"), "lattice"}, + {LINE_SEGMENT, N_("Line Segment"), "line_segment"}, + {OFFSET, N_("Offset"), "offset"}, + {PARALLEL, N_("Parallel"), "parallel"}, + {PATH_LENGTH, N_("Path length"), "path_length"}, + {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, + {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, + {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, + {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, + {TEXT_LABEL, N_("Text label"), "text_label"}, +#endif + }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -326,6 +317,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case TRANSFORM_2PTS: neweffect = static_cast<Effect*> ( new LPETransform2Pts(lpeobj) ); break; + case MEASURE_LINE: + neweffect = static_cast<Effect*> ( new LPEMeasureLine(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; @@ -367,10 +361,14 @@ Effect::Effect(LivePathEffectObject *lpeobject) oncanvasedit_it(0), is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true), show_orig_path(false), + keep_paths(false), + is_load(true), lpeobj(lpeobject), concatenate_before_pwd2(false), sp_lpe_item(NULL), current_zoom(1), + upd_params(true), + sp_shape(NULL), sp_curve(NULL), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden @@ -407,15 +405,15 @@ Effect::doOnApply (SPLPEItem const*/*lpeitem*/) } void -Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP) +Effect::setCurrentZoom(double cZ) { - selectedNodesPoints = sNP; + current_zoom = cZ; } void -Effect::setCurrentZoom(double cZ) +Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP) { - current_zoom = cZ; + selectedNodesPoints = sNP; } bool @@ -438,6 +436,82 @@ Effect::isNodePointSelected(Geom::Point const &nodePoint) const return false; } +void +Effect::processObjects(LpeAction lpe_action) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + for (std::vector<const char *>::iterator el_it = items.begin(); + el_it != items.end(); ++el_it) { + const char * id = *el_it; + if (!id) { + return; + } + SPObject *elemref = NULL; + if ((elemref = document->getObjectById(id))) { + Inkscape::XML::Node * elemnode = elemref->getRepr(); + std::vector<SPItem*> item_list; + item_list.push_back(SP_ITEM(elemref)); + std::vector<Inkscape::XML::Node*> item_to_select; + std::vector<SPItem*> item_selected; + SPCSSAttr *css; + Glib::ustring css_str; + SPItem *item = SP_ITEM(elemref); + switch (lpe_action){ + case LPE_TO_OBJECTS: + if (item->isHidden()) { + sp_object_ref(item, 0 ); + item->deleteObject(true); + sp_object_unref(item); + } else { + if (elemnode->attribute("inkscape:path-effect")) { + sp_item_list_to_curves(item_list, item_selected, item_to_select); + } + elemnode->setAttribute("sodipodi:insensitive", NULL); + } + break; + + case LPE_ERASE: + sp_object_ref(item, 0 ); + item->deleteObject(true); + sp_object_unref(item); + break; + + case LPE_VISIBILITY: + css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style")); + if (!this->isVisible()/* && std::strcmp(elemref->getId(),sp_lpe_item->getId()) != 0*/) { + css->setAttribute("display", "none"); + } else { + css->setAttribute("display", NULL); + } + sp_repr_css_write_string(css,css_str); + elemnode->setAttribute("style", css_str.c_str()); + break; + + default: + break; + } + } + } + if (lpe_action == LPE_ERASE || lpe_action == LPE_TO_OBJECTS) { + items.clear(); + } +} + +void Effect::setCurrentShape(SPShape * shape){ + if(shape){ + sp_shape = shape; + if (!(sp_curve = sp_shape->getCurveBeforeLPE())) { + // oops + return; + } + pathvector_before_effect = sp_curve->get_pathvector(); + } +} + /** * Is performed each time before the effect is updated. */ @@ -449,35 +523,35 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/) void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/) { + is_load = false; } void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) { } - +void Effect::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) +{ +} //secret impl methods (shhhh!) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); - /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); - pathvector_before_effect = sp_curve->get_pathvector();*/ + SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item); + setCurrentShape(shape); doOnApply(lpeitem); } void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); - //printf("(SPLPEITEM*) %p\n", sp_lpe_item); SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item); - if(shape){ - sp_curve = shape->getCurve(); - pathvector_before_effect = sp_curve->get_pathvector(); - } + setCurrentShape(shape); doBeforeEffect(lpeitem); if (apply_to_clippath_and_mask && SP_IS_GROUP(sp_lpe_item)) { sp_lpe_item->apply_to_clippath(sp_lpe_item); sp_lpe_item->apply_to_mask(sp_lpe_item); } + update_helperpath(); } /** @@ -577,6 +651,7 @@ void Effect::readallParameters(Inkscape::XML::Node const* repr) { std::vector<Parameter *>::iterator it = param_vector.begin(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); while (it != param_vector.end()) { Parameter * param = *it; const gchar * key = param->param_key.c_str(); @@ -587,10 +662,17 @@ Effect::readallParameters(Inkscape::XML::Node const* repr) g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key); } } else { - // set default value - param->param_set_default(); + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() + + (Glib::ustring)"/" + + (Glib::ustring)key; + bool valid = prefs->getEntry(pref_path).isValid(); + if(valid){ + param->param_update_default(prefs->getString(pref_path).c_str()); + } else { + param->param_set_default(); + } } - ++it; } } @@ -624,15 +706,15 @@ Effect::registerParameter(Parameter * param) * Add all registered LPE knotholder handles to the knotholder */ void -Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +Effect::addHandles(KnotHolder *knotholder, SPItem *item) { using namespace Inkscape::LivePathEffect; // add handles provided by the effect itself - addKnotHolderEntities(knotholder, desktop, item); + addKnotHolderEntities(knotholder, item); // add handles provided by the effect's parameters (if any) for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) { - (*p)->addKnotHolderEntities(knotholder, desktop, item); + (*p)->addKnotHolderEntities(knotholder, item); } } @@ -667,6 +749,13 @@ Effect::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathV { } +/** + * Call to a method on nodetool to update the helper path from the effect + */ +void +Effect::update_helperpath() { + Inkscape::UI::Tools::sp_update_helperpath(); +} /** * This *creates* a new widget, management of deletion should be done by the caller @@ -698,10 +787,96 @@ Effect::newWidget() ++it; } - return dynamic_cast<Gtk::Widget *>(vbox); } +/** + * This *creates* a new widget, with default values setter + */ +Gtk::Widget * +Effect::defaultParamSet() +{ + // use manage here, because after deletion of Effect object, others might still be pointing to this widget. + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() ); + Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox() ); + Glib::ustring effectname = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_label(effectType()); + Glib::ustring effectkey = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_key(effectType()); + std::vector<Parameter *>::iterator it = param_vector.begin(); + Inkscape::UI::Widget::Registry * wr; + bool has_params = false; + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + has_params = true; + Parameter * param = *it; + Glib::ustring * tip = param->param_getTooltip(); + const gchar * key = param->param_key.c_str(); + const gchar * value = param->param_label.c_str(); + const gchar * tooltip_extra = _(". Change custom values for this parameter"); + Glib::ustring tooltip = param->param_tooltip + (Glib::ustring)tooltip_extra; + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + effectkey + + (Glib::ustring)"/" + + (Glib::ustring)key; + bool valid = prefs->getEntry(pref_path).isValid(); + const gchar * set_or_upd; + if (valid) { + set_or_upd = _("Update"); + } else { + set_or_upd = _("Set"); + } + Gtk::HBox * vbox_param = Gtk::manage( new Gtk::HBox(true) ); + Gtk::Label *parameter_label = Gtk::manage(new Gtk::Label(value, Gtk::ALIGN_START)); + parameter_label->set_use_markup(true); + parameter_label->set_use_underline (true); + parameter_label->set_ellipsize(Pango::ELLIPSIZE_END); + vbox_param->pack_start(*parameter_label, true, true, 2); + Gtk::Button *set = Gtk::manage(new Gtk::Button((Glib::ustring)set_or_upd)); + Gtk::Button *unset = Gtk::manage(new Gtk::Button(Glib::ustring(_("Unset")))); + unset->signal_clicked().connect(sigc::bind<Glib::ustring, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::unsetDefaultParam), pref_path, set, unset)); + set->signal_clicked().connect(sigc::bind<Glib::ustring, gchar *, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::setDefaultParam), pref_path, param->param_getSVGValue(), set, unset)); + if (!valid) { + unset->set_sensitive(false); + } + vbox_param->pack_start(*set, true, true, 2); + vbox_param->pack_start(*unset, true, true, 2); + + vbox_expander->pack_start(*vbox_param, true, true, 2); + } + ++it; + } + Glib::ustring tip = "<b>" + effectname + (Glib::ustring)_("</b>: Set default parameters"); + Gtk::Expander * expander = Gtk::manage(new Gtk::Expander(tip)); + expander->set_use_markup(true); + expander->add(*vbox_expander); + expander->set_expanded(false); + vbox->pack_start(*dynamic_cast<Gtk::Widget *> (expander), true, true, 2); + if (has_params) { + return dynamic_cast<Gtk::Widget *>(vbox); + } else { + return NULL; + } +} + +void +Effect::setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(pref_path, (Glib::ustring)value); + gchar * label = _("Update"); + set->set_label((Glib::ustring)label); + unset->set_sensitive(true); +} + +void +Effect::unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set, Gtk::Button *unset) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->remove(pref_path); + gchar * label = _("Set"); + set->set_label((Glib::ustring)label); + unset->set_sensitive(false); +} Inkscape::XML::Node *Effect::getRepr() { diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 898e089b7..e353eba23 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -19,7 +19,7 @@ class SPDocument; class SPDesktop; class SPItem; -class LivePathEffectObject; +class LivePathEffectObject; class SPLPEItem; class KnotHolder; class KnotHolderEntity; @@ -44,6 +44,12 @@ enum LPEPathFlashType { DEFAULT }; +enum LpeAction { + LPE_ERASE = 0, + LPE_TO_OBJECTS, + LPE_VISIBILITY +}; + class Effect { public: static Effect* New(EffectType lpenr, LivePathEffectObject *lpeobj); @@ -66,13 +72,16 @@ public: virtual void doAfterEffect (SPLPEItem const* lpeitem); virtual void doOnRemove (SPLPEItem const* lpeitem); - + virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem); void writeParamsToSVG(); virtual void acceptParamPath (SPPath const* param_path); static int acceptsNumClicks(EffectType type); int acceptsNumClicks() const { return acceptsNumClicks(effectType()); } void doAcceptPathPreparations(SPLPEItem *lpeitem); + SPShape * getCurrentShape(){ return sp_shape; }; + void setCurrentShape(SPShape * shape); + void processObjects(LpeAction lpe_action); /* * isReady() indicates whether all preparations which are necessary to apply the LPE are done, @@ -85,7 +94,7 @@ public: virtual void doEffect (SPCurve * curve); virtual Gtk::Widget * newWidget(); - + virtual Gtk::Widget * defaultParamSet(); /** * Sets all parameters to their default values and writes them to SVG. */ @@ -100,8 +109,9 @@ public: // /TODO: in view of providesOwnFlashPaths() below, this is somewhat redundant // (but spiro lpe still needs it!) virtual LPEPathFlashType pathFlashType() const { return DEFAULT; } - void addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + void addHandles(KnotHolder *knotholder, SPItem *item); std::vector<Geom::PathVector> getCanvasIndicators(SPLPEItem const* lpeitem); + void update_helperpath(); inline bool providesOwnFlashPaths() const { return provides_own_flash_paths || show_orig_path; @@ -122,7 +132,13 @@ public: void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); bool apply_to_clippath_and_mask; - + bool keep_paths; // set this to false allow retain extra generated objects, see measure line LPE + bool is_load; + bool upd_params; + BoolParam is_visible; + SPCurve * sp_curve; + Geom::PathVector pathvector_before_effect; + Geom::PathVector pathvector_after_effect; protected: Effect(LivePathEffectObject *lpeobject); @@ -139,7 +155,7 @@ protected: void registerParameter(Parameter * param); Parameter * getNextOncanvasEditableParam(); - virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPDesktop * /*desktop*/, SPItem * /*item*/) {}; + virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPItem * /*item*/) {}; virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec); @@ -147,7 +163,6 @@ protected: bool _provides_knotholder_entities; int oncanvasedit_it; - BoolParam is_visible; bool show_orig_path; // set this to true in derived effects to automatically have the original // path displayed as helperpath @@ -159,13 +174,15 @@ protected: // this boolean defaults to false, it concatenates the input path to one pwd2, // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. bool concatenate_before_pwd2; - SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. + SPShape * sp_shape; // these get stored in doBeforeEffect_impl before doEffect chain, or in performPathEffects on groups, and derived classes may do as they please with them. + std::vector<const char *> items; double current_zoom; std::vector<Geom::Point> selectedNodesPoints; - SPCurve * sp_curve; - Geom::PathVector pathvector_before_effect; + private: + void setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset); + void unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set , Gtk::Button *unset); bool provides_own_flash_paths; // if true, the standard flash path is suppressed bool is_ready; diff --git a/src/live_effects/lpe-angle_bisector.cpp b/src/live_effects/lpe-angle_bisector.cpp index 900d29e3a..56d33eb4b 100644 --- a/src/live_effects/lpe-angle_bisector.cpp +++ b/src/live_effects/lpe-angle_bisector.cpp @@ -8,16 +8,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-angle_bisector.h" - -#include <2geom/path.h> -#include <2geom/sbasis-to-bezier.h> - +#include "2geom/sbasis-to-bezier.h" #include "sp-lpe-item.h" #include "knot-holder-entity.h" #include "knotholder.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 21459f322..302165719 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -4,22 +4,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> #include <math.h> - #include "live_effects/lpe-attach-path.h" - #include "display/curve.h" -#include "sp-item.h" -#include "2geom/path.h" #include "sp-shape.h" #include "sp-text.h" -#include "2geom/bezier-curve.h" #include "2geom/path-sink.h" -#include "parameter/parameter.h" -#include "live_effects/parameter/point.h" -#include "parameter/originalpath.h" -#include "2geom/affine.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp index bc112285f..363356cac 100644 --- a/src/live_effects/lpe-bendpath.cpp +++ b/src/live_effects/lpe-bendpath.cpp @@ -6,27 +6,12 @@ */ #include "live_effects/lpe-bendpath.h" -#include "sp-shape.h" -#include "sp-item.h" -#include "sp-path.h" #include "sp-item-group.h" -#include "svg/svg.h" -#include "ui/widget/scalar.h" - -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> - #include "knot-holder-entity.h" #include "knotholder.h" - +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -#include <algorithm> - using std::vector; @@ -72,10 +57,10 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) : scale_y_rel(_("W_idth in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false), vertical_pattern(_("_Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false) { - registerParameter( dynamic_cast<Parameter *>(&bend_path) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); - registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) ); + registerParameter( &bend_path ); + registerParameter( &prop_scale); + registerParameter( &scale_y_rel); + registerParameter( &vertical_pattern); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); diff --git a/src/live_effects/lpe-bool.cpp b/src/live_effects/lpe-bool.cpp index 6c9830fbd..2930414b3 100644 --- a/src/live_effects/lpe-bool.cpp +++ b/src/live_effects/lpe-bool.cpp @@ -1,7 +1,7 @@ /* * Boolean operation live path effect * - * Copyright (C) 2016 Michael Soegtrop + * Copyright (C) 2016-2017 Michael Soegtrop * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp index 43a60d482..c83d7e3bc 100644 --- a/src/live_effects/lpe-bounding-box.cpp +++ b/src/live_effects/lpe-bounding-box.cpp @@ -3,18 +3,14 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <glibmm/i18n.h> - #include "live_effects/lpe-bounding-box.h" #include "display/curve.h" -#include "sp-item.h" -#include "2geom/path.h" #include "sp-shape.h" #include "sp-text.h" -#include "2geom/bezier-curve.h" -#include "lpe-bounding-box.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -24,8 +20,8 @@ LPEBoundingBox::LPEBoundingBox(LivePathEffectObject *lpeobject) : linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), visual_bounds(_("Visual Bounds"), _("Uses the visual bounding box"), "visualbounds", &wr, this) { - registerParameter( dynamic_cast<Parameter *>(&linked_path) ); - registerParameter( dynamic_cast<Parameter *>(&visual_bounds) ); + registerParameter(&linked_path); + registerParameter(&visual_bounds); //perceived_path = true; } @@ -45,6 +41,7 @@ void LPEBoundingBox::doEffect (SPCurve * curve) p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom())); p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom())); p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top())); + p.close(); Geom::PathVector out; out.push_back(p); curve->set_pathvector(out); diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 1423e670a..721a4ecab 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -44,12 +44,12 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) weight.param_set_range(NO_POWER, 100.0); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); - weight.param_overwrite_widget(true); + weight.param_set_undo(false); steps.param_set_range(1, 10); steps.param_set_increments(1, 1); steps.param_set_digits(0); - steps.param_overwrite_widget(true); + steps.param_set_undo(false); helper_size.param_set_range(0.0, 999.0); helper_size.param_set_increments(1, 1); @@ -86,7 +86,7 @@ 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_homogeneous(false); vbox->set_border_width(5); std::vector<Parameter *>::iterator it = param_vector.begin(); while (it != param_vector.end()) { @@ -168,6 +168,7 @@ void LPEBSpline::changeWeight(double weight_ammount) doBSplineFromWidget(curve, weight_ammount/100.0); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); + g_free(str); } } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 7823f00f0..90cf82c19 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -6,8 +6,8 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "live_effects/effect.h" +#include "live_effects/effect.h" #include <vector> namespace Inkscape { diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp index dbb1f4b6b..3410b13f2 100644 --- a/src/live_effects/lpe-circle_3pts.cpp +++ b/src/live_effects/lpe-circle_3pts.cpp @@ -15,9 +15,10 @@ #include "live_effects/lpe-circle_3pts.h" // You might need to include other 2geom files. You can add them here: -#include <2geom/path.h> #include <2geom/circle.h> #include <2geom/path-sink.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp index 8f2156044..fcefc4ec6 100644 --- a/src/live_effects/lpe-circle_with_radius.cpp +++ b/src/live_effects/lpe-circle_with_radius.cpp @@ -15,9 +15,10 @@ #include "display/curve.h" // You might need to include other 2geom files. You can add them here: -#include <2geom/pathvector.h> #include <2geom/circle.h> #include <2geom/path-sink.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> using namespace Geom; diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp index 7541c0be2..31bf0e270 100644 --- a/src/live_effects/lpe-clone-original.cpp +++ b/src/live_effects/lpe-clone-original.cpp @@ -4,20 +4,338 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-clone-original.h" - #include "display/curve.h" +#include "svg/path-string.h" +#include "svg/svg.h" +#include "sp-clippath.h" +#include "sp-mask.h" +#include "xml/sp-css-attr.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { LPECloneOriginal::LPECloneOriginal(LivePathEffectObject *lpeobject) : Effect(lpeobject), - linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this) + linkeditem(_("Linked Item:"), _("Item from which to take the original data"), "linkeditem", &wr, this), + scale(_("Scale %"), _("Scale item %"), "scale", &wr, this, 100.0), + preserve_position(_("Preserve position"), _("Preserve position"), "preserve_position", &wr, this, false), + inverse(_("Inverse clone"), _("Use LPE item as origin"), "inverse", &wr, this, false), + d(_("Clone shape -d-"), _("Clone shape -d-"), "d", &wr, this, true), + transform(_("Clone transforms"), _("Clone transforms"), "transform", &wr, this, true), + fill(_("Clone fill"), _("Clone fill"), "fill", &wr, this, false), + stroke(_("Clone stroke"), _("Clone stroke"), "stroke", &wr, this, false), + paintorder(_("Clone paint order"), _("Clone paint order"), "paintorder", &wr, this, false), + opacity(_("Clone opacity"), _("Clone opacity"), "opacity", &wr, this, false), + filter(_("Clone filter"), _("Clone filter"), "filter", &wr, this, false), + attributes("Attributes linked", "Attributes linked, comma separated atributes", "attributes", &wr, this,""), + style_attributes("Style attributes linked", "Style attributes linked, comma separated atributes", "style_attributes", &wr, this,""), + expanded(false), + origin(Geom::Point(0,0)) { - registerParameter( dynamic_cast<Parameter *>(&linked_path) ); + //0.92 compatibility + const gchar * linkedpath = this->getRepr()->attribute("linkedpath"); + if (linkedpath && strcmp(linkedpath, "") != 0){ + this->getRepr()->setAttribute("linkeditem", linkedpath); + this->getRepr()->setAttribute("linkedpath", NULL); + this->getRepr()->setAttribute("transform", "false"); + }; + + registerParameter(&linkeditem); + registerParameter(&scale); + registerParameter(&attributes); + registerParameter(&style_attributes); + registerParameter(&preserve_position); + registerParameter(&inverse); + registerParameter(&d); + registerParameter(&transform); + registerParameter(&fill); + registerParameter(&stroke); + registerParameter(&paintorder); + registerParameter(&opacity); + registerParameter(&filter); + scale.param_set_range(0.01, 999999.0); + scale.param_set_increments(1, 1); + scale.param_set_digits(2); + attributes.param_hide_canvas_text(); + style_attributes.param_hide_canvas_text(); + preserve_position_changed = preserve_position; + preserve_affine = Geom::identity(); +} + +void +LPECloneOriginal::cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, const char * attributes, const char * style_attributes, bool root) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + if ( SP_IS_GROUP(origin) && SP_IS_GROUP(dest) && SP_GROUP(origin)->getItemCount() == SP_GROUP(dest)->getItemCount() ) { + std::vector< SPObject * > childs = origin->childList(true); + size_t index = 0; + for (std::vector<SPObject * >::iterator obj_it = childs.begin(); + obj_it != childs.end(); ++obj_it) { + SPObject *dest_child = dest->nthChild(index); + cloneAttrbutes((*obj_it), dest_child, live, attributes, style_attributes, false); + index++; + } + } + //Attributes + SPShape * shape_origin = SP_SHAPE(origin); + SPPath * path_origin = SP_PATH(origin); + SPShape * shape_dest = SP_SHAPE(dest); + SPMask *mask_origin = SP_ITEM(origin)->mask_ref->getObject(); + SPMask *mask_dest = SP_ITEM(dest)->mask_ref->getObject(); + if(mask_origin && mask_dest) { + std::vector<SPObject*> mask_list = mask_origin->childList(true); + std::vector<SPObject*> mask_list_dest = mask_dest->childList(true); + if (mask_list.size() == mask_list_dest.size()) { + size_t i = 0; + for ( std::vector<SPObject*>::const_iterator iter=mask_list.begin();iter!=mask_list.end();++iter) { + SPObject * mask_data = *iter; + SPObject * mask_dest_data = mask_list_dest[i]; + cloneAttrbutes(mask_data, mask_dest_data, live, attributes, style_attributes, false); + i++; + } + } + } + SPClipPath *clippath_origin = SP_ITEM(origin)->clip_ref->getObject(); + SPClipPath *clippath_dest = SP_ITEM(dest)->clip_ref->getObject(); + if(clippath_origin && clippath_dest) { + std::vector<SPObject*> clippath_list = clippath_origin->childList(true); + std::vector<SPObject*> clippath_list_dest = clippath_dest->childList(true); + if (clippath_list.size() == clippath_list_dest.size()) { + size_t i = 0; + for ( std::vector<SPObject*>::const_iterator iter=clippath_list.begin();iter!=clippath_list.end();++iter) { + SPObject * clippath_data = *iter; + SPObject * clippath_dest_data = clippath_list_dest[i]; + cloneAttrbutes(clippath_data, clippath_dest_data, live, attributes, style_attributes, false); + i++; + } + } + } + gchar ** attarray = g_strsplit(attributes, ",", 0); + gchar ** iter = attarray; + Geom::Affine affine_dest = Geom::identity(); + Geom::Affine affine_origin = Geom::identity(); + Geom::Affine affine_previous = Geom::identity(); + sp_svg_transform_read(SP_ITEM(dest)->getAttribute("transform"), &affine_dest); + sp_svg_transform_read(SP_ITEM(origin)->getAttribute("transform"), &affine_origin); + while (*iter != NULL) { + const char* attribute = (*iter); + if ( std::strcmp(attribute, "transform") == 0 ) { + if (preserve_position) { + Geom::Affine dest_affine = Geom::identity(); + if (root) { + dest_affine *= affine_origin; + if (preserve_affine == Geom::identity()) { + dest_affine *= Geom::Translate(affine_dest.translation()); + } + dest_affine *= Geom::Translate(affine_origin.translation()).inverse(); + dest_affine *= Geom::Translate(preserve_affine.translation()); + affine_previous = preserve_affine; + preserve_affine = Geom::identity(); + gchar * str = sp_svg_transform_write(dest_affine); + SP_ITEM(dest)->getRepr()->setAttribute("transform", str); + g_free(str); + } + } else { + gchar * str = sp_svg_transform_write(affine_origin); + SP_ITEM(dest)->getRepr()->setAttribute("transform", str); + g_free(str); + } + } else if ( shape_dest && shape_origin && live && (std::strcmp(attribute, "d") == 0)) { + SPCurve *c = NULL; + if (inverse) { + c = shape_origin->getCurveBeforeLPE(); + } else { + c = shape_origin->getCurve(); + } + if (c) { + Geom::PathVector c_pv = c->get_pathvector(); + Geom::OptRect orig_bbox = SP_ITEM(origin)->geometricBounds(); + Geom::OptRect dest_bbox = SP_ITEM(dest)->geometricBounds(); + if (dest_bbox && orig_bbox && root) { + Geom::Point orig_point = (*orig_bbox).corner(0); + Geom::Point dest_point = (*dest_bbox).corner(0); + if (scale != 100.0) { + double scale_affine = scale/100.0; + Geom::Scale scale = Geom::Scale(scale_affine); + c_pv *= Geom::Translate(orig_point).inverse(); + c_pv *= scale; + c_pv *= Geom::Translate(orig_point); + } + if (preserve_position) { + c_pv *= Geom::Translate(dest_point - orig_point); + } + } + if (inverse) { + c_pv *= i2anc_affine(origin, sp_lpe_item); + } else { + c_pv *= i2anc_affine(dest, sp_lpe_item); + } + c->set_pathvector(c_pv); + if (!path_origin) { + shape_dest->setCurveInsync(c, TRUE); + gchar *str = sp_svg_write_path(c_pv); + dest->getRepr()->setAttribute(attribute, str); + g_free(str); + } else { + shape_dest->setCurve(c, TRUE); + } + c->unref(); + } else { + dest->getRepr()->setAttribute(attribute, NULL); + } + } else { + dest->getRepr()->setAttribute(attribute, origin->getRepr()->attribute(attribute)); + } + iter++; + } + g_strfreev (attarray); + SPCSSAttr *css_origin = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css_origin, origin->getRepr()->attribute("style")); + SPCSSAttr *css_dest = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css_dest, dest->getRepr()->attribute("style")); + gchar ** styleattarray = g_strsplit(style_attributes, ",", 0); + gchar ** styleiter = styleattarray; + while (*styleiter != NULL) { + const char* attribute = (*styleiter); + const char* origin_attribute = sp_repr_css_property(css_origin, attribute, ""); + if (!strlen(origin_attribute)) { //==0 + sp_repr_css_set_property (css_dest, attribute, NULL); + } else { + sp_repr_css_set_property (css_dest, attribute, origin_attribute); + } + styleiter++; + } + g_strfreev (styleattarray); + Glib::ustring css_str; + sp_repr_css_write_string(css_dest,css_str); + dest->getRepr()->setAttribute("style", css_str.c_str()); +} + +void +LPECloneOriginal::doBeforeEffect (SPLPEItem const* lpeitem){ + if (linkeditem.linksToItem()) { + linkeditem.setInverse(inverse); + if ( preserve_position_changed != preserve_position ) { + if (!preserve_position) { + sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &preserve_affine); + } + preserve_position_changed = preserve_position; + } + Glib::ustring attr = ""; + if (d) { + attr.append("d,"); + } + if (transform) { + attr.append("transform,"); + } + attr.append(Glib::ustring(attributes.param_getSVGValue()).append(",")); + if (attr.size() && !Glib::ustring(attributes.param_getSVGValue()).size()) { + attr.erase (attr.size()-1, 1); + } + Glib::ustring style_attr = ""; + if (fill) { + style_attr.append("fill,").append("fill-rule,"); + } + if (stroke) { + style_attr.append("stroke,").append("stroke-width,").append("stroke-linecap,").append("stroke-linejoin,"); + style_attr.append("stroke-opacity,").append("stroke-miterlimit,").append("stroke-dasharray,"); + style_attr.append("stroke-opacity,").append("stroke-dashoffset,").append("marker-start,"); + style_attr.append("marker-mid,").append("marker-end,"); + } + if (paintorder) { + style_attr.append("paint-order,"); + } + if (filter) { + style_attr.append("filter,"); + } + if (opacity) { + style_attr.append("opacity,"); + } + if (style_attr.size() && !Glib::ustring(style_attributes.param_getSVGValue()).size()) { + style_attr.erase (style_attr.size()-1, 1); + } + style_attr.append(Glib::ustring(style_attributes.param_getSVGValue()).append(",")); + + SPItem * from = inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject()); + SPItem * to = !inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject()); + cloneAttrbutes(from, to, true, g_strdup(attr.c_str()), g_strdup(style_attr.c_str()), true); + Geom::OptRect bbox = from->geometricBounds(); + if (bbox && preserve_position && origin != Geom::Point(0,0)) { + origin = (*bbox).corner(0) - origin; + to->transform *= Geom::Translate(origin); + } + bbox = from->geometricBounds(); + if (bbox && preserve_position) { + origin = (*bbox).corner(0); + } + } +} + + +Gtk::Widget * +LPECloneOriginal::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); + Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vbox_expander->set_border_width(0); + vbox_expander->set_spacing(2); + std::vector<Parameter *>::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + if (param->param_key == "linkedpath") { + ++it; + continue; + } + Gtk::Widget * widg = param->param_newWidget(); + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + if (param->param_key != "attributes" && + param->param_key != "style_attributes") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show attributes override")))); + expander->add(*vbox_expander); + expander->set_expanded(expanded); + expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPECloneOriginal::onExpanderChanged) ); + vbox->pack_start(*expander, true, true, 2); + return dynamic_cast<Gtk::Widget *>(vbox); +} + +void +LPECloneOriginal::onExpanderChanged() +{ + expanded = expander->get_expanded(); + if(expanded) { + expander->set_label (Glib::ustring(_("Hide attributes override"))); + } else { + expander->set_label (Glib::ustring(_("Show attributes override"))); + } } LPECloneOriginal::~LPECloneOriginal() @@ -25,12 +343,21 @@ LPECloneOriginal::~LPECloneOriginal() } -void LPECloneOriginal::doEffect (SPCurve * curve) +void +LPECloneOriginal::transform_multiply(Geom::Affine const& postmul, bool set) +{ + if (linkeditem.linksToItem()) { + linkeditem.getObject()->requestModified(SP_OBJECT_MODIFIED_FLAG); + } +} + +void +LPECloneOriginal::doEffect (SPCurve * curve) { - if ( linked_path.linksToPath() ) { - Geom::PathVector linked_pathv = linked_path.get_pathvector(); - if ( !linked_pathv.empty() ) { - curve->set_pathvector(linked_pathv); + if (linkeditem.linksToItem() && !inverse) { + SPShape * shape = getCurrentShape(); + if(shape){ + curve->set_pathvector(shape->getCurve()->get_pathvector()); } } } diff --git a/src/live_effects/lpe-clone-original.h b/src/live_effects/lpe-clone-original.h index abf65ded8..9bab8553f 100644 --- a/src/live_effects/lpe-clone-original.h +++ b/src/live_effects/lpe-clone-original.h @@ -8,24 +8,48 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include <gtkmm/expander.h> #include "live_effects/effect.h" +#include "live_effects/parameter/originalitem.h" #include "live_effects/parameter/originalpath.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/point.h" +#include "live_effects/parameter/text.h" +#include "live_effects/lpegroupbbox.h" namespace Inkscape { namespace LivePathEffect { -class LPECloneOriginal : public Effect { +class LPECloneOriginal : public Effect, GroupBBoxEffect { public: LPECloneOriginal(LivePathEffectObject *lpeobject); virtual ~LPECloneOriginal(); - virtual void doEffect (SPCurve * curve); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); + virtual Gtk::Widget * newWidget(); + void onExpanderChanged(); + void cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, const char * attributes, const char * style_attributes, bool root); private: - OriginalPathParam linked_path; - -private: + OriginalItemParam linkeditem; + ScalarParam scale; + BoolParam preserve_position; + BoolParam inverse; + BoolParam d; + BoolParam transform; + BoolParam fill; + BoolParam stroke; + BoolParam paintorder; + BoolParam opacity; + BoolParam filter; + TextParam attributes; + TextParam style_attributes; + Geom::Point origin; + bool preserve_position_changed; + bool expanded; + Gtk::Expander * expander; + Geom::Affine preserve_affine; LPECloneOriginal(const LPECloneOriginal&); LPECloneOriginal& operator=(const LPECloneOriginal&); }; diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp index b1e0edaac..db620fa95 100644 --- a/src/live_effects/lpe-constructgrid.cpp +++ b/src/live_effects/lpe-constructgrid.cpp @@ -10,12 +10,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-constructgrid.h" - -#include <2geom/path.h> -#include <2geom/transforms.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -27,8 +24,8 @@ LPEConstructGrid::LPEConstructGrid(LivePathEffectObject *lpeobject) : nr_x(_("Size _X:"), _("The size of the grid in X direction."), "nr_x", &wr, this, 5), nr_y(_("Size _Y:"), _("The size of the grid in Y direction."), "nr_y", &wr, this, 5) { - registerParameter( dynamic_cast<Parameter *>(&nr_x) ); - registerParameter( dynamic_cast<Parameter *>(&nr_y) ); + registerParameter(&nr_x); + registerParameter(&nr_y); nr_x.param_make_integer(); nr_y.param_make_integer(); diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index efea76039..3abcbf217 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -11,38 +11,32 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> +#include <gtkmm.h> #include <gdk/gdk.h> #include <2geom/path-intersection.h> #include <2geom/sbasis-to-bezier.h> +#include <2geom/intersection-graph.h> #include "live_effects/lpe-copy_rotate.h" -#include <2geom/path.h> -#include <2geom/transforms.h> -#include <2geom/angle.h> - -#include "knot-holder-entity.h" -#include "knotholder.h" +#include "display/curve.h" +#include "svg/path-string.h" +#include "svg/svg.h" +#include "style.h" +#include "helper/geom.h" +#include "xml/sp-css-attr.h" +#include "path-chemistry.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { -namespace CR { - -class KnotHolderEntityStartingAngle : public LPEKnotHolderEntity { -public: - KnotHolderEntityStartingAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; +static const Util::EnumData<RotateMethod> RotateMethodData[RM_END] = { + { RM_NORMAL, N_("Normal"), "normal" }, + { RM_KALEIDOSCOPE, N_("Kaleidoscope"), "kaleidoskope" }, + { RM_FUSE, N_("Fuse paths"), "fuse_paths" } }; - -class KnotHolderEntityRotationAngle : public LPEKnotHolderEntity { -public: - KnotHolderEntityRotationAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - -} // namespace CR +static const Util::EnumDataConverter<RotateMethod> +RMConverter(RotateMethodData, RM_END); bool pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) @@ -61,28 +55,49 @@ pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const & LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : Effect(lpeobject), - origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"), - starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), - rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0), - num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 6), + method(_("Method:"), _("Rotate methods"), "method", RMConverter, &wr, this, RM_NORMAL), + origin(_("Origin"), _("Adjust origin of the rotation"), "origin", &wr, this, _("Adjust origin of the rotation")), + starting_point(_("Start point"), _("Starting point to define start angle"), "starting_point", &wr, this, _("Adjust starting point to define start angle")), + starting_angle(_("Starting angle"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), + rotation_angle(_("Rotation angle"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0), + num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 6), + gap(_("Gap"), _("Gap"), "gap", &wr, this, -0.0001), copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true), - fuse_paths(_("Fuse paths"), _("Fuse paths by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false), + mirror_copies(_("Mirror copies"), _("Mirror between copies"), "mirror_copies", &wr, this, false), + split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false), dist_angle_handle(100.0) { show_orig_path = true; _provides_knotholder_entities = true; - apply_to_clippath_and_mask = true; - + //0.92 compatibility + if (this->getRepr()->attribute("fuse_paths") && strcmp(this->getRepr()->attribute("fuse_paths"), "true") == 0){ + this->getRepr()->setAttribute("fuse_paths", NULL); + this->getRepr()->setAttribute("method", "kaleidoskope"); + this->getRepr()->setAttribute("mirror_copies", "true"); + }; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter(&copies_to_360); - registerParameter(&fuse_paths); + registerParameter(&method); + registerParameter(&num_copies); registerParameter(&starting_angle); + registerParameter(&starting_point); registerParameter(&rotation_angle); - registerParameter(&num_copies); + registerParameter(&gap); registerParameter(&origin); + registerParameter(&copies_to_360); + registerParameter(&mirror_copies); + registerParameter(&split_items); + gap.param_set_range(-99999.0, 99999.0); + gap.param_set_increments(0.1, 0.1); + gap.param_set_digits(5); + num_copies.param_set_range(1, 999999); num_copies.param_make_integer(true); - num_copies.param_set_range(0, 1000); + apply_to_clippath_and_mask = true; + previous_num_copies = num_copies; + previous_origin = Geom::Point(0,0); + previous_start_point = Geom::Point(0,0); + starting_point.param_widget_is_visible(false); + reset = false; } LPECopyRotate::~LPECopyRotate() @@ -91,6 +106,242 @@ LPECopyRotate::~LPECopyRotate() } void +LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem) +{ + if (split_items) { + is_load = false; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + items.clear(); + container = dynamic_cast<SPObject *>(sp_lpe_item->parent); + Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot(); + Inkscape::XML::Node *root_origin = document->getReprRoot(); + if (root_origin != root) { + return; + } + if (previous_num_copies != num_copies) { + gint numcopies_gap = previous_num_copies - num_copies; + if (numcopies_gap > 0 && num_copies != 0) { + guint counter = num_copies - 1; + while (numcopies_gap > 0) { + const char * id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str()); + if (!id || strlen(id) == 0) { + return; + } + SPObject *elemref = NULL; + if ((elemref = document->getObjectById(id))) { + SP_ITEM(elemref)->setHidden(true); + } + counter++; + numcopies_gap--; + } + } + previous_num_copies = num_copies; + } + SPObject *elemref = NULL; + const char * id = g_strdup(Glib::ustring("rotated-").append("0").append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str()); + guint counter = 0; + while((elemref = document->getObjectById(id))) { + id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str()); + if (SP_ITEM(elemref)->isHidden()) { + items.push_back(id); + } + counter++; + } + Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))); + for (size_t i = 1; i < num_copies; ++i) { + Geom::Affine r = Geom::identity(); + if(mirror_copies && i%2 != 0) { + r *= Geom::Rotate(Geom::Angle(half_dir)).inverse(); + r *= Geom::Scale(1, -1); + r *= Geom::Rotate(Geom::Angle(half_dir)); + } + + Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i))); + Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + if (method != RM_NORMAL) { + if(mirror_copies && i%2 != 0) { + t = m * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + } + } else { + if(mirror_copies && i%2 != 0) { + t = m * Geom::Rotate(Geom::rad_from_deg(-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + } + } + t *= sp_lpe_item->transform; + toItem(t, i-1, reset); + } + reset = false; + } else { + processObjects(LPE_ERASE); + items.clear(); + } +} + +void +LPECopyRotate::cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool root, bool reset) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) { + std::vector< SPObject * > childs = orig->childList(true); + size_t index = 0; + for (std::vector<SPObject * >::iterator obj_it = childs.begin(); + obj_it != childs.end(); ++obj_it) { + SPObject *dest_child = dest->nthChild(index); + cloneD(*obj_it, dest_child, transform, false, reset); + index++; + } + } + SPShape * shape = SP_SHAPE(orig); + if (shape && !SP_IS_PATH(dest)) { + const char * id = dest->getId(); + Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); + dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); + dest->getRepr()->setAttribute("d", id); + } + if (SP_IS_PATH(dest) && shape) { + SPCurve *c = NULL; + if (root) { + c = new SPCurve(); + c->set_pathvector(pathvector_after_effect); + } else { + c = shape->getCurve(); + } + if (c) { + SP_PATH(dest)->setCurve(c, TRUE); + c->unref(); + } else { + dest->getRepr()->setAttribute("d", NULL); + } + if (reset) { + dest->getRepr()->setAttribute("style", shape->getRepr()->attribute("style")); + } + } +} + +void +LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + const char * elemref_id = g_strdup(Glib::ustring("rotated-").append(std::to_string(i)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str()); + items.push_back(elemref_id); + SPObject *elemref= NULL; + Inkscape::XML::Node *phantom = NULL; + if ((elemref = document->getObjectById(elemref_id))) { + phantom = elemref->getRepr(); + } else { + phantom = sp_lpe_item->getRepr()->duplicate(xml_doc); + std::vector<const char *> attrs; + attrs.push_back("inkscape:path-effect"); + attrs.push_back("inkscape:original-d"); + attrs.push_back("sodipodi:type"); + attrs.push_back("sodipodi:rx"); + attrs.push_back("sodipodi:ry"); + attrs.push_back("sodipodi:cx"); + attrs.push_back("sodipodi:cy"); + attrs.push_back("sodipodi:end"); + attrs.push_back("sodipodi:start"); + attrs.push_back("inkscape:flatsided"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:rounded"); + attrs.push_back("sodipodi:arg1"); + attrs.push_back("sodipodi:arg2"); + attrs.push_back("sodipodi:r1"); + attrs.push_back("sodipodi:r2"); + attrs.push_back("sodipodi:sides"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("sodipodi:argument"); + attrs.push_back("sodipodi:expansion"); + attrs.push_back("sodipodi:radius"); + attrs.push_back("sodipodi:revolution"); + attrs.push_back("sodipodi:t0"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("x"); + attrs.push_back("y"); + attrs.push_back("rx"); + attrs.push_back("ry"); + attrs.push_back("width"); + attrs.push_back("height"); + phantom->setAttribute("id", elemref_id); + for(const char * attr : attrs) { + phantom->setAttribute(attr, NULL); + } + } + if (!elemref) { + elemref = container->appendChildRepr(phantom); + Inkscape::GC::release(phantom); + } + cloneD(SP_OBJECT(sp_lpe_item), elemref, transform, true, reset); + gchar *str = sp_svg_transform_write(transform); + elemref->getRepr()->setAttribute("transform" , str); + g_free(str); + SP_ITEM(elemref)->setHidden(false); + if (elemref->parent != container) { + Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); + copy->setAttribute("id", elemref_id); + container->appendChildRepr(copy); + Inkscape::GC::release(copy); + elemref->deleteObject(); + } +} + +void +LPECopyRotate::resetStyles(){ + reset = true; + doAfterEffect(sp_lpe_item); +} + +Gtk::Widget * LPECopyRotate::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 = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + 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 * hbox = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles")))); + reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPECopyRotate::resetStyles)); + reset_button->set_size_request(110,20); + vbox->pack_start(*hbox, true,true,2); + hbox->pack_start(*reset_button, false, false,2); + return dynamic_cast<Gtk::Widget *>(vbox); +} + + +void LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) { using namespace Geom; @@ -107,17 +358,14 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) void LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set) { - if(fuse_paths) { - Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0])); - angle += starting_angle; - starting_angle.param_set_value(angle); - } // cycle through all parameters. Most parameters will not need transformation, but path and point params do. - for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { Parameter * param = *it; - param->param_transform_multiply(postmul, set); + if(param->param_key != "starting_point" || postmul.isRotation()) { + param->param_transform_multiply(postmul, set); + } } + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); } void @@ -125,38 +373,54 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - if (copies_to_360) { + if (copies_to_360 && num_copies > 2) { rotation_angle.param_set_value(360.0/(double)num_copies); } - if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) { + if (method != RM_NORMAL && rotation_angle * num_copies > 360.1 && rotation_angle > 0 && copies_to_360) { num_copies.param_set_value(floor(360/rotation_angle)); } - if (fuse_paths && copies_to_360) { - num_copies.param_set_increments(2,2); + if (method != RM_NORMAL && mirror_copies && copies_to_360) { + num_copies.param_set_increments(2.0,10.0); if ((int)num_copies%2 !=0) { num_copies.param_set_value(num_copies+1); rotation_angle.param_set_value(360.0/(double)num_copies); } } else { - num_copies.param_set_increments(1,1); + num_copies.param_set_increments(1.0, 10.0); } - if (dist_angle_handle < 1.0) { - dist_angle_handle = 1.0; - } A = Point(boundingbox_X.min(), boundingbox_Y.middle()); B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); + if (Geom::are_near(A, B, 0.01)) { + B += Geom::Point(1.0, 0.0); + } dir = unit_vector(B - A); // I first suspected the minus sign to be a bug in 2geom but it is // likely due to SVG's choice of coordinate system orientation (max) - start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle; - rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle; - if ( fuse_paths || copies_to_360 ) { - rot_pos = origin; + bool near_start_point = Geom::are_near(previous_start_point, (Geom::Point)starting_point, 0.01); + bool near_origin = Geom::are_near(previous_origin, (Geom::Point)origin, 0.01); + if (!near_start_point) { + starting_angle.param_set_value(deg_from_rad(-angle_between(dir, starting_point - origin))); + if (GDK_SHIFT_MASK) { + dist_angle_handle = L2(B - A); + } else { + dist_angle_handle = L2(starting_point - origin); + } } - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); + if (dist_angle_handle < 1.0) { + dist_angle_handle = 1.0; + } + double distance = dist_angle_handle; + if (previous_start_point != Geom::Point(0,0) || previous_origin != Geom::Point(0,0)) { + distance = Geom::distance(previous_origin, starting_point); + } + start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * distance; + if (!near_start_point || !near_origin || split_items) { + starting_point.param_setValue(start_pos); + } + + previous_origin = (Geom::Point)origin; + previous_start_point = (Geom::Point)starting_point; } void @@ -231,30 +495,21 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s } Geom::PathVector tmp_path_helper; Geom::Path append_path = original; - + Geom::Point previous = original.finalPoint(); for (int i = 0; i < num_copies; ++i) { Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i))); Geom::Affine m = pre * rot * Geom::Translate(origin); - if (i%2 != 0) { - Geom::Point A = (Geom::Point)origin; - Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; - Geom::Translate m1(A[0], A[1]); - double hyp = Geom::distance(A, B); - double c = (B[0] - A[0]) / hyp; // cos(alpha) - double s = (B[1] - A[1]) / hyp; // sin(alpha) - - Geom::Affine m2(c, -s, s, c, 0.0, 0.0); - Geom::Scale sca(1.0, -1.0); - - Geom::Affine tmp_m = m1.inverse() * m2; - m = tmp_m; - m = m * sca; - m = m * m2.inverse(); - m = m * m1; + if (i%2 != 0 && mirror_copies) { + Geom::Point point_a = (Geom::Point)origin; + Geom::Point point_b = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; + Geom::Line ls(point_a, point_b); + m = Geom::reflection (ls.vector(), point_a); + append_path *= m; } else { append_path = original; + append_path *= m; } - append_path *= m; + previous = append_path.finalPoint(); if (tmp_path_helper.size() > 0) { if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) { Geom::Path tmp_append = append_path.reversed(); @@ -340,63 +595,98 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s tmp_path.clear(); } -Geom::Piecewise<Geom::D2<Geom::SBasis> > -LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +Geom::PathVector +LPECopyRotate::doEffect_path (Geom::PathVector const & path_in) { - using namespace Geom; - - if (num_copies == 1 && !fuse_paths) { - return pwd2_in; - } - + Geom::PathVector path_out; double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); - Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider; - Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider; - //Note:: beter way to do this - //Whith AppendNew have problems whith the crossing order - Geom::Path divider = Geom::Path(line_start); + Geom::OptRect bbox = sp_lpe_item->geometricBounds(); + size_divider = Geom::distance(origin,bbox) + (diagonal * 6); + Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider; + Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider; + divider = Geom::Path(line_start); divider.appendNew<Geom::LineSegment>((Geom::Point)origin); divider.appendNew<Geom::LineSegment>(line_end); - Piecewise<D2<SBasis> > output; - Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle)); - if (fuse_paths) { - Geom::PathVector path_out; - Geom::PathVector tmp_path; - PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()) { - continue; - } - bool end_open = false; - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { - end_open = true; - } - } - Geom::Path original = (Geom::Path)(*path_it); - if (end_open && path_it->closed()) { - original.close(false); - original.appendNew<Geom::LineSegment>( original.initialPoint() ); - original.close(true); - } - tmp_path.push_back(original); - setFusion(tmp_path, divider, size_divider); - path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); - tmp_path.clear(); + divider.close(); + half_dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin); + if (method != RM_NORMAL) { + if (method != RM_KALEIDOSCOPE) { + path_out = doEffect_path_post(path_in); + } else { + path_out = pathv_to_linear_and_cubic_beziers(path_in); + } + if (num_copies == 0) { + return path_out; } - if (path_out.size()>0) { - output = paths_to_pw(path_out); + Geom::PathVector triangle; + triangle.push_back(divider); + Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(triangle, path_out); + if (pig && !path_out.empty() && !triangle.empty()) { + path_out = pig->getIntersection(); + } + path_out *= Geom::Translate(half_dir * gap); + if ( !split_items ) { + path_out *= Geom::Translate(half_dir * gap).inverse(); + path_out = doEffect_path_post(path_out); } } else { - for (int i = 0; i < num_copies; ++i) { - Rotate rot(-rad_from_deg(rotation_angle * i)); - Affine t = pre * rot * Translate(origin); - output.concat(pwd2_in * t); + path_out = doEffect_path_post(path_in); + } + return pathv_to_linear_and_cubic_beziers(path_out); +} + +Geom::PathVector +LPECopyRotate::doEffect_path_post (Geom::PathVector const & path_in) +{ + if ((split_items || num_copies == 1) && method == RM_NORMAL) { + if (split_items) { + Geom::PathVector path_out = pathv_to_linear_and_cubic_beziers(path_in); + Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))); + Geom::Affine t = m * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + return path_out * t; + } + return path_in; + } + + Geom::Affine pre = Geom::Translate(-origin) * Geom::Rotate(-Geom::rad_from_deg(starting_angle)); + Geom::PathVector original_pathv = pathv_to_linear_and_cubic_beziers(path_in); + Geom::PathVector output_pv; + Geom::PathVector output; + for (int i = 0; i < num_copies; ++i) { + Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * i)); + Geom::Affine r = Geom::identity(); + if( i%2 != 0 && mirror_copies) { + r *= Geom::Rotate(Geom::Angle(half_dir)).inverse(); + r *= Geom::Scale(1, -1); + r *= Geom::Rotate(Geom::Angle(half_dir)); + } + Geom::Affine t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + if(mirror_copies && i%2 != 0) { + t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin); + } + if (method != RM_NORMAL) { + Geom::PathVector join_pv = original_pathv * t; + join_pv *= Geom::Translate(half_dir * rot * gap); + Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(output_pv, join_pv); + if (pig) { + if (!output_pv.empty()) { + output_pv = pig->getUnion(); + } else { + output_pv = join_pv; + } + } + } else { + t = pre * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + if(mirror_copies && i%2 != 0) { + t = pre * Geom::Rotate(Geom::rad_from_deg(-starting_angle-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + } + output_pv = path_in * t; + output.insert(output.end(), output_pv.begin(), output_pv.end()); } } + if (method != RM_NORMAL) { + output = output_pv; + } return output; } @@ -408,7 +698,7 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geo Geom::Path hp; hp.start(start_pos); hp.appendNew<Geom::LineSegment>((Geom::Point)origin); - hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle); + hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * Geom::distance(origin,starting_point)); Geom::PathVector pathv; pathv.push_back(hp); hp_vec.push_back(pathv); @@ -422,84 +712,23 @@ LPECopyRotate::resetDefaults(SPItem const* item) } void -LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) -{ - { - KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the starting angle")); - knotholder->add(e); - } - { - KnotHolderEntity *e = new CR::KnotHolderEntityRotationAngle(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the rotation angle")); - knotholder->add(e); - } -}; - -namespace CR { - -using namespace Geom; - -void -KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) { - LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect); - - Geom::Point const s = snap_knot_position(p, state); - - // I first suspected the minus sign to be a bug in 2geom but it is - // likely due to SVG's choice of coordinate system orientation (max) - lpe->starting_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin))); - if (state & GDK_SHIFT_MASK) { - lpe->dist_angle_handle = L2(lpe->B - lpe->A); - } else { - lpe->dist_angle_handle = L2(p - lpe->origin); - } - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); + processObjects(LPE_VISIBILITY); } -void -KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +void +LPECopyRotate::doOnRemove (SPLPEItem const* /*lpeitem*/) { - LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect); - - Geom::Point const s = snap_knot_position(p, state); - - // I first suspected the minus sign to be a bug in 2geom but it is - // likely due to SVG's choice of coordinate system orientation (max) - lpe->rotation_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle); - if (state & GDK_SHIFT_MASK) { - lpe->dist_angle_handle = L2(lpe->B - lpe->A); - } else { - lpe->dist_angle_handle = L2(p - lpe->origin); + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { + processObjects(LPE_TO_OBJECTS); + items.clear(); + return; } - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); + processObjects(LPE_ERASE); } -Geom::Point -KnotHolderEntityStartingAngle::knot_get() const -{ - LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect); - return lpe->start_pos; -} - -Geom::Point -KnotHolderEntityRotationAngle::knot_get() const -{ - LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect); - return lpe->rot_pos; -} - -} // namespace CR - -/* ######################## */ - } //namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index 87af867df..a0a3d4dc1 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -15,50 +15,68 @@ */ #include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/text.h" #include "live_effects/parameter/point.h" #include "live_effects/lpegroupbbox.h" namespace Inkscape { namespace LivePathEffect { -namespace CR { -// we need a separate namespace to avoid clashes with LPEPerpBisector -class KnotHolderEntityStartingAngle; -class KnotHolderEntityRotationAngle; -} +enum RotateMethod { + RM_NORMAL, + RM_KALEIDOSCOPE, + RM_FUSE, + RM_END +}; class LPECopyRotate : public Effect, GroupBBoxEffect { public: LPECopyRotate(LivePathEffectObject *lpeobject); virtual ~LPECopyRotate(); virtual void doOnApply (SPLPEItem const* lpeitem); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); + Geom::PathVector doEffect_path_post (Geom::PathVector const & path_in); virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void doAfterEffect (SPLPEItem const* lpeitem); virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); virtual void split(Geom::PathVector &path_in, Geom::Path const ÷r); virtual void resetDefaults(SPItem const* item); virtual void transform_multiply(Geom::Affine const& postmul, bool set); - /* the knotholder entity classes must be declared friends */ - friend class CR::KnotHolderEntityStartingAngle; - friend class CR::KnotHolderEntityRotationAngle; - void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - + virtual void doOnRemove (SPLPEItem const* /*lpeitem*/); + virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/); + virtual Gtk::Widget * newWidget(); + void toItem(Geom::Affine transform, size_t i, bool reset); + void cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool root, bool reset); + void resetStyles(); protected: virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); private: + EnumParam<RotateMethod> method; PointParam origin; + PointParam starting_point; ScalarParam starting_angle; ScalarParam rotation_angle; ScalarParam num_copies; + ScalarParam gap; BoolParam copies_to_360; - BoolParam fuse_paths; + BoolParam mirror_copies; + BoolParam split_items; Geom::Point A; Geom::Point B; Geom::Point dir; + Geom::Point half_dir; Geom::Point start_pos; - Geom::Point rot_pos; + Geom::Point previous_origin; + Geom::Point previous_start_point; double dist_angle_handle; + double size_divider; + Geom::Path divider; + double previous_num_copies; + bool reset; + SPObject * container; LPECopyRotate(const LPECopyRotate&); LPECopyRotate& operator=(const LPECopyRotate&); }; diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index 609447f26..f8d2e56ca 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -13,23 +13,16 @@ */ #include "ui/widget/scalar.h" -#include <glibmm/i18n.h> - #include "live_effects/lpe-curvestitch.h" -#include "sp-item.h" #include "sp-path.h" #include "svg/svg.h" #include "xml/repr.h" -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/affine.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -47,20 +40,21 @@ LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) { - registerParameter( dynamic_cast<Parameter *>(&nrofpaths) ); - registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&startpoint_spacing_variation) ); - registerParameter( dynamic_cast<Parameter *>(&endpoint_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&endpoint_spacing_variation) ); - registerParameter( dynamic_cast<Parameter *>(&strokepath) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); + registerParameter(&nrofpaths); + registerParameter(&startpoint_edge_variation); + registerParameter(&startpoint_spacing_variation); + registerParameter(&endpoint_edge_variation); + registerParameter(&endpoint_spacing_variation); + registerParameter(&strokepath ); + registerParameter(&prop_scale); + registerParameter(&scale_y_rel); nrofpaths.param_make_integer(); nrofpaths.param_set_range(2, Geom::infinity()); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); + transformed = false; } LPECurveStitch::~LPECurveStitch() @@ -113,8 +107,9 @@ LPECurveStitch::doEffect_path (Geom::PathVector const & path_in) if (!Geom::are_near(start,end)) { gdouble scaling_y = 1.0; - if (scale_y_rel.get_value()) { + if (scale_y_rel.get_value() || transformed) { scaling_y = (L2(end-start)/scaling)*prop_scale; + transformed = false; } else { scaling_y = prop_scale; } @@ -200,12 +195,8 @@ LPECurveStitch::transform_multiply(Geom::Affine const& postmul, bool set) if (postmul.isTranslation()) { strokepath.param_transform_multiply(postmul, set); } else if (!scale_y_rel.get_value()) { - // this basically means that for this transformation, the result should be the same as normal scaling the result path - // don't know how to do this yet. -// Geom::Affine new_postmul; - //new_postmul.setIdentity(); -// new_postmul.setTranslation(postmul.translation()); -// Effect::transform_multiply(new_postmul, set); + transformed = true; + strokepath.param_transform_multiply(postmul, set); } } diff --git a/src/live_effects/lpe-curvestitch.h b/src/live_effects/lpe-curvestitch.h index c6ea66f6c..0a48046e0 100644 --- a/src/live_effects/lpe-curvestitch.h +++ b/src/live_effects/lpe-curvestitch.h @@ -43,6 +43,7 @@ private: RandomParam endpoint_spacing_variation; ScalarParam prop_scale; BoolParam scale_y_rel; + bool transformed; LPECurveStitch(const LPECurveStitch&); LPECurveStitch& operator=(const LPECurveStitch&); diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp index aeecd5d5c..33e754a8a 100644 --- a/src/live_effects/lpe-dynastroke.cpp +++ b/src/live_effects/lpe-dynastroke.cpp @@ -14,14 +14,10 @@ #include "display/curve.h" //# include <libnr/n-art-bpath.h> -#include <2geom/path.h> -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> #include <2geom/sbasis-math.h> -#include <2geom/piecewise.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -59,17 +55,17 @@ LPEDynastroke::LPEDynastroke(LivePathEffectObject *lpeobject) : capping(_("Capping:"), _("left capping"), "capping", &wr, this, "M 100,5 C 50,5 0,0 0,0 0,0 50,-5 100,-5") { - registerParameter( dynamic_cast<Parameter *>(& method) ); - registerParameter( dynamic_cast<Parameter *>(& width) ); - registerParameter( dynamic_cast<Parameter *>(& roundness) ); - registerParameter( dynamic_cast<Parameter *>(& angle) ); - //registerParameter( dynamic_cast<Parameter *>(& modulo_pi) ); - registerParameter( dynamic_cast<Parameter *>(& start_cap) ); - registerParameter( dynamic_cast<Parameter *>(& growfor) ); - registerParameter( dynamic_cast<Parameter *>(& end_cap) ); - registerParameter( dynamic_cast<Parameter *>(& fadefor) ); - registerParameter( dynamic_cast<Parameter *>(& round_ends) ); - registerParameter( dynamic_cast<Parameter *>(& capping) ); + registerParameter(&method); + registerParameter(&width); + registerParameter(&roundness); + registerParameter(&angle); + //registerParameter(&modulo_pi) ); + registerParameter(&start_cap); + registerParameter(&growfor); + registerParameter(&end_cap); + registerParameter(&fadefor); + registerParameter(&round_ends); + registerParameter(&capping); width.param_set_range(0, Geom::infinity()); roundness.param_set_range(0.01, 1); diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp index 4c953bcda..28e7058d7 100644 --- a/src/live_effects/lpe-ellipse_5pts.cpp +++ b/src/live_effects/lpe-ellipse_5pts.cpp @@ -12,16 +12,14 @@ */ #include "live_effects/lpe-ellipse_5pts.h" - -// You might need to include other 2geom files. You can add them here: -#include <glibmm/i18n.h> -#include <2geom/path.h> #include <2geom/circle.h> #include <2geom/ellipse.h> #include <2geom/path-sink.h> #include "inkscape.h" #include "desktop.h" #include "message-stack.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -171,7 +169,7 @@ LPEEllipse5Pts::doEffect_path (Geom::PathVector const & path_in) // figure out if we have a slice, guarding against rounding errors - Path p(Geom::Point(cos(0), sin(0))); + Geom::Path p(Geom::Point(cos(0), sin(0))); double end = 2 * M_PI; for (s = 0; s < end; s += M_PI_2) { diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp index e873c0b15..8528ab14d 100644 --- a/src/live_effects/lpe-envelope.cpp +++ b/src/live_effects/lpe-envelope.cpp @@ -5,22 +5,10 @@ */ #include "live_effects/lpe-envelope.h" -#include "sp-shape.h" -#include "sp-item.h" -#include "sp-path.h" -#include "sp-item-group.h" #include "display/curve.h" -#include "svg/svg.h" -#include "ui/widget/scalar.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> - -#include <algorithm> using std::vector; namespace Inkscape { @@ -35,12 +23,12 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) : xx(_("_Enable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), yy(_("_Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&yy) ); - registerParameter( dynamic_cast<Parameter *>(&xx) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path1) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path2) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path3) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path4) ); + registerParameter(&yy); + registerParameter(&xx); + registerParameter(&bend_path1); + registerParameter(&bend_path2); + registerParameter(&bend_path3); + registerParameter(&bend_path4); concatenate_before_pwd2 = true; apply_to_clippath_and_mask = true; } @@ -61,7 +49,7 @@ Geom::Piecewise<Geom::D2<Geom::SBasis> > LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { - if(xx.get_value() == false && yy.get_value() == false) + if(!xx.get_value() && !yy.get_value()) { return pwd2_in; } @@ -172,7 +160,7 @@ LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd output_y = ybis*(compose((uskeleton1),x1) + y1*compose(n1,x1) ) + y*(compose((uskeleton3),x3) + y3*compose(n3,x3) ); output_y /= (boundingbox_Y.extent()); - if(xx.get_value() == false && yy.get_value() == true) + if(!xx.get_value() && yy.get_value()) { return output_y; } @@ -181,13 +169,13 @@ LPEEnvelope::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd output_x = x*(compose((uskeleton2),y2) + -x2*compose(n2,y2) ) + xbis*(compose((uskeleton4),y4) + -x4*compose(n4,y4) ); output_x /= (boundingbox_X.extent()); - if(xx.get_value() == true && yy.get_value() == false) + if(xx.get_value() && !yy.get_value()) { return output_x; } /*output : Deformation by Up, Left, Right and Down Bend Paths*/ - if(xx.get_value() == true && yy.get_value() == true) + if(xx.get_value() && yy.get_value()) { Piecewise<SBasis> xsqr = x*xbis; /* xsqr = x * (BBox_X - x) */ Piecewise<SBasis> ysqr = y*ybis; /* xsqr = y * (BBox_Y - y) */ diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp index 8b3f4714a..4a3ad7508 100644 --- a/src/live_effects/lpe-extrude.cpp +++ b/src/live_effects/lpe-extrude.cpp @@ -12,15 +12,10 @@ */ #include "live_effects/lpe-extrude.h" - +#include "sp-item.h" +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/transforms.h> -#include <algorithm> - -#include "sp-item.h" namespace Inkscape { namespace LivePathEffect { @@ -32,7 +27,7 @@ LPEExtrude::LPEExtrude(LivePathEffectObject *lpeobject) : show_orig_path = true; concatenate_before_pwd2 = false; - registerParameter( dynamic_cast<Parameter *>(&extrude_vector) ); + registerParameter(&extrude_vector); } LPEExtrude::~LPEExtrude() @@ -66,7 +61,7 @@ LPEExtrude::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2 using namespace Geom; // generate connecting lines (the 'sides' of the extrusion) - Path path(Point(0.,0.)); + Geom::Path path(Point(0.,0.)); path.appendNew<Geom::LineSegment>( extrude_vector.getVector() ); Piecewise<D2<SBasis> > connector = path.toPwSb(); diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp index 574ec3580..40fa91c68 100644 --- a/src/live_effects/lpe-fill-between-many.cpp +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -4,17 +4,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gtkmm/box.h> #include "live_effects/lpe-fill-between-many.h" #include "display/curve.h" -#include "sp-item.h" -#include "2geom/path.h" #include "sp-shape.h" #include "sp-text.h" -#include "2geom/bezier-curve.h" - +#include "svg/svg.h" +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> namespace Inkscape { @@ -22,10 +19,18 @@ namespace LivePathEffect { LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) : Effect(lpeobject), - linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this) + linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this), + fuse(_("Fuse coincident points"), _("Fuse coincident points"), "fuse", &wr, this, false), + allow_transforms(_("Allow transforms"), _("Allow transforms"), "allow_transforms", &wr, this, false), + join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true), + close(_("Close"), _("Close path"), "close", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&linked_paths) ); - //perceived_path = true; + registerParameter(&linked_paths); + registerParameter(&fuse); + registerParameter(&allow_transforms); + registerParameter(&join); + registerParameter(&close); + transformmultiply = false; } LPEFillBetweenMany::~LPEFillBetweenMany() @@ -47,22 +52,50 @@ void LPEFillBetweenMany::doEffect (SPCurve * curve) linked_path = (*iter)->_pathvector.front(); } - if (!res_pathv.empty()) { + if (!res_pathv.empty() && join) { linked_path = linked_path * SP_ITEM(obj)->getRelativeTransform(firstObj); - res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint()); + if (!are_near(res_pathv.front().finalPoint(), linked_path.initialPoint(), 0.01) || !fuse) { + res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint()); + } else { + linked_path.setInitial(res_pathv.front().finalPoint()); + } res_pathv.front().append(linked_path); } else { firstObj = SP_ITEM(obj); + if (close && !join) { + linked_path.close(); + } res_pathv.push_back(linked_path); } } } - if (!res_pathv.empty()) { + if (!res_pathv.empty() && close) { res_pathv.front().close(); } + if (res_pathv.empty()) { + res_pathv = curve->get_pathvector(); + } + if(!allow_transforms && !transformmultiply) { + Geom::Affine affine = Geom::identity(); + sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &affine); + res_pathv *= affine.inverse(); + } + if(transformmultiply) { + transformmultiply = false; + } curve->set_pathvector(res_pathv); } +void +LPEFillBetweenMany::transform_multiply(Geom::Affine const& postmul, bool set) +{ + if(!allow_transforms && sp_lpe_item) { + SP_ITEM(sp_lpe_item)->transform *= postmul.inverse(); + transformmultiply = true; + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); + } +} + } // namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-fill-between-many.h b/src/live_effects/lpe-fill-between-many.h index 99ee8b15f..fe824e936 100644 --- a/src/live_effects/lpe-fill-between-many.h +++ b/src/live_effects/lpe-fill-between-many.h @@ -19,12 +19,16 @@ class LPEFillBetweenMany : public Effect { public: LPEFillBetweenMany(LivePathEffectObject *lpeobject); virtual ~LPEFillBetweenMany(); - + virtual void transform_multiply(Geom::Affine const& postmul, bool set); virtual void doEffect (SPCurve * curve); private: OriginalPathArrayParam linked_paths; - + BoolParam fuse; + BoolParam allow_transforms; + BoolParam join; + BoolParam close; + bool transformmultiply; private: LPEFillBetweenMany(const LPEFillBetweenMany&); LPEFillBetweenMany& operator=(const LPEFillBetweenMany&); diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp index 89ea80545..f8d86ae99 100644 --- a/src/live_effects/lpe-fill-between-strokes.cpp +++ b/src/live_effects/lpe-fill-between-strokes.cpp @@ -3,17 +3,14 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <glibmm/i18n.h> - #include "live_effects/lpe-fill-between-strokes.h" #include "display/curve.h" -#include "sp-item.h" -#include "2geom/path.h" #include "sp-shape.h" #include "sp-text.h" -#include "2geom/bezier-curve.h" +#include "svg/svg.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -22,12 +19,20 @@ LPEFillBetweenStrokes::LPEFillBetweenStrokes(LivePathEffectObject *lpeobject) : Effect(lpeobject), linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), second_path(_("Second path:"), _("Second path from which to take the original path data"), "secondpath", &wr, this), - reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this) + reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this), + fuse(_("Fuse coincident points"), _("Fuse coincident points"), "fuse", &wr, this, false), + allow_transforms(_("Allow transforms"), _("Allow transforms"), "allow_transforms", &wr, this, false), + join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true), + close(_("Close"), _("Close path"), "close", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&linked_path) ); - registerParameter( dynamic_cast<Parameter *>(&second_path) ); - registerParameter( dynamic_cast<Parameter *>(&reverse_second) ); - //perceived_path = true; + registerParameter(&linked_path); + registerParameter(&second_path); + registerParameter(&reverse_second); + registerParameter(&fuse); + registerParameter(&allow_transforms); + registerParameter(&join); + registerParameter(&close); + transformmultiply = false; } LPEFillBetweenStrokes::~LPEFillBetweenStrokes() @@ -38,6 +43,13 @@ LPEFillBetweenStrokes::~LPEFillBetweenStrokes() void LPEFillBetweenStrokes::doEffect (SPCurve * curve) { if (curve) { + Geom::Affine affine = Geom::identity(); + if(!allow_transforms && !transformmultiply) { + sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &affine); + } + if(transformmultiply) { + transformmultiply = false; + } if ( linked_path.linksToPath() && second_path.linksToPath() && linked_path.getObject() && second_path.getObject() ) { Geom::PathVector linked_pathv = linked_path.get_pathvector(); Geom::PathVector second_pathv = second_path.get_pathvector(); @@ -55,22 +67,33 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) } if ( !result_linked_pathv.empty() && !result_second_pathv.empty() && !result_linked_pathv.front().closed() ) { - if (reverse_second.get_value()) - { - result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().finalPoint()); - result_linked_pathv.front().append(result_second_pathv.front().reversed()); + if (reverse_second.get_value()) { + result_second_pathv.front() = result_second_pathv.front().reversed(); } - else - { - result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().initialPoint()); + if (join) { + if (!are_near(result_linked_pathv.front().finalPoint(), result_second_pathv.front().initialPoint(),0.01) || !fuse) { + result_linked_pathv.front().appendNew<Geom::LineSegment>(result_second_pathv.front().initialPoint()); + } else { + result_second_pathv.front().setInitial(result_linked_pathv.front().finalPoint()); + } result_linked_pathv.front().append(result_second_pathv.front()); + if (close) { + result_linked_pathv.front().close(); + } + } else { + if (close) { + result_linked_pathv.front().close(); + result_second_pathv.front().close(); + } + result_linked_pathv.push_back(result_second_pathv.front()); } + result_linked_pathv *= affine.inverse(); curve->set_pathvector(result_linked_pathv); - } - else if ( !result_linked_pathv.empty() ) { + } else if ( !result_linked_pathv.empty() ) { + result_linked_pathv *= affine.inverse(); curve->set_pathvector(result_linked_pathv); - } - else if ( !result_second_pathv.empty() ) { + } else if ( !result_second_pathv.empty() ) { + result_second_pathv *= affine.inverse(); curve->set_pathvector(result_second_pathv); } } @@ -83,6 +106,10 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) result_pathv.push_back((*iter)); } if ( !result_pathv.empty() ) { + result_pathv *= affine.inverse(); + if (close) { + result_pathv.front().close(); + } curve->set_pathvector(result_pathv); } } @@ -95,12 +122,26 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) result_pathv.push_back((*iter)); } if ( !result_pathv.empty() ) { + result_pathv *= affine.inverse(); + if (close) { + result_pathv.front().close(); + } curve->set_pathvector(result_pathv); } } } } +void +LPEFillBetweenStrokes::transform_multiply(Geom::Affine const& postmul, bool set) +{ + if(!allow_transforms && sp_lpe_item) { + SP_ITEM(sp_lpe_item)->transform *= postmul.inverse(); + transformmultiply = true; + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); + } +} + } // namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-fill-between-strokes.h b/src/live_effects/lpe-fill-between-strokes.h index ec57b1852..5bbd6e7da 100644 --- a/src/live_effects/lpe-fill-between-strokes.h +++ b/src/live_effects/lpe-fill-between-strokes.h @@ -19,13 +19,18 @@ class LPEFillBetweenStrokes : public Effect { public: LPEFillBetweenStrokes(LivePathEffectObject *lpeobject); virtual ~LPEFillBetweenStrokes(); - + virtual void transform_multiply(Geom::Affine const& postmul, bool set); virtual void doEffect (SPCurve * curve); private: OriginalPathParam linked_path; OriginalPathParam second_path; BoolParam reverse_second; + BoolParam fuse; + BoolParam allow_transforms; + BoolParam join; + BoolParam close; + bool transformmultiply; private: LPEFillBetweenStrokes(const LPEFillBetweenStrokes&); diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 07760b172..11298bcbe 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -4,91 +4,158 @@ * * 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/elliptical-arc.h> -#include <2geom/line.h> -#include "desktop.h" +#include "live_effects/lpe-fillet-chamfer.h" +#include "helper/geom.h" #include "display/curve.h" -#include "helper/geom-nodetype.h" #include "helper/geom-curves.h" -#include "helper/geom.h" - -#include "live_effects/parameter/filletchamferpointarray.h" - -// for programmatically updating knots -#include "ui/tools-switch.h" +#include "helper/geom-satellite.h" +#include <2geom/elliptical-arc.h> +#include "knotholder.h" +#include <boost/optional.hpp> // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -using namespace Geom; namespace Inkscape { namespace LivePathEffect { -static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = { - { FM_AUTO, N_("Auto"), "auto" }, +static const Util::EnumData<Filletmethod> FilletmethodData[] = { + { FM_AUTO, N_("Auto"), "auto" }, { FM_ARC, N_("Force arc"), "arc" }, { FM_BEZIER, N_("Force bezier"), "bezier" } }; -static const Util::EnumDataConverter<FilletMethod> -FMConverter(FilletMethodData, FM_END); - -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), - use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), - method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), - radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.), - chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0), - - helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0) +static const Util::EnumDataConverter<Filletmethod> FMConverter(FilletmethodData, FM_END); + +LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"), + satellites_param("Satellites_param", "Satellites_param", + "satellites_param", &wr, this), + method(_("Method:"), _("Methods to calculate the fillet or chamfer"), + "method", FMConverter, &wr, this, FM_AUTO), + mode(_("Mode:"), _("Mode, fillet or chamfer"), + "mode", &wr, this, "F", true), + radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, + this, 0.0), + chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", + &wr, this, 1), + flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), + "flexible", &wr, this, false), + mirror_knots(_("Mirror Knots"), _("Mirror Knots"), "mirror_knots", &wr, + this, true), + only_selected(_("Change only selected nodes"), + _("Change only selected nodes"), "only_selected", &wr, this, + false), + use_knot_distance(_("Use knots distance instead radius"), + _("Use knots distance instead radius"), + "use_knot_distance", &wr, this, false), + hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, + false), + apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true), + apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true), + helper_size(_("Helper path size with direction to node:"), + _("Helper path size with direction to node"), "helper_size", &wr, this, 0), + _pathvector_satellites(NULL), + _degenerate_hide(false) { - registerParameter(&fillet_chamfer_values); + registerParameter(&satellites_param); + registerParameter(&unit); registerParameter(&method); + registerParameter(&mode); registerParameter(&radius); registerParameter(&chamfer_steps); registerParameter(&helper_size); registerParameter(&flexible); registerParameter(&use_knot_distance); - registerParameter(&ignore_radius_0); + registerParameter(&mirror_knots); + registerParameter(&apply_no_radius); + registerParameter(&apply_with_radius); registerParameter(&only_selected); registerParameter(&hide_knots); - radius.param_set_range(0., infinity()); + radius.param_set_range(0.0, Geom::infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); - radius.param_overwrite_widget(true); + radius.param_set_undo(false); chamfer_steps.param_set_range(1, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); - chamfer_steps.param_overwrite_widget(true); - helper_size.param_set_range(0, infinity()); + helper_size.param_set_range(0, 999); helper_size.param_set_increments(5, 5); helper_size.param_set_digits(0); - helper_size.param_overwrite_widget(true); - fillet_chamfer_values.set_chamfer_steps(3); + _provides_knotholder_entities = true; } -LPEFilletChamfer::~LPEFilletChamfer() {} +void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) +{ + SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem); + SPShape *shape = dynamic_cast<SPShape *>(splpeitem); + if (shape) { + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector()); + Satellites satellites; + double power = radius; + std::cout << power << "power\n"; + if (!flexible) { + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = nv->display_units->abbr; + power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str()); + } + std::cout << power << "power22222222\n"; + SatelliteType satellite_type = FILLET; + std::map<std::string, SatelliteType> gchar_map_to_satellite_type = + boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE); + std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(mode.param_getSVGValue())); + if (it != gchar_map_to_satellite_type.end()) { + satellite_type = it->second; + } + for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + std::vector<Satellite> subpath_satellites; + for (Geom::Path::const_iterator curve_it = path_it->begin(); curve_it != path_it->end(); ++curve_it) { + //Maybe we want this satellites... + //if (curve_it->isDegenerate()) { + // continue + //} + Satellite satellite(satellite_type); + satellite.setSteps(chamfer_steps); + satellite.setAmount(power); + satellite.setIsTime(flexible); + satellite.setHasMirror(mirror_knots); + satellite.setHidden(hide_knots); + subpath_satellites.push_back(satellite); + } + //we add the last satellite on open path because _pathvector_satellites is related to nodes, not curves + //so maybe in the future we can need this last satellite in other effects + //dont remove for this effect because _pathvector_satellites class has methods when the path is modiffied + //and we want one method for all uses + if (!path_it->closed()) { + Satellite satellite(satellite_type); + satellite.setSteps(chamfer_steps); + satellite.setAmount(power); + satellite.setIsTime(flexible); + satellite.setHasMirror(mirror_knots); + satellite.setHidden(hide_knots); + subpath_satellites.push_back(satellite); + } + satellites.push_back(subpath_satellites); + } + _pathvector_satellites = new PathVectorSatellites(); + _pathvector_satellites->setPathVector(pathv); + _pathvector_satellites->setSatellites(satellites); + satellites_param.setPathVectorSatellites(_pathvector_satellites); + } else { + g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups)."); + SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem); + item->removeCurrentPathEffect(false); + } +} Gtk::Widget *LPEFilletChamfer::newWidget() { @@ -99,54 +166,50 @@ Gtk::Widget *LPEFilletChamfer::newWidget() vbox->set_border_width(5); vbox->set_homogeneous(false); vbox->set_spacing(2); - Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon...")))); - advertaising->pack_start(*advert, true, true, 2); - vbox->pack_start(*advertaising, true, true, 2); - Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after.")))); - advertaising2->pack_start(*advert2, true, true, 2); - vbox->pack_start(*advertaising2, true, true, 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; + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount)); + widg = widg_registered; 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); + Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalar_parameter->get_children(); + Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); + entry_widget->set_width_chars(6); } +// } else if (param->param_key == "unit") { +// Inkscape::UI::Widget::RegisteredUnitMenu* widg_registered = +// Gtk::manage(dynamic_cast< Inkscape::UI::Widget::RegisteredUnitMenu *>(widg)); +// widg_registered->setUnit(unit.get_abbreviation()); +// widg_registered->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change unit parameter")); +// widg_registered->getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::convertUnit)); +// widg = widg_registered; } else if (param->param_key == "chamfer_steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions)); - widg = widgRegistered; + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps)); + widg = widg_registered; 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(3); + Gtk::HBox *scalar_parameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> childList = scalar_parameter->get_children(); + Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); + entry_widget->set_width_chars(3); } - } 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)); + Inkscape::UI::Widget::Scalar *widg_registered = + Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + widg_registered->signal_value_changed().connect( + sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); } 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); @@ -158,504 +221,407 @@ Gtk::Widget *LPEFilletChamfer::newWidget() } } } - ++it; } - Gtk::HBox *filletContainer = 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)); - filletContainer->pack_start(*fillet, true, true, 2); - Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); - inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet)); - filletContainer->pack_start(*inverseFillet, true, true, 2); - - Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::HBox *fillet_container = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); + fillet->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),FILLET)); + + fillet_container->pack_start(*fillet, true, true, 2); + Gtk::Button *inverse_fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverse_fillet->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_FILLET)); + fillet_container->pack_start(*inverse_fillet, true, true, 2); + + Gtk::HBox *chamfer_container = 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)); + chamfer->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),CHAMFER)); - chamferContainer->pack_start(*chamfer, true, true, 2); - Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer")))); - inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer)); - chamferContainer->pack_start(*inverseChamfer, true, true, 2); + chamfer_container->pack_start(*chamfer, true, true, 2); + Gtk::Button *inverse_chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer")))); + inverse_chamfer->signal_clicked() + .connect(sigc::bind<SatelliteType>(sigc::mem_fun(*this, &LPEFilletChamfer::updateSatelliteType),INVERSE_CHAMFER)); + chamfer_container->pack_start(*inverse_chamfer, true, true, 2); - vbox->pack_start(*filletContainer, true, true, 2); - vbox->pack_start(*chamferContainer, true, true, 2); + vbox->pack_start(*fillet_container, true, true, 2); + vbox->pack_start(*chamfer_container, 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], std::abs((*point_it)[Y]) * -1)); - } else { - result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]))); - } - } - fillet_chamfer_values.param_set_and_write_new_value(result); - refreshKnots(); -} - -void LPEFilletChamfer::toggleFlexFixed() +void LPEFilletChamfer::refreshKnots() { - 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 (satellites_param._knoth) { + satellites_param._knoth->update_knots(); } - 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() +void LPEFilletChamfer::updateAmount() { - double power = 0; + setSelected(_pathvector_satellites); + double power = radius; if (!flexible) { - power = radius * -1; - } else { - power = radius; + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = nv->display_units->abbr; + power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str()); } - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); + _pathvector_satellites->updateAmount(power, apply_no_radius, apply_with_radius, only_selected, + use_knot_distance, flexible); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::fillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 1); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet")); -} - -void LPEFilletChamfer::inverseFillet() -{ - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 2); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); -} +//void LPEFilletChamfer::convertUnit() +//{ +// SPDocument * document = SP_ACTIVE_DOCUMENT; +// SPNamedView *nv = sp_document_namedview(document, NULL); +// Glib::ustring display_unit = nv->display_units->abbr; +// _pathvector_satellites->convertUnit(unit.get_abbreviation(), display_unit, apply_no_radius, apply_with_radius); +// satellites_param.setPathVectorSatellites(_pathvector_satellites); +//} -void LPEFilletChamfer::chamferSubdivisions() +void LPEFilletChamfer::updateChamferSteps() { - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); + setSelected(_pathvector_satellites); + _pathvector_satellites->updateSteps(chamfer_steps, apply_no_radius, apply_with_radius, only_selected); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::chamfer() +void LPEFilletChamfer::updateSatelliteType(SatelliteType satellitetype) { - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer")); + std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map = + boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO"); + mode.param_setValue((Glib::ustring)satellite_type_to_gchar_map.at(satellitetype)); + setSelected(_pathvector_satellites); + _pathvector_satellites->updateSatelliteType(satellitetype, apply_no_radius, apply_with_radius, only_selected); + satellites_param.setPathVectorSatellites(_pathvector_satellites); } -void LPEFilletChamfer::inverseChamfer() -{ - fillet_chamfer_values.set_chamfer_steps(chamfer_steps); - Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000); - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); -} - -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); - } - DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed")); -} - -void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power) -{ - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); - int counter = 0; - for (PathVector::const_iterator path_it = original_pathv_processed.begin(); - path_it != original_pathv_processed.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() && 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 && !use_knot_distance) { - powerend = fillet_chamfer_values.rad_to_len(counter,powerend); - } - 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 && !isNodePointSelected(curve_it1->initialPoint())) { - powerend = filletChamferData[counter][X]; +void LPEFilletChamfer::setSelected(PathVectorSatellites *_pathvector_satellites){ + Geom::PathVector const pathv = _pathvector_satellites->getPathVector(); + Satellites satellites = _pathvector_satellites->getSatellites(); + for (size_t i = 0; i < satellites.size(); ++i) { + for (size_t j = 0; j < satellites[i].size(); ++j) { + Geom::Curve const &curve_in = pathv[i][j]; + if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){ + satellites[i][j].setSelected(true); + } else { + satellites[i][j].setSelected(false); } - result.push_back(Point(powerend, filletChamferData[counter][Y])); - ++curve_it1; - ++curve_it2; - counter++; } } - fillet_chamfer_values.param_set_and_write_new_value(result); + _pathvector_satellites->setSatellites(satellites); } -void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type) +void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) { - std::vector<Point> filletChamferData = fillet_chamfer_values.data(); - std::vector<Geom::Point> result; - Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); - int counter = 0; - for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.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(); - } + if (sp_curve) { + //fillet chamfer specific calls + satellites_param.setUseDistance(use_knot_distance); + satellites_param.setCurrentZoom(current_zoom); + //mandatory call + satellites_param.setEffectType(effectType()); + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector()); + //if are diferent sizes call to recalculate + //TODO: Update the satellite data in paths modified, + Satellites satellites = satellites_param.data(); + if (satellites.empty()) { + doOnApply(lpeItem); + satellites = satellites_param.data(); } - 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 && !isNodePointSelected(curve_it1->initialPoint()))) { - toggle = false; - } - if (toggle) { - if(type >= 5000){ - if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){ - type = type - 2000; - } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){ - type = type - 1000; - } + if (_pathvector_satellites) { + size_t number_nodes = pathv.nodes().size(); + size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites(); + if (number_nodes != previous_number_nodes) { + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(sp_curve->get_pathvector()); + Satellites satellites; + double power = radius; + if (!flexible) { + SPDocument * document = SP_ACTIVE_DOCUMENT; + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = nv->display_units->abbr; + power = Inkscape::Util::Quantity::convert(power, unit.get_abbreviation(), display_unit.c_str()); } - result.push_back(Point(filletChamferData[counter][X], type)); - } else { - result.push_back(filletChamferData[counter]); - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; + SatelliteType satellite_type = FILLET; + std::map<std::string, SatelliteType> gchar_map_to_satellite_type = + boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE); + std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(mode.param_getSVGValue())); + if (it != gchar_map_to_satellite_type.end()) { + satellite_type = it->second; + } + Satellite satellite(satellite_type); + satellite.setSteps(chamfer_steps); + satellite.setAmount(power); + satellite.setIsTime(flexible); + satellite.setHasMirror(mirror_knots); + satellite.setHidden(hide_knots); + _pathvector_satellites->recalculateForNewPathVector(pathv, satellite); + satellites = _pathvector_satellites->getSatellites(); } - 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 = pathv_to_linear_and_cubic_beziers(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) { - std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv); - Geom::NodeType nodetype; - if (positions.second == 0) { - if (path_it->closed()) { - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1); - Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); - nodetype = get_nodetype(*A, *curve_it1); + if (_degenerate_hide) { + satellites_param.setGlobalKnotHide(true); + } else { + satellites_param.setGlobalKnotHide(false); + } + if (hide_knots) { + satellites_param.setHelperSize(0); + } else { + satellites_param.setHelperSize(helper_size); + } + for (size_t i = 0; i < satellites.size(); ++i) { + for (size_t j = 0; j < satellites[i].size(); ++j) { + Geom::Curve const &curve_in = pathv[i][j]; + if (satellites[i][j].is_time != flexible) { + satellites[i][j].is_time = flexible; + double amount = satellites[i][j].amount; + if (pathv[i].size() == j) { + continue; + } + if (satellites[i][j].is_time) { + double time = timeAtArcLength(amount, curve_in); + satellites[i][j].amount = time; } else { - nodetype = NODE_NONE; + double size = arcLengthAt(amount, curve_in); + satellites[i][j].amount = size; } - } 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)); + if (satellites[i][j].has_mirror != mirror_knots) { + satellites[i][j].has_mirror = mirror_knots; } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; + satellites[i][j].hidden = hide_knots; + if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){ + satellites[i][j].setSelected(true); } - counter++; } } - fillet_chamfer_values.param_set_and_write_new_value(point); - } else { - g_warning("LPE Fillet can only be applied to shapes (not groups)."); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeItem); - item->removeCurrentPathEffect(false); - } -} - -void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) -{ - if (SP_IS_SHAPE(lpeItem)) { - if(hide_knots){ - fillet_chamfer_values.set_helper_size(0); - } else { - fillet_chamfer_values.set_helper_size(helper_size); - } - fillet_chamfer_values.set_use_distance(use_knot_distance); - 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 = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); + if (!_pathvector_satellites) { + _pathvector_satellites = new PathVectorSatellites(); } + _pathvector_satellites->setPathVector(pathv); + _pathvector_satellites->setSatellites(satellites); + satellites_param.setPathVectorSatellites(_pathvector_satellites, false); + refreshKnots(); } else { g_warning("LPE Fillet can only be applied to shapes (not groups)."); } } -int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) +void +LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) { - int nKnots = c->nodes_in_path(); - PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - for (Geom::PathVector::const_iterator path_it = pv.begin(); - path_it != pv.end(); ++path_it) { - if (!(*path_it).closed()) { - nKnots--; - } - } - return nKnots; + hp_vec.push_back(_hp); } void -LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in) +LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps) { - if (!path_in.empty()) { - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); + setSelected(_pathvector_satellites); + double path_subdivision = 1.0 / steps; + for (size_t i = 1; i < steps; i++) { + Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i); + tmp_path.appendNew<Geom::LineSegment>(chamfer_step); } + tmp_path.appendNew<Geom::LineSegment>(end_arc_point); } Geom::PathVector LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) { - Geom::PathVector pathvector_out; - Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(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; + const double GAP_HELPER = 0.00001; + Geom::PathVector path_out; + size_t path = 0; const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); - for (PathVector::const_iterator path_it = path_in_processed.begin(); - path_it != path_in_processed.end(); ++path_it) { - if (path_it->empty()) + _degenerate_hide = false; + Geom::PathVector const pathv = pathv_to_linear_and_cubic_beziers(path_in); + Satellites satellites = _pathvector_satellites->getSatellites(); + for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.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) { - Curve *curve_it2Fixed = (*path_it->begin()).duplicate(); - if(!path_it->closed() || curve_it2 != curve_endit){ - curve_it2Fixed = (*curve_it2).duplicate(); + Geom::Path tmp_path; + if (path_it->size() == 1) { + path++; + tmp_path.start(path_it[0].pointAt(0)); + tmp_path.append(path_it[0]); + path_out.push_back(tmp_path); + continue; + } + double time0 = 0; + size_t curve = 0; + for (Geom::Path::const_iterator curve_it1 = path_it->begin(); curve_it1 != path_it->end(); ++curve_it1) { + size_t next_index = curve + 1; + if (curve == pathv[path].size() - 1 && pathv[path].closed()) { + next_index = 0; + } + //append last extreme of paths on open paths + if (curve == pathv[path].size() -1 && !pathv[path].closed()) { //the path is open and we are at end of path + if (time0 != 1) { //Previous satellite not at 100% amount + Geom::Curve *last_curve = curve_it1->portion(time0, 1); + last_curve->setInitial(tmp_path.finalPoint()); + tmp_path.append(*last_curve); + } + continue; } - bool last = curve_it2 == curve_endit; - std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last); - Curve *knotCurve1 = curve_it1->portion(times[0], times[1]); - if (counterCurves > 0) { - knotCurve1->setInitial(path_out.finalPoint()); + Geom::Curve const &curve_it2 = pathv[path][next_index]; + Satellite satellite = satellites[path][next_index]; + if (Geom::are_near((*curve_it1).initialPoint(), (*curve_it1).finalPoint())) { + _degenerate_hide = true; + g_warning("Knots hidded if consecutive nodes has the same position."); + return path_in; + } + if (!curve) { //curve == 0 + if (!path_it->closed()) { + time0 = 0; + } else { + time0 = satellites[path][0].time(*curve_it1); + } + } + double s = satellite.arcDistance(curve_it2); + double time1 = satellite.time(s, true, (*curve_it1)); + double time2 = satellite.time(curve_it2); + if (time1 <= time0) { + time1 = time0; + } + if (time2 > 1) { + time2 = 1; + } + Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1); + Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1); + if (curve > 0) { + knot_curve_1->setInitial(tmp_path.finalPoint()); } else { - path_out.start((*curve_it1).pointAt(times[0])); + tmp_path.start((*curve_it1).pointAt(time0)); } - Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1); - Point startArcPoint = knotCurve1->finalPoint(); - Point endArcPoint = curve_it2Fixed->pointAt(times[2]); - 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); + + Geom::Point start_arc_point = knot_curve_1->finalPoint(); + Geom::Point end_arc_point = curve_it2.pointAt(time2); + //add a gap helper + if (time2 == 1) { + end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER); } - 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]); + if (time1 == time0) { + start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER); } - 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; + + double k1 = distance(start_arc_point, curve_it1->finalPoint()) * K; + double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K; + Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1); + Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2); + Geom::Ray ray_1(start_arc_point, curve_it1->finalPoint()); + Geom::Ray ray_2(curve_it2.initialPoint(), end_arc_point); + if (cubic_1) { + ray_1.setPoints((*cubic_1)[2], start_arc_point); } - Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; - handleAngle = ray2.angle() + angle; - if (ccwToggle) { - handleAngle = ray2.angle() - angle; + if (cubic_2) { + ray_2.setPoints(end_arc_point, (*cubic_2)[1]); } - Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); - //straigth lines arc based - Line const x_line(Geom::Point(0,0),Geom::Point(1,0)); - Line const angled_line(startArcPoint,endArcPoint); - double angleArc = Geom::angle_between( x_line,angled_line); - double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0); - Coord rx = radius; - Coord ry = rx; - - if (times[1] != 1) { - if (times[1] != gapHelper && times[1] != times[0] + gapHelper) { - path_out.append(*knotCurve1); - } - int type = 0; - if(path_it->closed() && last){ - type = std::abs(filletChamferData[counter - counterCurves][Y]); - } else if (!path_it->closed() && last){ - //0 - } else { - type = std::abs(filletChamferData[counter + 1][Y]); - } - if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){ - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type >= 3000 && type < 4000) { - unsigned int chamferSubs = type-3000; - Geom::Path path_chamfer; - path_chamfer.start(path_out.finalPoint()); - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - } else { - path_chamfer.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); - } - double chamfer_stepsTime = 1.0/chamferSubs; - for(unsigned int i = 1; i < chamferSubs; i++){ - Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); - path_out.appendNew<Geom::LineSegment>(chamferStep); + bool ccw_toggle = cross(curve_it1->finalPoint() - start_arc_point, end_arc_point - start_arc_point) < 0; + double angle = angle_between(ray_1, ray_2, ccw_toggle); + double handle_angle_1 = ray_1.angle() - angle; + double handle_angle_2 = ray_2.angle() + angle; + if (ccw_toggle) { + handle_angle_1 = ray_1.angle() + angle; + handle_angle_2 = ray_2.angle() - angle; + } + Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point; + Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2); + Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point; + Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2); + if (time0 == 1) { + handle_1 = start_arc_point; + inverse_handle_1 = start_arc_point; + } + //remove gap helper + if (time2 == 1) { + end_arc_point = curve_it2.pointAt(time2); + } + if (time1 == time0) { + start_arc_point = curve_it1->pointAt(time0); + } + if (time1 != 1) { + if (time1 != time0 || (time1 == 1 && time0 == 1)) { + if (!knot_curve_1->isDegenerate()) { + tmp_path.append(*knot_curve_1); } - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type >= 4000 && type < 5000) { - unsigned int chamferSubs = type-4000; - Geom::Path path_chamfer; - path_chamfer.start(path_out.finalPoint()); - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - ccwToggle = ccwToggle?0:1; - path_chamfer.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_chamfer.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + } + SatelliteType type = satellite.satellite_type; + size_t steps = satellite.steps; + if (!steps) steps = 1; + Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0)); + Geom::Line const angled_line(start_arc_point, end_arc_point); + double arc_angle = Geom::angle_between(x_line, angled_line); + double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) / + sin(angle / 2.0); + Geom::Coord rx = radius; + Geom::Coord ry = rx; + bool eliptical = (is_straight_curve(*curve_it1) && + is_straight_curve(curve_it2) && method != FM_BEZIER) || + method == FM_ARC; + switch (type) { + case CHAMFER: + { + Geom::Path path_chamfer; + path_chamfer.start(tmp_path.finalPoint()); + if (eliptical) { + ccw_toggle = ccw_toggle ? 0 : 1; + path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point); + } + addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps); } - double chamfer_stepsTime = 1.0/chamferSubs; - for(unsigned int i = 1; i < chamferSubs; i++){ - Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); - path_out.appendNew<Geom::LineSegment>(chamferStep); + break; + case INVERSE_CHAMFER: + { + Geom::Path path_chamfer; + path_chamfer.start(tmp_path.finalPoint()); + if (eliptical) { + path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point); + } + addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps); } - path_out.appendNew<Geom::LineSegment>(endArcPoint); - } else if (type == 2) { - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - ccwToggle = ccwToggle?0:1; - path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - }else{ - path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + break; + case INVERSE_FILLET: + { + if (eliptical) { + tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point); + } } - } else if (type == 1){ - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_out.appendNew<EllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); - } else { - path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); + break; + default: //fillet + { + if (eliptical) { + ccw_toggle = ccw_toggle ? 0 : 1; + tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, 0, ccw_toggle, end_arc_point); + } else { + tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point); + } } + break; } } else { - path_out.append(*knotCurve1); - } - if (path_it->closed() && last) { - path_out.close(); - } - ++curve_it1; - if (curve_it2 != curve_endit) { - ++curve_it2; + if (!knot_curve_1->isDegenerate()) { + tmp_path.append(*knot_curve_1); + } } - counter++; - counterCurves++; + curve++; + time0 = time2; + } + if (path_it->closed()) { + tmp_path.close(); } - pathvector_out.push_back(path_out); + path++; + path_out.push_back(tmp_path); } - return pathvector_out; + return path_out; } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 290a37f92..c628added 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -7,25 +7,23 @@ * * 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 + * Jabiertxof:Thanks to all people help me * * Released under GNU GPL, read the file 'COPYING' for more information */ #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/parameter/satellitesarray.h" #include "live_effects/effect.h" +#include "live_effects/parameter/unit.h" +#include "live_effects/parameter/hidden.h" +#include "helper/geom-pathvectorsatellites.h" +#include "helper/geom-satellite.h" namespace Inkscape { namespace LivePathEffect { -enum FilletMethod { +enum Filletmethod { FM_AUTO, FM_ARC, FM_BEZIER, @@ -35,41 +33,39 @@ enum FilletMethod { class LPEFilletChamfer : public Effect { public: LPEFilletChamfer(LivePathEffectObject *lpeobject); - virtual ~LPEFilletChamfer(); - + virtual void doBeforeEffect(SPLPEItem const *lpeItem); virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in); - virtual void doOnApply(SPLPEItem const *lpeItem); - virtual void doBeforeEffect(SPLPEItem const *lpeItem); - virtual void adjustForNewPath(Geom::PathVector const &path_in); - virtual Gtk::Widget* newWidget(); - - int getKnotsNumber(SPCurve const *c); - void toggleHide(); - void toggleFlexFixed(); - void chamfer(); - void chamferSubdivisions(); - void inverseChamfer(); - void fillet(); - void inverseFillet(); - void updateFillet(); - void doUpdateFillet(Geom::PathVector const& original_pathv, double power); - void doChangeType(Geom::PathVector const& original_pathv, int type); + virtual Gtk::Widget *newWidget(); + Geom::Ray getRay(Geom::Point start, Geom::Point end, Geom::Curve *curve, bool reverse); + void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps); + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); + void updateSatelliteType(SatelliteType satellitetype); + void setSelected(PathVectorSatellites *_pathvector_satellites); + //void convertUnit(); + void updateChamferSteps(); + void updateAmount(); void refreshKnots(); - FilletChamferPointArrayParam fillet_chamfer_values; + SatellitesArrayParam satellites_param; private: - - BoolParam hide_knots; - BoolParam ignore_radius_0; - BoolParam only_selected; - BoolParam flexible; - BoolParam use_knot_distance; - EnumParam<FilletMethod> method; + UnitParam unit; + EnumParam<Filletmethod> method; ScalarParam radius; ScalarParam chamfer_steps; + BoolParam flexible; + HiddenParam mode; + BoolParam mirror_knots; + BoolParam only_selected; + BoolParam use_knot_distance; + BoolParam hide_knots; + BoolParam apply_no_radius; + BoolParam apply_with_radius; ScalarParam helper_size; + bool _degenerate_hide; + PathVectorSatellites *_pathvector_satellites; + Geom::PathVector _hp; LPEFilletChamfer(const LPEFilletChamfer &); LPEFilletChamfer &operator=(const LPEFilletChamfer &); diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp index d4d695542..dad520041 100644 --- a/src/live_effects/lpe-gears.cpp +++ b/src/live_effects/lpe-gears.cpp @@ -7,15 +7,9 @@ */ #include "live_effects/lpe-gears.h" - -#include <vector> - -#include <glibmm/i18n.h> - -#include <2geom/d2.h> -#include <2geom/sbasis.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/path.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> using std::vector; using namespace Geom; @@ -212,7 +206,8 @@ namespace LivePathEffect { LPEGears::LPEGears(LivePathEffectObject *lpeobject) : Effect(lpeobject), teeth(_("_Teeth:"), _("The number of teeth"), "teeth", &wr, this, 10), - phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5) + phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5), + min_radius(_("Min Radius:"), _("Minimum radius, low values can be slow"), "min_radius", &wr, this, 5.0) { /* Tooth pressure angle: The angle between the tooth profile and a perpendicular to the pitch * circle, usually at the point where the pitch circle meets the tooth profile. Standard angles @@ -223,8 +218,10 @@ LPEGears::LPEGears(LivePathEffectObject *lpeobject) : teeth.param_make_integer(); teeth.param_set_range(3, 1e10); - registerParameter( dynamic_cast<Parameter *>(&teeth) ); - registerParameter( dynamic_cast<Parameter *>(&phi) ); + min_radius.param_set_range(0.01, 9999.0); + registerParameter(&teeth); + registerParameter(&phi); + registerParameter(&min_radius); } LPEGears::~LPEGears() @@ -247,12 +244,17 @@ LPEGears::doEffect_path (Geom::PathVector const &path_in) gear->angle(atan2((*it).initialPoint() - gear_centre)); ++it; - if ( it == gearpath.end() ) return path_out; - gear->pitch_radius(Geom::distance(gear_centre, (*it).finalPoint())); + if ( it == gearpath.end() ) return path_out; + double radius = Geom::distance(gear_centre, (*it).finalPoint()); + radius = radius < min_radius?min_radius:radius; + gear->pitch_radius(radius); path_out.push_back( gear->path()); - + for (++it; it != gearpath.end() ; ++it) { + if (are_near((*it).initialPoint(), (*it).finalPoint())) { + continue; + } // iterate through Geom::Curve in path_in Gear* gearnew = new Gear(gear->spawn( (*it).finalPoint() )); path_out.push_back( gearnew->path() ); diff --git a/src/live_effects/lpe-gears.h b/src/live_effects/lpe-gears.h index 5dd6dd239..57b49d2b5 100644 --- a/src/live_effects/lpe-gears.h +++ b/src/live_effects/lpe-gears.h @@ -27,6 +27,7 @@ public: private: ScalarParam teeth; ScalarParam phi; + ScalarParam min_radius; LPEGears(const LPEGears&); LPEGears& operator=(const LPEGears&); diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index 74c7efd90..db3faa307 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -9,18 +9,15 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <glibmm/i18n.h> - #include "live_effects/lpe-interpolate.h" -#include <2geom/path.h> #include <2geom/sbasis-to-bezier.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis-geometric.h> #include "sp-path.h" #include "display/curve.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -33,9 +30,9 @@ LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : { show_orig_path = true; - registerParameter( dynamic_cast<Parameter *>(&trajectory_path) ); - registerParameter( dynamic_cast<Parameter *>(&equidistant_spacing) ); - registerParameter( dynamic_cast<Parameter *>(&number_of_steps) ); + registerParameter(&trajectory_path); + registerParameter(&equidistant_spacing); + registerParameter(&number_of_steps); number_of_steps.param_make_integer(); number_of_steps.param_set_range(2, Geom::infinity()); diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp index cf70832ee..0a0bcea14 100644 --- a/src/live_effects/lpe-interpolate_points.cpp +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -12,10 +12,9 @@ */ #include "live_effects/lpe-interpolate_points.h" - -#include <2geom/path.h> - #include "live_effects/lpe-powerstroke-interpolators.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index fe42932be..0e1e46a94 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -10,19 +10,17 @@ #include "live_effects/parameter/enum.h" #include "helper/geom-pathstroke.h" -#include "sp-shape.h" #include "style.h" -#include "xml/repr.h" -#include "sp-paint-server.h" #include "svg/svg-color.h" #include "desktop-style.h" #include "svg/css-ostringstream.h" #include "display/curve.h" -#include <2geom/path.h> #include <2geom/elliptical-arc.h> #include "lpe-jointype.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -85,6 +83,7 @@ LPEJoinType::~LPEJoinType() void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) { if (SP_IS_SHAPE(lpeitem)) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; @@ -111,8 +110,14 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - - line_width.param_set_value(width); + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() + + (Glib::ustring)"/" + + (Glib::ustring)"line_width"; + bool valid = prefs->getEntry(pref_path).isValid(); + if(!valid){ + line_width.param_set_value(width); + } line_width.write_to_SVG(); } } diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index a033a6c4a..261612fdb 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -16,28 +16,24 @@ #include "sp-path.h" #include "display/curve.h" #include "live_effects/lpe-knot.h" -#include "svg/svg.h" #include "style.h" #include "knot-holder-entity.h" #include "knotholder.h" -#include <glibmm/i18n.h> #include <gdk/gdk.h> #include <2geom/sbasis-to-bezier.h> -#include <2geom/sbasis.h> -#include <2geom/d2.h> -#include <2geom/path.h> #include <2geom/bezier-to-sbasis.h> #include <2geom/basic-intersection.h> -#include <2geom/exception.h> +#include "helper/geom.h" // for change crossing undo #include "verbs.h" #include "document.h" #include "document-undo.h" -#include <exception> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -101,7 +97,7 @@ findShadowedTime(Geom::Path const &patha, std::vector<Geom::Point> const &pt_and Affine mat = from_basis( T, N, pt_and_dir[0] ); mat = mat.inverse(); - Path p = patha * mat; + Geom::Path p = patha * mat; std::vector<double> times; @@ -360,12 +356,12 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : switcher(0.,0.) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&interruption_width) ); - registerParameter( dynamic_cast<Parameter *>(&prop_to_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&add_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&add_other_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&switcher_size) ); - registerParameter( dynamic_cast<Parameter *>(&crossing_points_vector) ); + registerParameter(&interruption_width); + registerParameter(&prop_to_stroke_width); + registerParameter(&add_stroke_width); + registerParameter(&add_other_stroke_width); + registerParameter(&switcher_size); + registerParameter(&crossing_points_vector); _provides_knotholder_entities = true; } @@ -399,14 +395,14 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in) if (gpaths.size()==0){ return path_in; } - - for (unsigned comp=0; comp<path_in.size(); comp++){ + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); + for (unsigned comp=0; comp<original_pathv.size(); comp++){ //find the relevant path component in gpaths (required to allow groups!) //Q: do we always receive the group members in the same order? can we rest on that? unsigned i0 = 0; for (i0=0; i0<gpaths.size(); i0++){ - if (path_in[comp]==gpaths[i0]) break; + if (original_pathv[comp]==gpaths[i0]) break; } if (i0 == gpaths.size() ) {THROW_EXCEPTION("lpe-knot error: group member not recognized");}// this should not happen... @@ -484,7 +480,7 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in) // std::cout<<"fusing first and last component\n"; ++beg_comp; --end_comp; - Path first = gpaths[i0].portion(dom.back()); + Geom::Path first = gpaths[i0].portion(dom.back()); //FIXME: stitching should not be necessary (?!?) first.setStitching(true); first.append(gpaths[i0].portion(dom.front())); @@ -521,7 +517,7 @@ collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::v c = SP_SHAPE(lpeitem)->getCurve(); } if (c) { - Geom::PathVector subpaths = c->get_pathvector(); + Geom::PathVector subpaths = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); for (unsigned i=0; i<subpaths.size(); i++){ paths.push_back(subpaths[i]); //FIXME: do we have to be more carefull when trying to access stroke width? @@ -619,10 +615,10 @@ LPEKnot::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::Pat hp_vec.push_back(pathv); } -void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { KnotHolderEntity *e = new KnotHolderEntityCrossingSwitcher(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Drag to select a crossing, click to flip it") ); knotholder->add(e); }; diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h index 95bfaf6e1..ac518b97c 100644 --- a/src/live_effects/lpe-knot.h +++ b/src/live_effects/lpe-knot.h @@ -61,7 +61,7 @@ public: /* the knotholder entity classes must be declared friends */ friend class KnotHolderEntityCrossingSwitcher; - void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); protected: virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index 3c23e349e..124a7a9c6 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -6,7 +6,7 @@ * Authors: * Johan Engelen <j.b.c.engelen@utwente.nl> * Steren Giannini - * Noé Falzon + * No� Falzon * Victor Navez * * Copyright (C) 2007-2008 Authors @@ -16,23 +16,12 @@ #include "live_effects/lpe-lattice.h" -#include "sp-shape.h" -#include "sp-item.h" -#include "sp-path.h" #include "display/curve.h" -#include "svg/svg.h" -#include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> -#include <2geom/transforms.h> - -#include "desktop.h" // TODO: should be factored out (see below) - +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> using namespace Geom; namespace Inkscape { @@ -61,22 +50,22 @@ LPELattice::LPELattice(LivePathEffectObject *lpeobject) : { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&grid_point0) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point1) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point2) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point3) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point4) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point5) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point6) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point7) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point8) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point9) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point10) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point11) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point12) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point13) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); + registerParameter(&grid_point0); + registerParameter(&grid_point1); + registerParameter(&grid_point2); + registerParameter(&grid_point3); + registerParameter(&grid_point4); + registerParameter(&grid_point5); + registerParameter(&grid_point6); + registerParameter(&grid_point7); + registerParameter(&grid_point8); + registerParameter(&grid_point9); + registerParameter(&grid_point10); + registerParameter(&grid_point11); + registerParameter(&grid_point12); + registerParameter(&grid_point13); + registerParameter(&grid_point14); + registerParameter(&grid_point15); apply_to_clippath_and_mask = true; } diff --git a/src/live_effects/lpe-lattice.h b/src/live_effects/lpe-lattice.h index 5eb48909b..8720af138 100644 --- a/src/live_effects/lpe-lattice.h +++ b/src/live_effects/lpe-lattice.h @@ -9,7 +9,7 @@ * Authors: * Johan Engelen * Steren Giannini - * Noé Falzon + * Noé Falzon * Victor Navez * * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index 0c403daec..e827491c0 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -6,7 +6,7 @@ * Authors: * Johan Engelen <j.b.c.engelen@utwente.nl> * Steren Giannini - * Noé Falzon + * No� Falzon * Victor Navez * ~suv * Jabiertxo Arraiza @@ -16,26 +16,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <gtkmm.h> #include "live_effects/lpe-lattice2.h" - -#include <gtkmm/expander.h> - -#include "sp-shape.h" -#include "sp-item.h" -#include "sp-path.h" #include "display/curve.h" -#include "svg/svg.h" #include "helper/geom.h" -#include <2geom/path.h> -#include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> -#include "helper/geom-curves.h" -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> -#include <2geom/transforms.h> + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> using namespace Geom; @@ -280,7 +269,7 @@ void LPELattice2::onExpanderChanged() { expanded = expander->get_expanded(); - if(expander->get_expanded()) { + if(expanded) { expander->set_label (Glib::ustring(_("Hide Points"))); } else { expander->set_label (Glib::ustring(_("Show Points"))); diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h index 8d0c18a3a..95c5285fb 100644 --- a/src/live_effects/lpe-lattice2.h +++ b/src/live_effects/lpe-lattice2.h @@ -9,7 +9,7 @@ * Authors: * Johan Engelen * Steren Giannini - * Noé Falzon + * Noé Falzon * Victor Navez * ~suv * Jabiertxo Arraiza @@ -18,9 +18,9 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "live_effects/parameter/enum.h" -#include <gtkmm/widget.h> + #include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" #include "live_effects/parameter/point.h" #include "live_effects/lpegroupbbox.h" diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp index dfd8aea8f..fd23da804 100644 --- a/src/live_effects/lpe-line_segment.cpp +++ b/src/live_effects/lpe-line_segment.cpp @@ -13,10 +13,8 @@ #include "live_effects/lpe-line_segment.h" #include "ui/tools/lpe-tool.h" - -#include <2geom/pathvector.h> -#include <2geom/geom.h> -#include <2geom/bezier-curve.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -34,7 +32,7 @@ LPELineSegment::LPELineSegment(LivePathEffectObject *lpeobject) : end_type(_("End type:"), _("Determines on which side the line or line segment is infinite."), "end_type", EndTypeConverter, &wr, this, END_OPEN_BOTH) { /* register all your parameters here, so Inkscape knows which parameters this effect has: */ - registerParameter( dynamic_cast<Parameter *>(&end_type) ); + registerParameter(&end_type); } LPELineSegment::~LPELineSegment() diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp new file mode 100644 index 000000000..99828aef8 --- /dev/null +++ b/src/live_effects/lpe-measure-line.cpp @@ -0,0 +1,763 @@ +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * Some code and ideas migrated from dimensioning.py by + * Johannes B. Rutzmoser, johannes.rutzmoser (at) googlemail (dot) com + * https://github.com/Rutzmoser/inkscape_dimensioning + * Copyright (C) 2014 Author(s) + + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "live_effects/lpe-measure-line.h" +#include <pangomm/fontdescription.h> +#include "ui/dialog/livepatheffect-editor.h" +#include <libnrtype/font-lister.h> +#include "inkscape.h" +#include "xml/node.h" +#include "xml/sp-css-attr.h" +#include "preferences.h" +#include "util/units.h" +#include "svg/svg-length.h" +#include "svg/svg-color.h" +#include "svg/svg.h" +#include "display/curve.h" +#include "helper/geom.h" +#include "2geom/affine.h" +#include "path-chemistry.h" +#include "style.h" +#include "sp-root.h" +#include "sp-defs.h" +#include "sp-item.h" +#include "sp-shape.h" +#include "sp-path.h" +#include "document.h" +#include <iomanip> + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +using namespace Geom; +namespace Inkscape { +namespace LivePathEffect { + +static const Util::EnumData<OrientationMethod> OrientationMethodData[] = { + { OM_HORIZONTAL, N_("Horizontal"), "horizontal" }, + { OM_VERTICAL, N_("Vertical"), "vertical" }, + { OM_PARALLEL, N_("Parallel"), "parallel" } +}; +static const Util::EnumDataConverter<OrientationMethod> OMConverter(OrientationMethodData, OM_END); + +LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"), + fontbutton(_("Font"), _("Font Selector"), "fontbutton", &wr, this), + orientation(_("Orientation"), _("Orientation method"), "orientation", OMConverter, &wr, this, OM_PARALLEL, false), + curve_linked(_("Curve on origin"), _("Curve on origin, set 0 to start/end"), "curve_linked", &wr, this, 1), + precision(_("Precision"), _("Precision"), "precision", &wr, this, 2), + position(_("Position"), _("Position"), "position", &wr, this, 5), + text_top_bottom(_("Text top/bottom"), _("Text top/bottom"), "text_top_bottom", &wr, this, 0), + text_right_left(_("Text right/left"), _("Text right/left"), "text_right_left", &wr, this, 0), + helpline_distance(_("Helpline distance"), _("Helpline distance"), "helpline_distance", &wr, this, 0.0), + helpline_overlap(_("Helpline overlap"), _("Helpline overlap"), "helpline_overlap", &wr, this, 2.0), + scale(_("Scale"), _("Scaling factor"), "scale", &wr, this, 1.0), + format(_("Format"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"{measure}{unit}"), + id_origin("id_origin", "id_origin", "id_origin", &wr, this,""), + arrows_outside(_("Arrows outside"), _("Arrows outside"), "arrows_outside", &wr, this, false), + flip_side(_("Flip side"), _("Flip side"), "flip_side", &wr, this, false), + scale_sensitive(_("Scale sensitive"), _("Costrained scale sensitive to transformed containers"), "scale_sensitive", &wr, this, true), + local_locale(_("Local Number Format"), _("Local number format"), "local_locale", &wr, this, true), + line_group_05(_("Line Group 0.5"), _("Line Group 0.5, from 0.7"), "line_group_05", &wr, this, true), + rotate_anotation(_("Rotate Anotation"), _("Rotate Anotation"), "rotate_anotation", &wr, this, true), + hide_back(_("Hide if label over"), _("Hide DIN line if label over"), "hide_back", &wr, this, true), + dimline_format(_("CSS DIN line"), _("Override CSS to DIN line, return to save, empty to reset to DIM"), "dimline_format", &wr, this,""), + helperlines_format(_("CSS helpers"), _("Override CSS to helper lines, return to save, empty to reset to DIM"), "helperlines_format", &wr, this,""), + anotation_format(_("CSS anotation"), _("Override CSS to anotation text, return to save, empty to reset to DIM"), "anotation_format", &wr, this,""), + arrows_format(_("CSS arrows"), _("Override CSS to arrows, return to save, empty to reset DIM"), "arrows_format", &wr, this,""), + expanded(false) +{ + //set to true the parameters you want to be changed his default values + registerParameter(&unit); + registerParameter(&fontbutton); + registerParameter(&orientation); + registerParameter(&curve_linked); + registerParameter(&precision); + registerParameter(&position); + registerParameter(&text_top_bottom); + registerParameter(&text_right_left); + registerParameter(&helpline_distance); + registerParameter(&helpline_overlap); + registerParameter(&scale); + registerParameter(&format); + registerParameter(&arrows_outside); + registerParameter(&flip_side); + registerParameter(&scale_sensitive); + registerParameter(&local_locale); + registerParameter(&line_group_05); + registerParameter(&rotate_anotation); + registerParameter(&hide_back); + registerParameter(&dimline_format); + registerParameter(&helperlines_format); + registerParameter(&anotation_format); + registerParameter(&arrows_format); + registerParameter(&id_origin); + + id_origin.param_hide_canvas_text(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + Glib::ustring format_value = prefs->getString("/live_effects/measure-line/format"); + if(format_value.empty()){ + format_value = "{measure}{unit}"; + } + format.param_update_default(format_value.c_str()); + + format.param_hide_canvas_text(); + dimline_format.param_hide_canvas_text(); + helperlines_format.param_hide_canvas_text(); + anotation_format.param_hide_canvas_text(); + arrows_format.param_hide_canvas_text(); + precision.param_set_range(0, 100); + precision.param_set_increments(1, 1); + precision.param_set_digits(0); + precision.param_make_integer(true); + curve_linked.param_set_range(0, 999); + curve_linked.param_set_increments(1, 1); + curve_linked.param_set_digits(0); + curve_linked.param_make_integer(true); + precision.param_make_integer(true); + position.param_set_range(-999999.0, 999999.0); + position.param_set_increments(1, 1); + position.param_set_digits(2); + text_top_bottom.param_set_range(-999999.0, 999999.0); + text_top_bottom.param_set_increments(1, 1); + text_top_bottom.param_set_digits(2); + text_right_left.param_set_range(-999999.0, 999999.0); + text_right_left.param_set_increments(1, 1); + text_right_left.param_set_digits(2); + helpline_distance.param_set_range(-999999.0, 999999.0); + helpline_distance.param_set_increments(1, 1); + helpline_distance.param_set_digits(2); + helpline_overlap.param_set_range(-999999.0, 999999.0); + helpline_overlap.param_set_increments(1, 1); + helpline_overlap.param_set_digits(2); + start_stored = Geom::Point(0,0); + end_stored = Geom::Point(0,0); + id_origin.param_widget_is_visible(false); +} + +LPEMeasureLine::~LPEMeasureLine() {} + +void +LPEMeasureLine::createArrowMarker(const char * mode) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + SPObject *elemref = NULL; + Inkscape::XML::Node *arrow = NULL; + if ((elemref = document->getObjectById(mode))) { + Inkscape::XML::Node *arrow= elemref->getRepr(); + if (arrow) { + arrow->setAttribute("sodipodi:insensitive", "true"); + arrow->setAttribute("transform", NULL); + Inkscape::XML::Node *arrow_data = arrow->firstChild(); + if (arrow_data) { + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property (css, "fill","#000000"); + sp_repr_css_set_property (css, "stroke","none"); + arrow_data->setAttribute("transform", NULL); + sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue()); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + arrow_data->setAttribute("style", css_str.c_str()); + } + } + } else { + arrow = xml_doc->createElement("svg:marker"); + arrow->setAttribute("id", mode); + arrow->setAttribute("inkscape:stockid", mode); + arrow->setAttribute("orient", "auto"); + arrow->setAttribute("refX", "0.0"); + arrow->setAttribute("refY", "0.0"); + arrow->setAttribute("style", "overflow:visible"); + arrow->setAttribute("sodipodi:insensitive", "true"); + /* Create <path> */ + Inkscape::XML::Node *arrow_path = xml_doc->createElement("svg:path"); + if (std::strcmp(mode, "ArrowDIN-start") == 0) { + arrow_path->setAttribute("d", "M -8,0 8,-2.11 8,2.11 z"); + } else if (std::strcmp(mode, "ArrowDIN-end") == 0) { + arrow_path->setAttribute("d", "M 8,0 -8,2.11 -8,-2.11 z"); + } else if (std::strcmp(mode, "ArrowDINout-start") == 0) { + arrow_path->setAttribute("d", "M 0,0 -16,2.11 -16,0.5 -26,0.5 -26,-0.5 -16,-0.5 -16,-2.11 z"); + } else { + arrow_path->setAttribute("d", "M 0,0 16,2.11 16,0.5 26,0.5 26,-0.5 16,-0.5 16,-2.11 z"); + } + + arrow_path->setAttribute("id", Glib::ustring(mode).append("_path").c_str()); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property (css, "fill","#000000"); + sp_repr_css_set_property (css, "stroke","none"); + sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue()); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + arrow_path->setAttribute("style", css_str.c_str()); + arrow->addChild(arrow_path, NULL); + Inkscape::GC::release(arrow_path); + elemref = SP_OBJECT(document->getDefs()->appendChildRepr(arrow)); + Inkscape::GC::release(arrow); + } + items.push_back(mode); +} + +void +LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + Inkscape::XML::Node *rtext = NULL; + double doc_w = document->getRoot()->width.value; + Geom::Scale scale = document->getDocumentScale(); + SPNamedView *nv = sp_document_namedview(document, NULL); + Glib::ustring display_unit = nv->display_units->abbr; + if (display_unit.empty()) { + display_unit = "px"; + } + //only check constrain viewbox on X + doc_scale = Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units ); + if( doc_scale > 0 ) { + doc_scale= 1.0/doc_scale; + } else { + doc_scale = 1.0; + } + const char * id = g_strdup(Glib::ustring("text-on-").append(this->getRepr()->attribute("id")).c_str()); + SPObject *elemref = NULL; + Inkscape::XML::Node *rtspan = NULL; + if ((elemref = document->getObjectById(id))) { + if (remove) { + elemref->deleteObject(); + return; + } + pos = pos - Point::polar(angle, text_right_left); + rtext = elemref->getRepr(); + sp_repr_set_svg_double(rtext, "x", pos[Geom::X]); + sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]); + rtext->setAttribute("sodipodi:insensitive", "true"); + rtext->setAttribute("transform", NULL); + } else { + if (remove) { + return; + } + rtext = xml_doc->createElement("svg:text"); + rtext->setAttribute("xml:space", "preserve"); + rtext->setAttribute("id", id); + rtext->setAttribute("sodipodi:insensitive", "true"); + pos = pos - Point::polar(angle, text_right_left); + sp_repr_set_svg_double(rtext, "x", pos[Geom::X]); + sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]); + rtspan = xml_doc->createElement("svg:tspan"); + rtspan->setAttribute("sodipodi:role", "line"); + } + gchar * transform; + Geom::Affine affine = Geom::Affine(Geom::Translate(pos).inverse()); + angle = std::fmod(angle, 2*M_PI); + if (angle < 0) angle += 2*M_PI; + if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) { + angle = std::fmod(angle + rad_from_deg(180), 2*M_PI); + if (angle < 0) angle += 2*M_PI; + } + affine *= Geom::Rotate(angle); + affine *= Geom::Translate(pos); + if (rotate_anotation) { + transform = sp_svg_transform_write(affine); + } else { + transform = NULL; + } + rtext->setAttribute("transform", transform); + g_free(transform); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue()); + Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); + fontlister->fill_css(css, Glib::ustring(fontbutton.param_getSVGValue())); + std::stringstream font_size; + font_size.imbue(std::locale::classic()); + font_size << fontsize << "pt"; + sp_repr_css_set_property (css, "font-size",font_size.str().c_str()); + sp_repr_css_set_property (css, "line-height","125%"); + sp_repr_css_set_property (css, "letter-spacing","0"); + sp_repr_css_set_property (css, "word-spacing", "0"); + sp_repr_css_set_property (css, "text-align", "center"); + sp_repr_css_set_property (css, "text-anchor", "middle"); + sp_repr_css_set_property (css, "fill", "#000000"); + sp_repr_css_set_property (css, "fill-opacity", "1"); + sp_repr_css_set_property (css, "stroke", "none"); + sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue()); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + if (!rtspan) { + rtspan = rtext->firstChild(); + } + rtext->setAttribute("style", css_str.c_str()); + rtspan->setAttribute("style", NULL); + rtspan->setAttribute("transform", NULL); + sp_repr_css_attr_unref (css); + if (!elemref) { + rtext->addChild(rtspan, NULL); + Inkscape::GC::release(rtspan); + } + length = Inkscape::Util::Quantity::convert(length / doc_scale, display_unit.c_str(), unit.get_abbreviation()); + char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL)); + if (local_locale) { + setlocale (LC_NUMERIC, ""); + } else { + setlocale (LC_NUMERIC, "C"); + } + gchar length_str[64]; + g_snprintf(length_str, 64, "%.*f", (int)precision, length); + setlocale (LC_NUMERIC, oldlocale); + g_free (oldlocale); + Glib::ustring label_value(format.param_getSVGValue()); + size_t s = label_value.find(Glib::ustring("{measure}"),0); + if(s < label_value.length()) { + label_value.replace(s,s+9,length_str); + } + s = label_value.find(Glib::ustring("{unit}"),0); + if(s < label_value.length()) { + label_value.replace(s,s+6,unit.get_abbreviation()); + } + if ( !valid ) { + label_value = Glib::ustring(_("Non Uniform Scale")); + } + Inkscape::XML::Node *rstring = NULL; + if (!elemref) { + rstring = xml_doc->createTextNode(label_value.c_str()); + rtspan->addChild(rstring, NULL); + Inkscape::GC::release(rstring); + } else { + rstring = rtspan->firstChild(); + rstring->setContent(label_value.c_str()); + } + if (!elemref) { + elemref = sp_lpe_item->parent->appendChildRepr(rtext); + Inkscape::GC::release(rtext); + } else if (elemref->parent != sp_lpe_item->parent) { + Inkscape::XML::Node *old_repr = elemref->getRepr(); + Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy); + Inkscape::GC::release(copy); + elemref->deleteObject(); + copy->setAttribute("id", id); + elemref = elemref_copy; + } + items.push_back(id); + Geom::OptRect bounds = SP_ITEM(elemref)->bounds(SPItem::GEOMETRIC_BBOX); + if (bounds) { + anotation_width = bounds->width() * 1.15; + } +} + +void +LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + SPObject *elemref = NULL; + Inkscape::XML::Node *line = NULL; + if (!main) { + Geom::Ray ray(start, end); + Geom::Coord angle = ray.angle(); + start = start + Point::polar(angle, helpline_distance ); + end = end + Point::polar(angle, helpline_overlap ); + } + Geom::PathVector line_pathv; + if (main && std::abs(text_top_bottom) < fontsize/1.5 && hide_back && !overflow){ + Geom::Path line_path; + double k = 0; + if (flip_side) { + k = (Geom::distance(start,end)/2.0) + arrow_gap - (anotation_width/2.0); + } else { + k = (Geom::distance(start,end)/2.0) - arrow_gap - (anotation_width/2.0); + } + if (Geom::distance(start,end) < anotation_width){ + if ((elemref = document->getObjectById(id))) { + if (remove) { + elemref->deleteObject(); + } + return; + } + } + //k = std::max(k , arrow_gap -1); + Geom::Ray ray(end, start); + Geom::Coord angle = ray.angle(); + line_path.start(start); + line_path.appendNew<Geom::LineSegment>(start - Point::polar(angle, k)); + line_pathv.push_back(line_path); + line_path.clear(); + line_path.start(end + Point::polar(angle, k)); + line_path.appendNew<Geom::LineSegment>(end); + line_pathv.push_back(line_path); + } else { + Geom::Path line_path; + line_path.start(start); + line_path.appendNew<Geom::LineSegment>(end); + line_pathv.push_back(line_path); + } + if ((elemref = document->getObjectById(id))) { + if (remove) { + elemref->deleteObject(); + return; + } + line = elemref->getRepr(); + + gchar * line_str = sp_svg_write_path( line_pathv ); + line->setAttribute("d" , line_str); + line->setAttribute("transform", NULL); + g_free(line_str); + } else { + if (remove) { + return; + } + line = xml_doc->createElement("svg:path"); + line->setAttribute("id", id); + gchar * line_str = sp_svg_write_path( line_pathv ); + line->setAttribute("d" , line_str); + g_free(line_str); + } + line->setAttribute("sodipodi:insensitive", "true"); + line_pathv.clear(); + + Glib::ustring style = Glib::ustring("stroke:#000000;fill:none;"); + if (overflow && !arrows) { + line->setAttribute("inkscape:label", "downline"); + } else if (main) { + line->setAttribute("inkscape:label", "dinline"); + if (arrows_outside) { + style = style + Glib::ustring("marker-start:url(#ArrowDINout-start);marker-end:url(#ArrowDINout-end);"); + } else { + style = style + Glib::ustring("marker-start:url(#ArrowDIN-start);marker-end:url(#ArrowDIN-end);"); + } + } else { + line->setAttribute("inkscape:label", "dinhelpline"); + } + std::stringstream stroke_w; + stroke_w.imbue(std::locale::classic()); + if (line_group_05) { + double stroke_width = Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str()); + stroke_w << stroke_width; + style = style + Glib::ustring("stroke-width:" + stroke_w.str()); + } else { + double stroke_width = Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str()); + stroke_w << stroke_width; + style = style + Glib::ustring("stroke-width:" + stroke_w.str()); + } + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, style.c_str()); + if (main) { + sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue()); + } else { + sp_repr_css_attr_add_from_string(css, helperlines_format.param_getSVGValue()); + } + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + line->setAttribute("style", css_str.c_str()); + if (!elemref) { + elemref = sp_lpe_item->parent->appendChildRepr(line); + Inkscape::GC::release(line); + } else if (elemref->parent != sp_lpe_item->parent) { + Inkscape::XML::Node *old_repr = elemref->getRepr(); + Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy); + Inkscape::GC::release(copy); + elemref->deleteObject(); + copy->setAttribute("id", id); + } + items.push_back(id); +} + +void +LPEMeasureLine::doOnApply(SPLPEItem const* lpeitem) +{ + if (!SP_IS_SHAPE(lpeitem)) { + g_warning("LPE measure line can only be applied to shapes (not groups)."); + SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); + item->removeCurrentPathEffect(false); + } + id_origin.param_setValue(Glib::ustring(lpeitem->getId())); + id_origin.write_to_SVG(); +} + +void +LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem) +{ + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); + sp_lpe_item->parent = dynamic_cast<SPObject *>(splpeitem->parent); + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Node *root = splpeitem->document->getReprRoot(); + Inkscape::XML::Node *root_origin = document->getReprRoot(); + if (root_origin != root) { + return; + } + SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem); + if (sp_path) { + Geom::Affine affinetransform = i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(document->getRoot())); + Geom::PathVector pathvector = sp_path->get_original_curve()->get_pathvector(); + Geom::Affine writed_transform = Geom::identity(); + sp_svg_transform_read(splpeitem->getAttribute("transform"), &writed_transform ); + pathvector *= writed_transform; + if ((Glib::ustring(format.param_getSVGValue()).empty())) { + format.param_setValue(Glib::ustring("{measure}{unit}")); + } + size_t ncurves = pathvector.curveCount(); + if (ncurves != (size_t)curve_linked.param_get_max()) { + curve_linked.param_set_range(0, ncurves); + } + Geom::Point start = pathvector.initialPoint(); + Geom::Point end = pathvector.finalPoint(); + if (curve_linked) { //!0 + start = pathvector.pointAt(curve_linked -1); + end = pathvector.pointAt(curve_linked); + } + if (Geom::are_near(start, start_stored, 0.01) && + Geom::are_near(end, end_stored, 0.01) && + sp_lpe_item->getCurrentLPE() != this){ + return; + } + items.clear(); + start_stored = start; + end_stored = end; + Geom::Point hstart = start; + Geom::Point hend = end; + bool remove = false; + if (Geom::are_near(hstart, hend)) { + remove = true; + } + if (orientation == OM_VERTICAL) { + Coord xpos = std::max(hstart[Geom::X],hend[Geom::X]); + if (flip_side) { + xpos = std::min(hstart[Geom::X],hend[Geom::X]); + } + hstart[Geom::X] = xpos; + hend[Geom::X] = xpos; + if (hstart[Geom::Y] > hend[Geom::Y]) { + swap(hstart,hend); + swap(start,end); + } + if (Geom::are_near(hstart[Geom::Y], hend[Geom::Y])) { + remove = true; + } + } + if (orientation == OM_HORIZONTAL) { + Coord ypos = std::max(hstart[Geom::Y],hend[Geom::Y]); + if (flip_side) { + ypos = std::min(hstart[Geom::Y],hend[Geom::Y]); + } + hstart[Geom::Y] = ypos; + hend[Geom::Y] = ypos; + if (hstart[Geom::X] < hend[Geom::X]) { + swap(hstart,hend); + swap(start,end); + } + if (Geom::are_near(hstart[Geom::X], hend[Geom::X])) { + remove = true; + } + } + double length = Geom::distance(hstart,hend) * scale; + Geom::Point pos = Geom::middle_point(hstart,hend); + Geom::Ray ray(hstart,hend); + Geom::Coord angle = ray.angle(); + if (flip_side) { + angle = std::fmod(angle + rad_from_deg(180), 2*M_PI); + if (angle < 0) angle += 2*M_PI; + } + if (arrows_outside) { + createArrowMarker("ArrowDINout-start"); + createArrowMarker("ArrowDINout-end"); + } else { + createArrowMarker("ArrowDIN-start"); + createArrowMarker("ArrowDIN-end"); + } + //We get the font size to offset the text to the middle + Pango::FontDescription fontdesc(Glib::ustring(fontbutton.param_getSVGValue())); + fontsize = fontdesc.get_size()/(double)Pango::SCALE; + fontsize *= document->getRoot()->c2p.inverse().expansionX(); + Geom::Coord angle_cross = std::fmod(angle + rad_from_deg(90), 2*M_PI); + if (angle_cross < 0) angle_cross += 2*M_PI; + angle = std::fmod(angle, 2*M_PI); + if (angle < 0) angle += 2*M_PI; + if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) { + pos = pos - Point::polar(angle_cross, (position - text_top_bottom) + fontsize/2.5); + } else { + pos = pos - Point::polar(angle_cross, (position + text_top_bottom) - fontsize/2.5); + } + double parents_scale = (affinetransform.expansionX() + affinetransform.expansionY()) / 2.0; + if (scale_sensitive) { + length *= parents_scale; + } + if (scale_sensitive && !affinetransform.preservesAngles()) { + createTextLabel(pos, length, angle, remove, false); + } else { + createTextLabel(pos, length, angle, remove, true); + } + bool overflow = false; + const char * downline = g_strdup(Glib::ustring("downline-").append(this->getRepr()->attribute("id")).c_str()); + //delete residual lines if exist + createLine(Geom::Point(),Geom::Point(), downline, true, overflow, true, false); + //Create it + if ((anotation_width/2) + std::abs(text_right_left) > Geom::distance(start,end)/2.0) { + Geom::Point sstart = end - Point::polar(angle_cross, position); + Geom::Point send = end - Point::polar(angle_cross, position); + if ((text_right_left < 0 && flip_side) || (text_right_left > 0 && !flip_side)) { + sstart = start - Point::polar(angle_cross, position); + send = start - Point::polar(angle_cross, position); + } + Geom::Point prog_end = Geom::Point(); + if (std::abs(text_top_bottom) < fontsize/1.5 && hide_back) { + if (text_right_left > 0 ) { + prog_end = sstart - Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0)); + } else { + prog_end = sstart + Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0)); + } + } else { + if (text_right_left > 0 ) { + prog_end = sstart - Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0)); + } else { + prog_end = sstart + Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0)); + } + } + overflow = true; + createLine(sstart, prog_end, downline, true, overflow, false, false); + } + //LINE + arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str()); + if (line_group_05) { + arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str()); + } + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue()); + char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL)); + setlocale (LC_NUMERIC, "C"); + double width_line = atof(sp_repr_css_property(css,"stroke-width","-1")); + setlocale (LC_NUMERIC, oldlocale); + g_free (oldlocale); + if (width_line > -0.0001) { + arrow_gap = 8 * Inkscape::Util::Quantity::convert(width_line/ doc_scale, "mm", display_unit.c_str()); + } + if (flip_side) { + arrow_gap *= -1; + } + hstart = hstart - Point::polar(angle_cross, position); + createLine(start, hstart, g_strdup(Glib::ustring("infoline-on-start-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove); + hend = hend - Point::polar(angle_cross, position); + createLine(end, hend, g_strdup(Glib::ustring("infoline-on-end-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove); + if (!arrows_outside) { + hstart = hstart + Point::polar(angle, arrow_gap); + hend = hend - Point::polar(angle, arrow_gap ); + } + createLine(hstart, hend, g_strdup(Glib::ustring("infoline-").append(this->getRepr()->attribute("id")).c_str()), true, overflow, remove, true); + } +} + +void +LPEMeasureLine::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) +{ + processObjects(LPE_VISIBILITY); +} + +void +LPEMeasureLine::doOnRemove (SPLPEItem const* /*lpeitem*/) +{ + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { + processObjects(LPE_TO_OBJECTS); + items.clear(); + return; + } + processObjects(LPE_ERASE); +} + +Gtk::Widget *LPEMeasureLine::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(); + Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vbox_expander->set_border_width(0); + vbox_expander->set_spacing(2); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter *param = *it; + Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + Glib::ustring *tip = param->param_getTooltip(); + if (widg) { + if (param->param_key != "dimline_format" && + param->param_key != "helperlines_format" && + param->param_key != "arrows_format" && + param->param_key != "anotation_format") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show DIM CSS style override")))); + expander->add(*vbox_expander); + expander->set_expanded(expanded); + expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPEMeasureLine::onExpanderChanged) ); + vbox->pack_start(*expander, true, true, 2); + return dynamic_cast<Gtk::Widget *>(vbox); +} + +void +LPEMeasureLine::onExpanderChanged() +{ + expanded = expander->get_expanded(); + if(expanded) { + expander->set_label (Glib::ustring(_("Hide DIM CSS style override"))); + } else { + expander->set_label (Glib::ustring(_("Show DIM CSS style override"))); + } +} + +Geom::PathVector +LPEMeasureLine::doEffect_path(Geom::PathVector const &path_in) +{ + return path_in; +} + +}; //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-measure-line.h b/src/live_effects/lpe-measure-line.h new file mode 100644 index 000000000..b42f7cfd5 --- /dev/null +++ b/src/live_effects/lpe-measure-line.h @@ -0,0 +1,107 @@ +#ifndef INKSCAPE_LPE_MEASURE_LINE_H +#define INKSCAPE_LPE_MEASURE_LINE_H + +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" + +#include <gtkmm/expander.h> + +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/fontbutton.h" +#include "live_effects/parameter/text.h" +#include "live_effects/parameter/unit.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/originalpath.h" +#include <libnrtype/font-lister.h> +#include <2geom/angle.h> +#include <2geom/ray.h> +#include <2geom/point.h> + +namespace Inkscape { +namespace LivePathEffect { + +enum OrientationMethod { + OM_HORIZONTAL, + OM_VERTICAL, + OM_PARALLEL, + OM_END +}; + +class LPEMeasureLine : public Effect { +public: + LPEMeasureLine(LivePathEffectObject *lpeobject); + virtual ~LPEMeasureLine(); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove (SPLPEItem const* /*lpeitem*/); + virtual void doEffect (SPCurve * curve){}; //stop the chain + virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/); + virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in); + void createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows = false); + void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid); + void onExpanderChanged(); + void createArrowMarker(const char * mode); + virtual Gtk::Widget *newWidget(); +private: + UnitParam unit; + FontButtonParam fontbutton; + EnumParam<OrientationMethod> orientation; + ScalarParam curve_linked; + ScalarParam precision; + ScalarParam position; + ScalarParam text_top_bottom; + ScalarParam text_right_left; + ScalarParam helpline_distance; + ScalarParam helpline_overlap; + ScalarParam scale; + TextParam format; + TextParam id_origin; + BoolParam arrows_outside; + BoolParam flip_side; + BoolParam scale_sensitive; + BoolParam local_locale; + BoolParam line_group_05; + BoolParam rotate_anotation; + BoolParam hide_back; + TextParam dimline_format; + TextParam helperlines_format; + TextParam anotation_format; + TextParam arrows_format; + Glib::ustring display_unit; + bool expanded; + Gtk::Expander * expander; + double doc_scale; + double fontsize; + double anotation_width; + double arrow_gap; + Geom::Point start_stored; + Geom::Point end_stored; +/* Geom::Affine affine_over;*/ + LPEMeasureLine(const LPEMeasureLine &); + LPEMeasureLine &operator=(const LPEMeasureLine &); + +}; + +} //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-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 9f3070ff4..5d80d65fe 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -13,77 +13,73 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gtkmm.h> -#include <glibmm/i18n.h> +#include <gtkmm.h> +#include "live_effects/lpeobject.h" +#include "live_effects/lpeobject-reference.h" #include "live_effects/lpe-mirror_symmetry.h" -#include <sp-path.h> -#include <display/curve.h> -#include <svg/path-string.h> +#include "display/curve.h" +#include "svg/path-string.h" +#include "svg/svg.h" +#include "sp-defs.h" +#include "helper/geom.h" +#include "2geom/intersection-graph.h" +#include "2geom/path-intersection.h" +#include "2geom/affine.h" #include "helper/geom.h" -#include <2geom/path.h> -#include <2geom/path-intersection.h> -#include <2geom/transforms.h> -#include <2geom/affine.h> -#include "knot-holder-entity.h" -#include "knotholder.h" -#include "inkscape.h" +#include "sp-lpe-item.h" +#include "path-chemistry.h" +#include "style.h" +#include "xml/sp-css-attr.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { static const Util::EnumData<ModeType> ModeTypeData[MT_END] = { - { MT_V, N_("Vertical Page Center"), "Vertical Page Center, use select tool to move item instead line" }, - { MT_H, N_("Horizontal Page Center"), "Horizontal Page Center, use select tool to move item instead line" }, - { MT_FREE, N_("Free from reflection line"), "Free from path" }, - { MT_X, N_("X from middle knot"), "X from middle knot" }, - { MT_Y, N_("Y from middle knot"), "Y from middle knot" } + { MT_V, N_("Vertical Page Center"), "vertical" }, + { MT_H, N_("Horizontal Page Center"), "horizontal" }, + { MT_FREE, N_("Free from reflection line"), "free" }, + { MT_X, N_("X from middle knot"), "X" }, + { MT_Y, N_("Y from middle knot"), "Y" } }; static const Util::EnumDataConverter<ModeType> MTConverter(ModeTypeData, MT_END); -namespace MS { - -class KnotHolderEntityCenterMirrorSymmetry : public LPEKnotHolderEntity { -public: - KnotHolderEntityCenterMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - -class KnotHolderEntityStartMirrorSymmetry : public LPEKnotHolderEntity { -public: - KnotHolderEntityStartMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - -class KnotHolderEntityEndMirrorSymmetry : public LPEKnotHolderEntity { -public: - KnotHolderEntityEndMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - -} // namespace MS - LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) : Effect(lpeobject), mode(_("Mode"), _("Symmetry move mode"), "mode", MTConverter, &wr, this, MT_FREE), - discard_orig_path(_("Discard original path?"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false), + split_gap(_("Gap on split"), _("Gap on split"), "split_gap", &wr, this, -0.001), + discard_orig_path(_("Discard original path"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false), fuse_paths(_("Fuse paths"), _("Fuse original and the reflection into a single path"), "fuse_paths", &wr, this, false), oposite_fuse(_("Opposite fuse"), _("Picks the other side of the mirror as the original"), "oposite_fuse", &wr, this, false), - start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, "Adjust the start of mirroring"), - end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, "Adjust end of mirroring") + split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false), + start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, _("Adjust start of mirroring")), + end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, _("Adjust end of mirroring")), + center_point(_("Center mirror line"), _("Center mirror line"), "center_point", &wr, this, _("Adjust center of mirroring")), + id_origin("id origin", "store the id of the first LPEItem", "id_origin", &wr, this,"") { show_orig_path = true; registerParameter(&mode); - registerParameter( &discard_orig_path); - registerParameter( &fuse_paths); - registerParameter( &oposite_fuse); - registerParameter( &start_point); - registerParameter( &end_point); + registerParameter(&split_gap); + registerParameter(&discard_orig_path); + registerParameter(&fuse_paths); + registerParameter(&oposite_fuse); + registerParameter(&split_items); + registerParameter(&start_point); + registerParameter(&end_point); + registerParameter(¢er_point); + registerParameter(&id_origin); + id_origin.param_hide_canvas_text(); + split_gap.param_set_range(-999999.0, 999999.0); + split_gap.param_set_increments(0.1, 0.1); + split_gap.param_set_digits(5); apply_to_clippath_and_mask = true; + previous_center = Geom::Point(0,0); + id_origin.param_widget_is_visible(false); + center_point.param_widget_is_visible(false); } LPEMirrorSymmetry::~LPEMirrorSymmetry() @@ -91,14 +87,39 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry() } void +LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem) +{ + is_load = false; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + if (split_items && !discard_orig_path) { + container = dynamic_cast<SPObject *>(sp_lpe_item->parent); + Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot(); + Inkscape::XML::Node *root_origin = document->getReprRoot(); + if (root_origin != root) { + return; + } + Geom::Line ls((Geom::Point)start_point, (Geom::Point)end_point); + Geom::Affine m = Geom::reflection (ls.vector(), (Geom::Point)start_point); + m = m * sp_lpe_item->transform; + toMirror(m); + } else { + processObjects(LPE_ERASE); + items.clear(); + } +} +void LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) { - using namespace Geom; + using namespace Geom; + original_bbox(lpeitem); + //center_point->param_set_liveupdate(false); Point point_a(boundingbox_X.max(), boundingbox_Y.min()); Point point_b(boundingbox_X.max(), boundingbox_Y.max()); - Point point_c(boundingbox_X.max(), boundingbox_Y.middle()); if (mode == MT_Y) { point_a = Geom::Point(boundingbox_X.min(),center_point[Y]); point_b = Geom::Point(boundingbox_X.max(),center_point[Y]); @@ -107,52 +128,216 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) point_a = Geom::Point(center_point[X],boundingbox_Y.min()); point_b = Geom::Point(center_point[X],boundingbox_Y.max()); } - line_separation.setPoints(point_a, point_b); - if ( mode == MT_X || mode == MT_Y ) { + if ((Geom::Point)start_point == (Geom::Point)end_point) { start_point.param_setValue(point_a); end_point.param_setValue(point_b); - center_point = Geom::middle_point(point_a, point_b); + previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); + center_point.param_setValue(previous_center); + return; + } + if ( mode == MT_X || mode == MT_Y ) { + if (!are_near(previous_center, (Geom::Point)center_point, 0.01)) { + center_point.param_setValue(Geom::middle_point(point_a, point_b), true); + end_point.param_setValue(point_b); + start_point.param_setValue(point_a); + } else { + if ( mode == MT_X ) { + if (!are_near(start_point[X], point_a[X], 0.01)) { + start_point.param_setValue(point_a); + } + if (!are_near(end_point[X], point_b[X], 0.01)) { + end_point.param_setValue(point_b); + } + } else { //MT_Y + if (!are_near(start_point[Y], point_a[Y], 0.01)) { + start_point.param_setValue(point_a); + } + if (!are_near(end_point[Y], point_b[Y], 0.01)) { + end_point.param_setValue(point_b); + } + } + } } else if ( mode == MT_FREE) { - if(!are_near(previous_center,center_point, 0.01)) { - Geom::Point trans = center_point - previous_center; + if (are_near(previous_center, (Geom::Point)center_point, 0.01)) { + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); + } else { + Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); start_point.param_setValue(start_point * trans); end_point.param_setValue(end_point * trans); - line_separation.setPoints(start_point, end_point); - } else { - center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); - line_separation.setPoints(start_point, end_point); } } else if ( mode == MT_V){ - if(SP_ACTIVE_DESKTOP){ - SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument(); - Geom::Rect view_box_rect = doc->getViewBox(); - Geom::Point sp = Geom::Point(view_box_rect.width()/2.0, 0); - sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (document) { + Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse(); + Geom::Point sp = Geom::Point(document->getWidth().value("px")/2.0, 0) * transform; start_point.param_setValue(sp); - Geom::Point ep = Geom::Point(view_box_rect.width()/2.0, view_box_rect.height()); - ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + Geom::Point ep = Geom::Point(document->getWidth().value("px")/2.0, document->getHeight().value("px")) * transform; end_point.param_setValue(ep); - center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); - line_separation.setPoints(start_point, end_point); + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } } else { //horizontal page - if(SP_ACTIVE_DESKTOP){ - SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument(); - Geom::Rect view_box_rect = doc->getViewBox(); - Geom::Point sp = Geom::Point(0, view_box_rect.height()/2.0); - sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (document) { + Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse(); + Geom::Point sp = Geom::Point(0, document->getHeight().value("px")/2.0) * transform; start_point.param_setValue(sp); - Geom::Point ep = Geom::Point(view_box_rect.width(), view_box_rect.height()/2.0); - ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + Geom::Point ep = Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")/2.0) * transform; end_point.param_setValue(ep); - center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); - line_separation.setPoints(start_point, end_point); + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } } previous_center = center_point; } void +LPEMirrorSymmetry::cloneD(SPObject *orig, SPObject *dest, bool live, bool root) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) { + std::vector< SPObject * > childs = orig->childList(true); + size_t index = 0; + for (std::vector<SPObject * >::iterator obj_it = childs.begin(); + obj_it != childs.end(); ++obj_it) { + SPObject *dest_child = dest->nthChild(index); + cloneD(*obj_it, dest_child, live, false); + index++; + } + } + SPShape * shape = SP_SHAPE(orig); + SPPath * path = SP_PATH(dest); + if (shape && !path) { + Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); + dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); + path = SP_PATH(dest); + } + if (path && shape) { + if ( live) { + SPCurve *c = NULL; + if (root) { + c = new SPCurve(); + c->set_pathvector(pathvector_after_effect); + } else { + c = shape->getCurve(); + } + if (c) { + path->setCurve(c, TRUE); + c->unref(); + } else { + dest->getRepr()->setAttribute("d", NULL); + } + } else { + dest->getRepr()->setAttribute("d", orig->getRepr()->attribute("d")); + } + } +} + +void +LPEMirrorSymmetry::toMirror(Geom::Affine transform) +{ + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (document) { + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + const char * id_origin_char = id_origin.param_getSVGValue(); + const char * elemref_id = g_strdup(Glib::ustring("mirror-").append(id_origin_char).c_str()); + items.clear(); + items.push_back(elemref_id); + SPObject *elemref= NULL; + Inkscape::XML::Node *phantom = NULL; + if ((elemref = document->getObjectById(elemref_id))) { + phantom = elemref->getRepr(); + } else { + phantom = sp_lpe_item->getRepr()->duplicate(xml_doc); + std::vector<const char *> attrs; + attrs.push_back("inkscape:path-effect"); + attrs.push_back("inkscape:original-d"); + attrs.push_back("sodipodi:type"); + attrs.push_back("sodipodi:rx"); + attrs.push_back("sodipodi:ry"); + attrs.push_back("sodipodi:cx"); + attrs.push_back("sodipodi:cy"); + attrs.push_back("sodipodi:end"); + attrs.push_back("sodipodi:start"); + attrs.push_back("inkscape:flatsided"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:rounded"); + attrs.push_back("sodipodi:arg1"); + attrs.push_back("sodipodi:arg2"); + attrs.push_back("sodipodi:r1"); + attrs.push_back("sodipodi:r2"); + attrs.push_back("sodipodi:sides"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("sodipodi:argument"); + attrs.push_back("sodipodi:expansion"); + attrs.push_back("sodipodi:radius"); + attrs.push_back("sodipodi:revolution"); + attrs.push_back("sodipodi:t0"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("inkscape:randomized"); + attrs.push_back("x"); + attrs.push_back("y"); + attrs.push_back("rx"); + attrs.push_back("ry"); + attrs.push_back("width"); + attrs.push_back("height"); + for(const char * attr : attrs) { + phantom->setAttribute(attr, NULL); + } + } + phantom->setAttribute("id", elemref_id); + if (!elemref) { + elemref = container->appendChildRepr(phantom); + Inkscape::GC::release(phantom); + } + cloneD(SP_OBJECT(sp_lpe_item), elemref, true, true); + gchar *str = sp_svg_transform_write(transform); + elemref->getRepr()->setAttribute("transform" , str); + g_free(str); + if (elemref->parent != container) { + Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); + copy->setAttribute("id", elemref_id); + container->appendChildRepr(copy); + Inkscape::GC::release(copy); + elemref->deleteObject(); + } + } +} + +//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication +void +LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) +{ + processObjects(LPE_VISIBILITY); +} + +void +LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/) +{ + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { + processObjects(LPE_TO_OBJECTS); + items.clear(); + return; + } + processObjects(LPE_ERASE); +} + +void +LPEMirrorSymmetry::transform_multiply(Geom::Affine const& postmul, bool set) +{ + // cycle through all parameters. Most parameters will not need transformation, but path and point params do. + for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { + Parameter * param = *it; + param->param_transform_multiply(postmul, set); + } + previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); +} + +void LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) { using namespace Geom; @@ -166,14 +351,22 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) start_point.param_update_default(point_a); end_point.param_setValue(point_b); end_point.param_update_default(point_b); - center_point = point_c; + center_point.param_setValue(point_c); previous_center = center_point; + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); + if (!lpeitem->hasPathEffectOfType(this->effectType(), false) ){ //first applied not ready yet + id_origin.param_setValue(lpeitem->getRepr()->attribute("id")); + id_origin.write_to_SVG(); + } } Geom::PathVector LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) { + if (split_items && !fuse_paths) { + return path_in; + } Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); Geom::PathVector path_out; @@ -181,30 +374,53 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) path_out = pathv_to_linear_and_cubic_beziers(path_in); } - Geom::Point point_a(line_separation.initialPoint()); - Geom::Point point_b(line_separation.finalPoint()); - - Geom::Translate m1(point_a[0], point_a[1]); - double hyp = Geom::distance(point_a, point_b); - double c = (point_b[0] - point_a[0]) / hyp; // cos(alpha) - double s = (point_b[1] - point_a[1]) / hyp; // sin(alpha) - - Geom::Affine m2(c, -s, s, c, 0.0, 0.0); - Geom::Scale sca(1.0, -1.0); - - Geom::Affine m = m1.inverse() * m2; - m = m * sca; - m = m * m2.inverse(); - m = m * m1; - - if (fuse_paths && !discard_orig_path) { + Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point); + Geom::Affine m = Geom::reflection (line_separation.vector(), (Geom::Point)start_point); + if (split_items && fuse_paths) { + Geom::OptRect bbox = sp_lpe_item->geometricBounds(); + Geom::Path p(Geom::Point(bbox->left(), bbox->top())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top())); + p.close(); + p *= Geom::Translate(bbox->midpoint()).inverse(); + p *= Geom::Scale(1.2); + p *= Geom::Rotate(line_separation.angle()); + p *= Geom::Translate(bbox->midpoint()); + bbox = p.boundsFast(); + p.clear(); + p.start(Geom::Point(bbox->left(), bbox->top())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom())); + p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top())); + p.close(); + p *= Geom::Translate(bbox->midpoint()).inverse(); + p *= Geom::Rotate(line_separation.angle()); + p *= Geom::Translate(bbox->midpoint()); + Geom::Point base(p.pointAt(3)); + if (oposite_fuse) { + base = p.pointAt(0); + } + p *= Geom::Translate(line_separation.pointAt(line_separation.nearestTime(base)) - base); + Geom::PathVector pv_bbox; + pv_bbox.push_back(p); + Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(pv_bbox, original_pathv); + if (pig && !original_pathv.empty() && !pv_bbox.empty()) { + path_out = pig->getBminusA(); + } + Geom::Point dir = rot90(unit_vector((Geom::Point)end_point - (Geom::Point)start_point)); + Geom::Point gap = dir * split_gap; + path_out *= Geom::Translate(gap); + } else if (fuse_paths && !discard_orig_path) { for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) { continue; } - Geom::PathVector tmp_path; + Geom::PathVector tmp_pathvector; double time_start = 0.0; int position = 0; bool end_open = false; @@ -250,11 +466,11 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) Geom::Path mirror = portion.reversed() * m; mirror.setInitial(portion.finalPoint()); portion.append(mirror); - if(i!=0) { + if(i != 0) { portion.setFinal(portion.initialPoint()); portion.close(); } - tmp_path.push_back(portion); + tmp_pathvector.push_back(portion); } portion.clear(); } @@ -275,36 +491,33 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) portion.append(mirror); portion = portion.reversed(); if (!original.closed()) { - tmp_path.push_back(portion); + tmp_pathvector.push_back(portion); } else { - if (cs.size() > 1 && tmp_path.size() > 0 && tmp_path[0].size() > 0 ) { - portion.setFinal(tmp_path[0].initialPoint()); - portion.setInitial(tmp_path[0].finalPoint()); - tmp_path[0].append(portion); + if (cs.size() > 1 && tmp_pathvector.size() > 0 && tmp_pathvector[0].size() > 0 ) { + portion.setFinal(tmp_pathvector[0].initialPoint()); + portion.setInitial(tmp_pathvector[0].finalPoint()); + tmp_pathvector[0].append(portion); } else { - tmp_path.push_back(portion); + tmp_pathvector.push_back(portion); } - tmp_path[0].close(); + tmp_pathvector[0].close(); } portion.clear(); } } } if (cs.size() == 0 && position == 1) { - tmp_path.push_back(original); - tmp_path.push_back(original * m); + tmp_pathvector.push_back(original); + tmp_pathvector.push_back(original * m); } - path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); - tmp_path.clear(); + path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end()); + tmp_pathvector.clear(); } - } - - if (!fuse_paths || discard_orig_path) { - for (int i = 0; i < static_cast<int>(path_in.size()); ++i) { - path_out.push_back(path_in[i] * m); + } else if (!fuse_paths || discard_orig_path) { + for (size_t i = 0; i < original_pathv.size(); ++i) { + path_out.push_back(original_pathv[i] * m); } } - return path_out; } @@ -323,44 +536,6 @@ LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector hp_vec.push_back(helper); } -void -LPEMirrorSymmetry::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) -{ - SPKnotShapeType knot_shape = SP_KNOT_SHAPE_CIRCLE; - SPKnotModeType knot_mode = SP_KNOT_MODE_XOR; - guint32 knot_color = 0x0000ff00; - { - KnotHolderEntity *c = new MS::KnotHolderEntityCenterMirrorSymmetry(this); - c->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the center"), knot_shape, knot_mode, knot_color ); - knotholder->add(c); - } -}; - -namespace MS { - -using namespace Geom; - -void -KnotHolderEntityCenterMirrorSymmetry::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) -{ - LPEMirrorSymmetry* lpe = dynamic_cast<LPEMirrorSymmetry *>(_effect); - Geom::Point const s = snap_knot_position(p, state); - lpe->center_point = s; - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); -} - -Geom::Point -KnotHolderEntityCenterMirrorSymmetry::knot_get() const -{ - LPEMirrorSymmetry const *lpe = dynamic_cast<LPEMirrorSymmetry const*>(_effect); - return lpe->center_point; -} - -} // namespace CR - } //namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index 3a244cb7e..e98c83f2b 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -18,19 +18,14 @@ #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/text.h" #include "live_effects/parameter/point.h" -#include "live_effects/parameter/path.h" #include "live_effects/parameter/enum.h" #include "live_effects/lpegroupbbox.h" namespace Inkscape { namespace LivePathEffect { -namespace MS { -// we need a separate namespace to avoid clashes with LPEPerpBisector -class KnotHolderEntityCenterMirrorSymmetry; -} - enum ModeType { MT_V, MT_H, @@ -46,25 +41,31 @@ public: virtual ~LPEMirrorSymmetry(); virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void doAfterEffect (SPLPEItem const* lpeitem); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); - /* the knotholder entity classes must be declared friends */ - friend class MS::KnotHolderEntityCenterMirrorSymmetry; - void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + virtual void doOnRemove (SPLPEItem const* /*lpeitem*/); + virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/); + void toMirror(Geom::Affine transform); + // void cloneAttrbutes(Inkscape::XML::Node * origin, Inkscape::XML::Node * dest, const char * first_attribute, ...); + void cloneD(SPObject *orig, SPObject *dest, bool live, bool root); protected: virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); private: EnumParam<ModeType> mode; + ScalarParam split_gap; BoolParam discard_orig_path; BoolParam fuse_paths; BoolParam oposite_fuse; + BoolParam split_items; PointParam start_point; PointParam end_point; - Geom::Line line_separation; + PointParam center_point; + TextParam id_origin; Geom::Point previous_center; - Geom::Point center_point; - + SPObject * container; LPEMirrorSymmetry(const LPEMirrorSymmetry&); LPEMirrorSymmetry& operator=(const LPEMirrorSymmetry&); }; diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index d611b88a1..a5d1d23c8 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -11,17 +11,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-offset.h" #include "sp-shape.h" #include "display/curve.h" - -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis-geometric.h> #include <2geom/elliptical-arc.h> -#include <2geom/transforms.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -32,7 +27,7 @@ LPEOffset::LPEOffset(LivePathEffectObject *lpeobject) : { show_orig_path = true; apply_to_clippath_and_mask = true; - registerParameter(dynamic_cast<Parameter *>(&offset_pt)); + registerParameter(&offset_pt); } LPEOffset::~LPEOffset() @@ -44,7 +39,7 @@ LPEOffset::doOnApply(SPLPEItem const* lpeitem) { Geom::Point offset = *(SP_SHAPE(lpeitem)->_curve->first_point()); offset_pt.param_update_default(offset); - offset_pt.param_setValue(offset,true); + offset_pt.param_setValue(offset); } static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp index 23cd5e2e7..271442c7d 100644 --- a/src/live_effects/lpe-parallel.cpp +++ b/src/live_effects/lpe-parallel.cpp @@ -11,18 +11,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-parallel.h" #include "sp-shape.h" #include "display/curve.h" -#include <2geom/path.h> -#include <2geom/transforms.h> - -#include "knot-holder-entity.h" #include "knotholder.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -54,9 +51,9 @@ LPEParallel::LPEParallel(LivePathEffectObject *lpeobject) : show_orig_path = true; _provides_knotholder_entities = true; - registerParameter(dynamic_cast<Parameter *>(&offset_pt)); - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&offset_pt); + registerParameter(&length_left); + registerParameter(&length_right); } LPEParallel::~LPEParallel() diff --git a/src/live_effects/lpe-path_length.cpp b/src/live_effects/lpe-path_length.cpp index 4ca380c15..61818a73b 100644 --- a/src/live_effects/lpe-path_length.cpp +++ b/src/live_effects/lpe-path_length.cpp @@ -11,12 +11,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-path_length.h" #include "util/units.h" - -#include "2geom/sbasis-geometric.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -28,10 +26,10 @@ LPEPathLength::LPEPathLength(LivePathEffectObject *lpeobject) : unit(_("Unit:"), _("Unit"), "unit", &wr, this), display_unit(_("Display unit"), _("Print unit after path length"), "display_unit", &wr, this, true) { - registerParameter(dynamic_cast<Parameter *>(&scale)); - registerParameter(dynamic_cast<Parameter *>(&info_text)); - registerParameter(dynamic_cast<Parameter *>(&unit)); - registerParameter(dynamic_cast<Parameter *>(&display_unit)); + registerParameter(&scale); + registerParameter(&info_text); + registerParameter(&unit); + registerParameter(&display_unit); } LPEPathLength::~LPEPathLength() @@ -39,12 +37,6 @@ LPEPathLength::~LPEPathLength() } -void -LPEPathLength::hideCanvasText() { - // this is only used in sp-lpe-item.cpp to hide the canvas text when the effect is invisible - info_text.param_setValue(""); -} - Geom::Piecewise<Geom::D2<Geom::SBasis> > LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { @@ -71,7 +63,9 @@ LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p //g_print ("Area is zero\n"); } //g_print ("Area: %f\n", area); - + if (!this->isVisible()) { + info_text.param_setValue(""); + } return pwd2_in; } diff --git a/src/live_effects/lpe-path_length.h b/src/live_effects/lpe-path_length.h index e108e770a..14d093c09 100644 --- a/src/live_effects/lpe-path_length.h +++ b/src/live_effects/lpe-path_length.h @@ -29,8 +29,6 @@ public: virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - void hideCanvasText(); - private: LPEPathLength(const LPEPathLength&); LPEPathLength& operator=(const LPEPathLength&); diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index 911c410f9..b026bbc22 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -6,22 +6,16 @@ #include "live_effects/lpe-patternalongpath.h" #include "live_effects/lpeobject.h" -#include "sp-shape.h" #include "display/curve.h" -#include "svg/svg.h" -#include "ui/widget/scalar.h" -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> -#include "knot-holder-entity.h" #include "knotholder.h" - +#include <cmath> #include <algorithm> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + using std::vector; @@ -70,7 +64,7 @@ static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTy LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : Effect(lpeobject), pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"), - original_height(0), + original_height(0.0), prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1.0), copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED), @@ -91,16 +85,16 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : fuse_tolerance(_("_Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), "fuse_tolerance", &wr, this, 0) { - registerParameter( dynamic_cast<Parameter *>(&pattern) ); - registerParameter( dynamic_cast<Parameter *>(©type) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); - registerParameter( dynamic_cast<Parameter *>(&spacing) ); - registerParameter( dynamic_cast<Parameter *>(&normal_offset) ); - registerParameter( dynamic_cast<Parameter *>(&tang_offset) ); - registerParameter( dynamic_cast<Parameter *>(&prop_units) ); - registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) ); - registerParameter( dynamic_cast<Parameter *>(&fuse_tolerance) ); + registerParameter(&pattern); + registerParameter(©type); + registerParameter(&prop_scale); + registerParameter(&scale_y_rel); + registerParameter(&spacing); + registerParameter(&normal_offset); + registerParameter(&tang_offset); + registerParameter(&prop_units); + registerParameter(&vertical_pattern); + registerParameter(&fuse_tolerance); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); @@ -151,15 +145,15 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con double xspace = spacing; double noffset = normal_offset; double toffset = tang_offset; - if (prop_units.get_value() && pattBndsY){ + if (prop_units.get_value()){ xspace *= pattBndsX->extent(); noffset *= pattBndsY->extent(); toffset *= pattBndsX->extent(); } //Prevent more than 90% overlap... - if (xspace < -pattBndsX->extent()*.9) { - xspace = -pattBndsX->extent()*.9; + if (xspace < -pattBndsX->extent() * 0.9) { + xspace = -pattBndsX->extent() * 0.9; } //TODO: dynamical update of parameter ranges? //if (prop_units.get_value()){ @@ -168,7 +162,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con // spacing.param_set_range(-pattBndsX.extent()*.9, Geom::infinity()); // } - y0+=noffset; + y0 += noffset; std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in; paths_in = split_at_discontinuities(pwd2_in); @@ -177,11 +171,14 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx]; Piecewise<SBasis> x = x0; Piecewise<SBasis> y = y0; - Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1); - uskeleton = remove_short_cuts(uskeleton,.01); + Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2, 0.1); + uskeleton = remove_short_cuts(uskeleton, 0.01); Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton)); - n = force_continuity(remove_short_cuts(n,.1)); - + if (Geom::are_near(pwd2_in[0].at0(),pwd2_in[pwd2_in.size()-1].at1(), 0.01)) { + n = force_continuity(remove_short_cuts(n, 0.1), 0.01); + } else { + n = force_continuity(remove_short_cuts(n, 0.1)); + } int nbCopies = 0; double scaling = 1; switch(type) { @@ -201,13 +198,13 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con case PAPCT_REPEATED_STRETCHED: // if uskeleton is closed: - if(path_i.segs.front().at0() == path_i.segs.back().at1()){ - nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace))); + if (are_near(path_i.segs.front().at0(), path_i.segs.back().at1())){ + nbCopies = std::max(1, static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace)))); pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace); scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent()); // if not closed: no space at the end }else{ - nbCopies = static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace))); + nbCopies = std::max(1, static_cast<int>(std::floor((uskeleton.domain().extent() - toffset + xspace)/(pattBndsX->extent()+xspace)))); pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace); scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent() - xspace); } @@ -217,18 +214,18 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con return pwd2_in; }; + //Ceil to 6 decimals + scaling = ceil(scaling * 1000000) / 1000000; double pattWidth = pattBndsX->extent() * scaling; - if (scaling != 1.0) { - x*=scaling; - } + x *= scaling; if ( scale_y_rel.get_value() ) { - y*=(scaling*prop_scale); + y *= prop_scale * scaling; } else { - if (prop_scale != 1.0) y *= prop_scale; + y *= prop_scale; } x += toffset; - + double offs = 0; for (int i=0; i<nbCopies; i++){ if (fuse_tolerance > 0){ @@ -241,7 +238,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con offs+=pattWidth; } } - if (fuse_tolerance > 0){ + if (fuse_tolerance > 0){ pre_output = fuse_nearby_ends(pre_output, fuse_tolerance); for (unsigned i=0; i<pre_output.size(); i++){ output.concat(pre_output[i]); @@ -264,11 +261,12 @@ LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set) bool transform_stroke = prefs ? prefs->getBool("/options/transform/stroke", true) : true; if (transform_stroke && !scale_y_rel) { prop_scale.param_set_value(prop_scale * ((postmul.expansionX() + postmul.expansionY()) / 2)); - } + prop_scale.write_to_SVG(); + } if (postmul.isTranslation()) { pattern.param_transform_multiply(postmul, set); + pattern.write_to_SVG(); } - sp_lpe_item_update_patheffect (sp_lpe_item, false, true); } void @@ -279,10 +277,10 @@ LPEPatternAlongPath::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vect void -LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { KnotHolderEntity *e = new WPAP::KnotHolderEntityWidthPatternAlongPath(this); - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE); + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE); knotholder->add(e); } diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h index 3d7fc02bc..c34a9a15d 100644 --- a/src/live_effects/lpe-patternalongpath.h +++ b/src/live_effects/lpe-patternalongpath.h @@ -43,7 +43,7 @@ public: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); - virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item); PathParam pattern; diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp index 660318c57..dab169cfe 100644 --- a/src/live_effects/lpe-perp_bisector.cpp +++ b/src/live_effects/lpe-perp_bisector.cpp @@ -11,19 +11,16 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <glibmm/i18n.h> - #include "live_effects/lpe-perp_bisector.h" #include "display/curve.h" #include "sp-path.h" #include "line-geometry.h" -#include "sp-lpe-item.h" -#include <2geom/path.h> -#include "knot-holder-entity.h" #include "knotholder.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { namespace PB { @@ -102,8 +99,8 @@ LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) : _provides_knotholder_entities = true; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&length_left); + registerParameter(&length_right); } LPEPerpBisector::~LPEPerpBisector() diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index ae951dfc9..3cff83fed 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -18,9 +18,11 @@ #include "live_effects/lpe-perspective-envelope.h" #include "helper/geom.h" #include "display/curve.h" -#include "svg/svg.h" #include <gsl/gsl_linalg.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + using namespace Geom; namespace Inkscape { @@ -32,8 +34,8 @@ enum DeformationType { }; static const Util::EnumData<unsigned> DeformationTypeData[] = { - {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"}, - {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"} + {DEFORMATION_PERSPECTIVE , N_("Perspective"), "perspective"}, + {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "envelope_deformation"} }; static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData)); @@ -108,15 +110,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) int position_c = Geom::sgn(Geom::cross(handles[2] - handles[3], handles[0] - handles[3])); if (position_a != 1 && move0) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[0])); - down_left_point.param_setValue(point_a, true); + down_left_point.param_setValue(point_a); } if (position_b == 1 && move0) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[0])); - down_left_point.param_setValue(point_b, true); + down_left_point.param_setValue(point_b); } if (position_c == 1 && move0) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[0])); - down_left_point.param_setValue(point_c, true); + down_left_point.param_setValue(point_c); } line_a.setPoints(handles[0],handles[2]); line_b.setPoints(handles[2],handles[3]); @@ -126,15 +128,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[3] - handles[0], handles[1] - handles[0])); if (position_a != 1 && move1) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[1])); - up_left_point.param_setValue(point_a, true); + up_left_point.param_setValue(point_a); } if (position_b == 1 && move1) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[1])); - up_left_point.param_setValue(point_b, true); + up_left_point.param_setValue(point_b); } if (position_c == 1 && move1) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[1])); - up_left_point.param_setValue(point_c, true); + up_left_point.param_setValue(point_c); } line_a.setPoints(handles[1],handles[3]); line_b.setPoints(handles[3],handles[0]); @@ -144,15 +146,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[0] - handles[1], handles[2] - handles[1])); if (position_a != 1 && move2) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[2])); - up_right_point.param_setValue(point_a, true); + up_right_point.param_setValue(point_a); } if (position_b == 1 && move2) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[2])); - up_right_point.param_setValue(point_b, true); + up_right_point.param_setValue(point_b); } if (position_c == 1 && move2) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[2])); - up_right_point.param_setValue(point_c, true); + up_right_point.param_setValue(point_c); } line_a.setPoints(handles[2],handles[0]); line_b.setPoints(handles[0],handles[1]); @@ -162,15 +164,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[1] - handles[2], handles[3] - handles[2])); if (position_a != 1 && move3) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[3])); - down_right_point.param_setValue(point_a, true); + down_right_point.param_setValue(point_a); } if (position_b == 1 && move3) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[3])); - down_right_point.param_setValue(point_b, true); + down_right_point.param_setValue(point_b); } if (position_c == 1 && move3) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[3])); - down_right_point.param_setValue(point_c, true); + down_right_point.param_setValue(point_c); } } else { handles.resize(4); @@ -367,17 +369,17 @@ LPEPerspectiveEnvelope::newWidget() Gtk::Label* handles = Gtk::manage(new Gtk::Label(Glib::ustring(_("Handles:")),Gtk::ALIGN_START)); vbox->pack_start(*handles, false, false, 2); hbox_up_handles->pack_start(*widg, true, true, 2); - hbox_up_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); + hbox_up_handles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET); } else if(param->param_key == "up_right_point") { hbox_up_handles->pack_start(*widg, true, true, 2); } else if(param->param_key == "down_left_point") { hbox_down_handles->pack_start(*widg, true, true, 2); - hbox_down_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); + hbox_down_handles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET); } else { hbox_down_handles->pack_start(*widg, true, true, 2); } if (tip) { - widg->set_tooltip_text(*tip); + widg->set_tooltip_markup(*tip); } else { widg->set_tooltip_text(""); widg->set_has_tooltip(false); @@ -401,12 +403,13 @@ LPEPerspectiveEnvelope::newWidget() } vbox->pack_start(*hbox_up_handles,true, true, 2); Gtk::HBox * hbox_middle = Gtk::manage(new Gtk::HBox(true,2)); - hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); - hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); + hbox_middle->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); + hbox_middle->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); vbox->pack_start(*hbox_middle, false, true, 2); vbox->pack_start(*hbox_down_handles, true, true, 2); Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); - Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR)); + Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(_("_Clear"), true)); + reset_button->set_image_from_icon_name("edit-clear"); reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid)); reset_button->set_size_request(140,30); vbox->pack_start(*hbox, true,true,2); @@ -431,8 +434,8 @@ LPEPerspectiveEnvelope::vertical(PointParam ¶m_one, PointParam ¶m_two, G } A[Geom::X] = nearest[Geom::X] - distance_middle; B[Geom::X] = nearest[Geom::X] + distance_middle; - param_one.param_setValue(A, true); - param_two.param_setValue(B, true); + param_one.param_setValue(A); + param_two.param_setValue(B); } void @@ -452,8 +455,8 @@ LPEPerspectiveEnvelope::horizontal(PointParam ¶m_one, PointParam ¶m_two, } A[Geom::Y] = nearest[Geom::Y] - distance_middle; B[Geom::Y] = nearest[Geom::Y] + distance_middle; - param_one.param_setValue(A, true); - param_two.param_setValue(B, true); + param_one.param_setValue(A); + param_two.param_setValue(B); } void @@ -538,4 +541,4 @@ LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v fill-column:99 End: */ -// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index c8cdd7912..435c91c2d 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -11,22 +11,17 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ #include <gtkmm.h> -#include <glibmm/i18n.h> - #include "persp3d.h" //#include "transf_mat_3x4.h" -#include "document.h" #include "document-private.h" #include "live_effects/lpe-perspective_path.h" #include "live_effects/lpeobject.h" -#include "sp-item-group.h" #include "knot-holder-entity.h" #include "knotholder.h" -#include "desktop.h" #include <util/units.h> -#include "inkscape.h" -#include <2geom/path.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -56,11 +51,11 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : uses_plane_xy(_("Uses XY plane?"), _("If true, put the path on the left side of an imaginary box, otherwise on the right side"), "uses_plane_xy", &wr, this, true) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&scalex) ); - registerParameter( dynamic_cast<Parameter *>(&scaley) ); - registerParameter( dynamic_cast<Parameter *>(&offsetx) ); - registerParameter( dynamic_cast<Parameter *>(&offsety) ); - registerParameter( dynamic_cast<Parameter *>(&uses_plane_xy) ); + registerParameter( &scalex); + registerParameter( &scaley); + registerParameter( &offsetx); + registerParameter( &offsety); + registerParameter( &uses_plane_xy); concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; @@ -107,12 +102,12 @@ void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { perspectiveID = perspective->get_text(); Persp3D *first = 0; Persp3D *persp = 0; - for ( SPObject *child = this->lpeobj->document->getDefs()->firstChild(); child && !persp; child = child->getNext() ) { - if (SP_IS_PERSP3D(child) && first == 0) { - first = SP_PERSP3D(child); + for (auto& child: lpeobj->document->getDefs()->children) { + if (SP_IS_PERSP3D(&child) && first == 0) { + first = SP_PERSP3D(&child); } - if (SP_IS_PERSP3D(child) && strcmp(child->getId(), const_cast<const gchar *>(perspectiveID.c_str())) == 0) { - persp = SP_PERSP3D(child); + if (SP_IS_PERSP3D(&child) && strcmp(child.getId(), const_cast<const gchar *>(perspectiveID.c_str())) == 0) { + persp = SP_PERSP3D(&child); break; } } @@ -231,15 +226,28 @@ LPEPerspectivePath::newWidget() ++it; } Gtk::HBox * perspectiveId = Gtk::manage(new Gtk::HBox(true,0)); + +#if WITH_GTKMM_3_10 + Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", Gtk::ALIGN_START, Gtk::ALIGN_START)); +#else Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", 0., 0.)); +#endif + Gtk::Entry* perspective = Gtk::manage(new Gtk::Entry()); perspective->set_text(perspectiveID); perspective->set_tooltip_text("Set the perspective ID to apply"); perspectiveId->pack_start(*labelPerspective, true, true, 2); perspectiveId->pack_start(*perspective, true, true, 2); vbox->pack_start(*perspectiveId, true, true, 2); - Gtk::Button* apply3D = Gtk::manage(new Gtk::Button(Glib::ustring(_("Refresh perspective")))); - apply3D->set_alignment(0.0, 0.5); + Gtk::Button* apply3D = Gtk::manage(new Gtk::Button()); + +#if WITH_GTKMM_3_10 + Gtk::Label *apply3DLabel = Gtk::manage(new Gtk::Label(_("Refresh perspective"), Gtk::ALIGN_START, Gtk::ALIGN_CENTER)); +#else + Gtk::Label *apply3DLabel = Gtk::manage(new Gtk::Label(_("Refresh perspective"), 0.0, 0.5)); +#endif + + apply3D->add(*apply3DLabel); apply3D->signal_clicked().connect(sigc::bind<Gtk::Entry*>(sigc::mem_fun(*this,&LPEPerspectivePath::refresh),perspective)); Gtk::Widget* apply3DWidget = dynamic_cast<Gtk::Widget *>(apply3D); apply3DWidget->set_tooltip_text("Refresh perspective"); @@ -247,9 +255,9 @@ LPEPerspectivePath::newWidget() return dynamic_cast<Gtk::Widget *>(vbox); } -void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { KnotHolderEntity *e = new PP::KnotHolderEntityOffset(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Adjust the origin") ); knotholder->add(e); }; diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h index c4ddf1853..87ee453ff 100644 --- a/src/live_effects/lpe-perspective_path.h +++ b/src/live_effects/lpe-perspective_path.h @@ -41,7 +41,7 @@ public: virtual Gtk::Widget * newWidget(); /* the knotholder entity classes must be declared friends */ friend class PP::KnotHolderEntityOffset; - void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); private: // add the parameters for your effect here: diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 03102a84a..d87f92fcc 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -13,31 +13,20 @@ #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-powerstroke-interpolators.h" -#include "sp-shape.h" #include "style.h" -#include "xml/repr.h" -#include "sp-paint-server.h" #include "svg/svg-color.h" #include "desktop-style.h" #include "svg/css-ostringstream.h" #include "display/curve.h" -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/transforms.h> -#include <2geom/bezier-utils.h> #include <2geom/elliptical-arc.h> -#include <2geom/sbasis-to-bezier.h> #include <2geom/path-sink.h> #include <2geom/path-intersection.h> -#include <2geom/crossing.h> -#include <2geom/ellipse.h> #include <2geom/circle.h> -#include <2geom/math-utils.h> -#include <math.h> +#include "helper/geom.h" -#include "spiro.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Geom { // should all be moved to 2geom at some point @@ -190,14 +179,14 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : interpolator_beta.addSlider(true); interpolator_beta.param_set_range(0.,1.); - registerParameter( dynamic_cast<Parameter *>(&offset_points) ); - registerParameter( dynamic_cast<Parameter *>(&sort_points) ); - registerParameter( dynamic_cast<Parameter *>(&interpolator_type) ); - registerParameter( dynamic_cast<Parameter *>(&interpolator_beta) ); - registerParameter( dynamic_cast<Parameter *>(&start_linecap_type) ); - registerParameter( dynamic_cast<Parameter *>(&linejoin_type) ); - registerParameter( dynamic_cast<Parameter *>(&miter_limit) ); - registerParameter( dynamic_cast<Parameter *>(&end_linecap_type) ); + registerParameter(&offset_points); + registerParameter(&sort_points); + registerParameter(&interpolator_type); + registerParameter(&interpolator_beta); + registerParameter(&start_linecap_type); + registerParameter(&linejoin_type); + registerParameter(&miter_limit); + registerParameter(&end_linecap_type); } LPEPowerStroke::~LPEPowerStroke() @@ -205,14 +194,13 @@ LPEPowerStroke::~LPEPowerStroke() } - void LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { + if (SP_IS_SHAPE(lpeitem) && offset_points.data().empty()) { SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); std::vector<Geom::Point> points; - Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector(); + Geom::PathVector const &pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeitem)->_curve->get_pathvector()); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.; SPCSSAttr *css = sp_repr_css_attr_new (); @@ -565,12 +553,11 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (path_in.empty()) { return path_out; } - - // for now, only regard first subpath and ignore the rest - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb(); - + Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(path_in); + Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = pathv[0].toPwSb(); Piecewise<D2<SBasis> > der = derivative(pwd2_in); - Piecewise<D2<SBasis> > n = rot90(unitVector(der)); + Piecewise<D2<SBasis> > n = unitVector(der,0.0001); + n = rot90(n); offset_points.set_pwd2(pwd2_in, n); LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value()); @@ -583,7 +570,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (sort_points) { sort(ts.begin(), ts.end(), compare_offsets); } - if (path_in[0].closed()) { + if (pathv[0].closed()) { // add extra points for interpolation between first and last point Point first_point = ts.front(); Point last_point = ts.back(); @@ -605,7 +592,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) for (std::size_t i = 0, e = ts.size(); i < e; ++i) { ts[i][Geom::X] *= xcoord_scaling; } - // create stroke path where points (x,y) := (t, offset) Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())); if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) { @@ -626,7 +612,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) // find time values for which x lies outside path domain // and only take portion of x and y that lies within those time values std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); - std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); + std::vector< double > rtsmax = roots (x + pwd2_in.domain().max()); if ( !rtsmin.empty() && !rtsmax.empty() ) { x = portion(x, rtsmin.at(0), rtsmax.at(0)); y = portion(y, rtsmin.at(0), rtsmax.at(0)); @@ -639,8 +625,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); - - if (path_in[0].closed()) { + if (pathv[0].closed()) { fixed_path.close(true); path_out.push_back(fixed_path); fixed_mirrorpath.close(true); @@ -684,7 +669,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) } fixed_path.append(fixed_mirrorpath); - switch (start_linecap) { case LINECAP_ZERO_WIDTH: // do nothing @@ -720,11 +704,9 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) break; } } - fixed_path.close(true); path_out.push_back(fixed_path); } - return path_out; } diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp index ac571d963..47613f58e 100644 --- a/src/live_effects/lpe-recursiveskeleton.cpp +++ b/src/live_effects/lpe-recursiveskeleton.cpp @@ -10,17 +10,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-recursiveskeleton.h" -#include <2geom/path.h> -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/piecewise.h> + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -33,7 +28,7 @@ LPERecursiveSkeleton::LPERecursiveSkeleton(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; iterations.param_make_integer(true); iterations.param_set_range(1, 15); - registerParameter( dynamic_cast<Parameter *>(&iterations) ); + registerParameter(&iterations); } diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 76421e0f0..d832b3615 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -13,24 +13,17 @@ */ #include "ui/widget/scalar.h" -#include <glibmm/i18n.h> #include "live_effects/lpe-rough-hatches.h" #include "sp-item.h" #include "sp-path.h" -#include "svg/svg.h" #include "xml/repr.h" -#include <2geom/path.h> -#include <2geom/piecewise.h> -#include <2geom/sbasis.h> #include <2geom/sbasis-math.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/affine.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -248,26 +241,26 @@ LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) : // bender(_("Global bending"), _("Relative position to a reference point defines global bending direction and amount"), "bender", &wr, this, Geom::Point(-5,0)) { - registerParameter( dynamic_cast<Parameter *>(&direction) ); - registerParameter( dynamic_cast<Parameter *>(&dist_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&growth) ); - registerParameter( dynamic_cast<Parameter *>(&do_bend) ); - registerParameter( dynamic_cast<Parameter *>(&bender) ); - registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) ); - registerParameter( dynamic_cast<Parameter *>(&scale_tf) ); - registerParameter( dynamic_cast<Parameter *>(&scale_tb) ); - registerParameter( dynamic_cast<Parameter *>(&scale_bf) ); - registerParameter( dynamic_cast<Parameter *>(&scale_bb) ); - registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) ); - registerParameter( dynamic_cast<Parameter *>(&fat_output) ); - registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) ); - registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) ); - registerParameter( dynamic_cast<Parameter *>(&front_thickness) ); - registerParameter( dynamic_cast<Parameter *>(&back_thickness) ); + registerParameter(&direction); + registerParameter(&dist_rdm); + registerParameter(&growth); + registerParameter(&do_bend); + registerParameter(&bender); + registerParameter(&top_edge_variation); + registerParameter(&bot_edge_variation); + registerParameter(&top_tgt_variation); + registerParameter(&bot_tgt_variation); + registerParameter(&scale_tf); + registerParameter(&scale_tb); + registerParameter(&scale_bf); + registerParameter(&scale_bb); + registerParameter(&top_smth_variation); + registerParameter(&bot_smth_variation); + registerParameter(&fat_output); + registerParameter(&stroke_width_top); + registerParameter(&stroke_width_bot); + registerParameter(&front_thickness); + registerParameter(&back_thickness); //hatch_dist.param_set_range(0.1, Geom::infinity()); growth.param_set_range(0, Geom::infinity()); diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 105fe2fc4..e847494a2 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -14,15 +14,13 @@ */ #include <gtkmm.h> -#include "desktop.h" #include "live_effects/lpe-roughen.h" #include "display/curve.h" -#include "live_effects/parameter/parameter.h" #include <boost/functional/hash.hpp> #include "helper/geom.h" -#include "sp-item-group.h" + +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -#include <cmath> namespace Inkscape { namespace LivePathEffect { @@ -122,7 +120,7 @@ Gtk::Widget *LPERoughen::newWidget() Gtk::ALIGN_START)); method_label->set_use_markup(true); vbox->pack_start(*method_label, false, false, 2); - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "displace_x") { @@ -131,7 +129,7 @@ Gtk::Widget *LPERoughen::newWidget() Gtk::ALIGN_START)); displace_x_label->set_use_markup(true); vbox->pack_start(*displace_x_label, false, false, 2); - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "global_randomize") { @@ -140,7 +138,7 @@ Gtk::Widget *LPERoughen::newWidget() Gtk::ALIGN_START)); global_rand->set_use_markup(true); vbox->pack_start(*global_rand, false, false, 2); - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "handles") { @@ -149,7 +147,7 @@ Gtk::Widget *LPERoughen::newWidget() Gtk::ALIGN_START)); options->set_use_markup(true); vbox->pack_start(*options, false, false, 2); - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + vbox->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_EXPAND_WIDGET); } Glib::ustring *tip = param->param_getTooltip(); @@ -229,7 +227,7 @@ void LPERoughen::doEffect(SPCurve *curve) nCurve->lineto(curve_it1->finalPoint()); } last_move = Geom::Point(0, 0); - double length = curve_it1->length(0.001); + double length = curve_it1->length(0.01); std::size_t splits = 0; if (method == DM_SEGMENTS) { splits = segments; @@ -354,9 +352,6 @@ SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point point_a3 = seg1[3] + point_a3; ray.setPoints(prev,A->initialPoint()); point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght); - if(prev == Geom::Point(0,0)){ - point_a1 = randomize(max_lenght); - } if(last){ Geom::Path b2(point_b3); b2.appendNew<Geom::LineSegment>(point_a3); diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index 44a723c89..bab06022f 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -12,8 +12,8 @@ #ifndef INKSCAPE_LPE_ROUGHEN_H #define INKSCAPE_LPE_ROUGHEN_H -#include "live_effects/parameter/enum.h" #include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/path.h" #include "live_effects/parameter/bool.h" diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index 49b5faa2e..852592219 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -12,11 +12,8 @@ */ #include "live_effects/lpe-ruler.h" -#include <2geom/piecewise.h> -#include <2geom/sbasis-geometric.h> -#include "inkscape.h" -#include "desktop.h" - +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -48,15 +45,15 @@ LPERuler::LPERuler(LivePathEffectObject *lpeobject) : offset(_("_Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), border_marks(_("Border marks:"), _("Choose whether to draw marks at the beginning and end of the path"), "border_marks", BorderMarkTypeConverter, &wr, this, BORDERMARK_BOTH) { - registerParameter(dynamic_cast<Parameter *>(&unit)); - registerParameter(dynamic_cast<Parameter *>(&mark_distance)); - registerParameter(dynamic_cast<Parameter *>(&mark_length)); - registerParameter(dynamic_cast<Parameter *>(&minor_mark_length)); - registerParameter(dynamic_cast<Parameter *>(&major_mark_steps)); - registerParameter(dynamic_cast<Parameter *>(&shift)); - registerParameter(dynamic_cast<Parameter *>(&offset)); - registerParameter(dynamic_cast<Parameter *>(&mark_dir)); - registerParameter(dynamic_cast<Parameter *>(&border_marks)); + registerParameter(&unit); + registerParameter(&mark_distance); + registerParameter(&mark_length); + registerParameter(&minor_mark_length); + registerParameter(&major_mark_steps); + registerParameter(&shift); + registerParameter(&offset); + registerParameter(&mark_dir); + registerParameter(&border_marks); major_mark_steps.param_make_integer(); major_mark_steps.param_set_range(1, 1000); diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp index 0bc1c4f17..7c298d0e7 100644 --- a/src/live_effects/lpe-show_handles.cpp +++ b/src/live_effects/lpe-show_handles.cpp @@ -7,9 +7,7 @@ */ #include <gtkmm.h> -#include <glibmm/i18n.h> #include "live_effects/lpe-show_handles.h" -#include "live_effects/parameter/parameter.h" #include <2geom/sbasis-to-bezier.h> #include <2geom/svg-path-parser.h> #include "helper/geom.h" @@ -17,6 +15,9 @@ #include "style.h" #include "svg/svg.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -25,20 +26,17 @@ LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject) nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true), handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true), original_path(_("Show path"), _("Show path"), "original_path", &wr, this, true), - scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10), - rotate_nodes(_("Rotate nodes"), _("Rotate nodes"), "rotate_nodes", &wr, this, 0) + show_center_node(_("Show center of node"), _("Show center of node"), "show_center_node", &wr, this, false), + scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10) { registerParameter(&nodes); registerParameter(&handles); registerParameter(&original_path); + registerParameter(&show_center_node); registerParameter(&scale_nodes_and_handles); - registerParameter(&rotate_nodes); scale_nodes_and_handles.param_set_range(0, 500.); scale_nodes_and_handles.param_set_increments(1, 1); scale_nodes_and_handles.param_set_digits(2); - rotate_nodes.param_set_range(0, 365); - rotate_nodes.param_set_increments(1, 1); - rotate_nodes.param_set_digits(0); stroke_width = 1.0; } @@ -130,7 +128,11 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) } } if(nodes) { - drawNode(curve_it1->initialPoint()); + Geom::NodeType nodetype = Geom::NODE_CUSP; + if(path_it->closed()) { + nodetype = Geom::get_nodetype(path_it->finalCurve(), *curve_it1); + } + drawNode(curve_it1->initialPoint(), nodetype); } while (curve_it1 != curve_endit) { cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); @@ -146,8 +148,9 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) } } } - if(nodes) { - drawNode(curve_it1->finalPoint()); + if(nodes && (curve_it2 != curve_endit || !path_it->closed())) { + Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2); + drawNode(curve_it1->finalPoint(), nodetype); } ++curve_it1; if(curve_it2 != curve_endit) { @@ -158,16 +161,26 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) } void -LPEShowHandles::drawNode(Geom::Point p) +LPEShowHandles::drawNode(Geom::Point p, Geom::NodeType nodetype) { if(stroke_width * scale_nodes_and_handles > 0.0) { + Geom::Rotate rotate = Geom::Rotate(0); + if ( nodetype == Geom::NODE_CUSP) { + rotate = Geom::Rotate::from_degrees(45); + } double diameter = stroke_width * scale_nodes_and_handles; char const * svgd; - svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z"; + if (show_center_node) { + svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z"; + } else { + svgd = "M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z"; + } Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Rotate::from_degrees(rotate_nodes) * Geom::Scale(diameter) * Geom::Translate(p); + pathv *= rotate * Geom::Scale(diameter) * Geom::Translate(p); outline_path.push_back(pathv[0]); - outline_path.push_back(pathv[1]); + if (show_center_node) { + outline_path.push_back(pathv[1]); + } } } diff --git a/src/live_effects/lpe-show_handles.h b/src/live_effects/lpe-show_handles.h index 34390dd32..c46abd2c2 100644 --- a/src/live_effects/lpe-show_handles.h +++ b/src/live_effects/lpe-show_handles.h @@ -8,7 +8,7 @@ * Copyright (C) Jabier Arraiza Cenoz 2014 <jabier.arraiza@marker.es> * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include "helper/geom-nodetype.h" #include "live_effects/effect.h" #include "live_effects/lpegroupbbox.h" #include "live_effects/parameter/bool.h" @@ -28,7 +28,7 @@ public: virtual void generateHelperPath(Geom::PathVector result); - virtual void drawNode(Geom::Point p); + virtual void drawNode(Geom::Point p, Geom::NodeType nodetype); virtual void drawHandle(Geom::Point p); @@ -43,8 +43,8 @@ private: BoolParam nodes; BoolParam handles; BoolParam original_path; + BoolParam show_center_node; ScalarParam scale_nodes_and_handles; - ScalarParam rotate_nodes; double stroke_width; static bool alerts_off; diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index f807bdc8d..5de9816bb 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -3,24 +3,16 @@ */ #include <gtkmm.h> - #include "live_effects/lpe-simplify.h" #include "display/curve.h" -#include "live_effects/parameter/parameter.h" -#include <glibmm/i18n.h> #include "helper/geom.h" -#include "livarot/Path.h" -#include "splivarot.h" #include <2geom/svg-path-parser.h> -#include "desktop.h" -#include "inkscape.h" #include "svg/svg.h" #include "ui/tools/node-tool.h" -#include <2geom/d2.h> -#include <2geom/generic-rect.h> -#include <2geom/interval.h> #include "ui/icon-names.h" -#include "util/units.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -148,11 +140,7 @@ LPESimplify::doEffect(SPCurve *curve) Geom::PathVector result = Geom::parse_svg_path(pathliv->svg_dump_path()); generateHelperPathAndSmooth(result); curve->set_pathvector(result); - SPDesktop* desktop = SP_ACTIVE_DESKTOP; - if(desktop && INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context); - nt->update_helperpath(); - } + Inkscape::UI::Tools::sp_update_helperpath(); } void diff --git a/src/live_effects/lpe-simplify.h b/src/live_effects/lpe-simplify.h index 294d77b35..6c407f572 100644 --- a/src/live_effects/lpe-simplify.h +++ b/src/live_effects/lpe-simplify.h @@ -6,7 +6,6 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - #include "live_effects/effect.h" #include "live_effects/parameter/togglebutton.h" #include "live_effects/lpegroupbbox.h" diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp index 6e4afbe9b..d3c94269a 100644 --- a/src/live_effects/lpe-skeleton.cpp +++ b/src/live_effects/lpe-skeleton.cpp @@ -20,14 +20,9 @@ #include "live_effects/lpe-skeleton.h" -// You might need to include other 2geom files. You can add them here: -#include <2geom/path.h> - +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -//#include "knot-holder-entity.h" -//#include "knotholder.h" - namespace Inkscape { namespace LivePathEffect { @@ -42,7 +37,7 @@ LPESkeleton::LPESkeleton(LivePathEffectObject *lpeobject) : //_provides_knotholder_entities /* register all your parameters here, so Inkscape knows which parameters this effect has: */ - registerParameter( dynamic_cast<Parameter *>(&number) ); + registerParameter(&number); } LPESkeleton::~LPESkeleton() @@ -102,10 +97,10 @@ public: } // namespace Skeleton void -LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { { KnotHolderEntityMyHandle *e = new KnotHolderEntityMyHandle(this); - e->create( desktop, item, knotholder, + e->create( NULL, item, knotholder, _("Text describing what this handle does"), //optional: knot_shape, knot_mode, knot_color); knotholder->add(e); diff --git a/src/live_effects/lpe-skeleton.h b/src/live_effects/lpe-skeleton.h index 3b45b6978..e633ba5ab 100644 --- a/src/live_effects/lpe-skeleton.h +++ b/src/live_effects/lpe-skeleton.h @@ -41,7 +41,7 @@ public: /* the knotholder entity classes (if any) can be declared friends */ //friend class Skeleton::KnotHolderEntityMyHandle; - //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); private: // add the parameters for your effect here: diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 82d343f6e..e3376b7e5 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -13,21 +13,14 @@ #include "live_effects/lpe-sketch.h" -#include <glibmm/i18n.h> - // You might need to include other 2geom files. You can add them here: -#include <2geom/path.h> -#include <2geom/sbasis.h> -#include <2geom/sbasis-geometric.h> #include <2geom/sbasis-math.h> #include <2geom/bezier-to-sbasis.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/d2.h> -#include <2geom/sbasis-math.h> -#include <2geom/piecewise.h> -#include <2geom/crossing.h> #include <2geom/path-intersection.h> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -69,25 +62,25 @@ LPESketch::LPESketch(LivePathEffectObject *lpeobject) : // register all your parameters here, so Inkscape knows which parameters this effect has: //Add some comment in the UI: *warning* the precise output of this effect might change in future releases! //convert to path if you want to keep exact output unchanged in future releases... - //registerParameter( dynamic_cast<Parameter *>(&testpointA) ); - registerParameter( dynamic_cast<Parameter *>(&nbiter_approxstrokes) ); - registerParameter( dynamic_cast<Parameter *>(&strokelength) ); - registerParameter( dynamic_cast<Parameter *>(&strokelength_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&strokeoverlap) ); - registerParameter( dynamic_cast<Parameter *>(&strokeoverlap_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&ends_tolerance) ); - registerParameter( dynamic_cast<Parameter *>(¶llel_offset) ); - registerParameter( dynamic_cast<Parameter *>(&tremble_size) ); - registerParameter( dynamic_cast<Parameter *>(&tremble_frequency) ); + //registerParameter(&testpointA) ); + registerParameter(&nbiter_approxstrokes); + registerParameter(&strokelength); + registerParameter(&strokelength_rdm); + registerParameter(&strokeoverlap); + registerParameter(&strokeoverlap_rdm); + registerParameter(&ends_tolerance); + registerParameter(¶llel_offset); + registerParameter(&tremble_size); + registerParameter(&tremble_frequency); #ifdef LPE_SKETCH_USE_CONSTRUCTION_LINES - registerParameter( dynamic_cast<Parameter *>(&nbtangents) ); - registerParameter( dynamic_cast<Parameter *>(&tgt_places_rdmness) ); - registerParameter( dynamic_cast<Parameter *>(&tgtscale) ); - registerParameter( dynamic_cast<Parameter *>(&tgtlength) ); - registerParameter( dynamic_cast<Parameter *>(&tgtlength_rdm) ); + registerParameter(&nbtangents); + registerParameter(&tgt_places_rdmness); + registerParameter(&tgtscale); + registerParameter(&tgtlength); + registerParameter(&tgtlength_rdm); #ifdef LPE_SKETCH_USE_CURVATURE - registerParameter( dynamic_cast<Parameter *>(&min_curvature) ); - registerParameter( dynamic_cast<Parameter *>(&max_curvature) ); + registerParameter(&min_curvature); + registerParameter(&max_curvature); #endif #endif diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp index 0d42596b2..8ea57bee4 100644 --- a/src/live_effects/lpe-spiro.cpp +++ b/src/live_effects/lpe-spiro.cpp @@ -7,9 +7,6 @@ #include "live_effects/lpe-spiro.h" #include "display/curve.h" -#include <typeinfo> -#include <2geom/pathvector.h> -#include <2geom/affine.h> #include <2geom/curves.h> #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" @@ -19,8 +16,6 @@ // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" -#include "desktop.h" - namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index 978ab57fb..69a4dfad9 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -13,17 +13,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-tangent_to_curve.h" #include "sp-path.h" #include "display/curve.h" -#include <2geom/path.h> -#include <2geom/transforms.h> - -#include "knot-holder-entity.h" #include "knotholder.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { @@ -64,10 +60,10 @@ LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) : show_orig_path = true; _provides_knotholder_entities = true; - registerParameter( dynamic_cast<Parameter *>(&angle) ); - registerParameter( dynamic_cast<Parameter *>(&t_attach) ); - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&angle); + registerParameter(&t_attach); + registerParameter(&length_left); + registerParameter(&length_right); } LPETangentToCurve::~LPETangentToCurve() @@ -96,22 +92,22 @@ LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const } void -LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { { KnotHolderEntity *e = new TtC::KnotHolderEntityAttachPt(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Adjust the point of attachment of the tangent") ); knotholder->add(e); } { KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Adjust the <b>left</b> end of the tangent") ); knotholder->add(e); } { KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Adjust the <b>right</b> end of the tangent") ); knotholder->add(e); } diff --git a/src/live_effects/lpe-tangent_to_curve.h b/src/live_effects/lpe-tangent_to_curve.h index 8e44c01d1..a6a3c17ca 100644 --- a/src/live_effects/lpe-tangent_to_curve.h +++ b/src/live_effects/lpe-tangent_to_curve.h @@ -41,7 +41,7 @@ public: friend class TtC::KnotHolderEntityLeftEnd; friend class TtC::KnotHolderEntityRightEnd; friend class TtC::KnotHolderEntityAttachPt; - virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item); private: ScalarParam angle; diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index f2ddd4929..45394ae91 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -13,26 +13,20 @@ #include "live_effects/lpe-taperstroke.h" -#include <2geom/path.h> -#include <2geom/path.h> #include <2geom/circle.h> #include <2geom/sbasis-to-bezier.h> #include "helper/geom-nodetype.h" #include "helper/geom-pathstroke.h" #include "display/curve.h" -#include "sp-shape.h" #include "style.h" -#include "xml/repr.h" -#include "sp-paint-server.h" #include "svg/svg-color.h" #include "desktop-style.h" #include "svg/css-ostringstream.h" #include "svg/svg.h" -#include "knot-holder-entity.h" #include "knotholder.h" - +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> template<typename T> @@ -97,6 +91,7 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) { if (SP_IS_SHAPE(lpeitem)) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; @@ -123,8 +118,14 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - - line_width.param_set_value(width); + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() + + (Glib::ustring)"/" + + (Glib::ustring)"stroke_width"; + bool valid = prefs->getEntry(pref_path).isValid(); + if(!valid){ + line_width.param_set_value(width); + } line_width.write_to_SVG(); } else { printf("WARNING: It only makes sense to apply Taper stroke to paths (not groups).\n"); @@ -441,14 +442,14 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path } } -void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE); + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE); knotholder->add(e); KnotHolderEntity *f = new TpS::KnotHolderEntityAttachEnd(this); - f->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE); + f->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE); knotholder->add(f); } @@ -476,7 +477,6 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con // use that object. Geom::PathVector pathv = lpe->pathvector_before_effect; - Piecewise<D2<SBasis> > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0]); pwd2.concat(p_in.toPwSb()); diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index 88604486e..e3ecbb56c 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -36,7 +36,7 @@ public: virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in); Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in); - virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item); friend class TpS::KnotHolderEntityAttachBegin; friend class TpS::KnotHolderEntityAttachEnd; diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index 2bcd4c136..c484c88a2 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -4,13 +4,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-test-doEffect-stack.h" -#include <2geom/piecewise.h> -#include <vector> -#include <cstring> +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + using std::memcpy; namespace Inkscape { @@ -23,12 +21,12 @@ LPEdoEffectStackTest::LPEdoEffectStackTest(LivePathEffectObject *lpeobject) : point(_("Point param:"), "tooltip of point parameter", "point_param", &wr, this), path(_("Path param:"), "tooltip of path parameter", "path_param", &wr, this,"M 0,100 100,0") { - registerParameter( dynamic_cast<Parameter *>(&step) ); - registerParameter( dynamic_cast<Parameter *>(&point) ); - registerParameter( dynamic_cast<Parameter *>(&path) ); + registerParameter(&step); + registerParameter(&point); + registerParameter(&path); point.set_oncanvas_looks(SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR, 0x00ff0000); - point.param_setValue(point,true); + point.param_setValue(point); } LPEdoEffectStackTest::~LPEdoEffectStackTest() diff --git a/src/live_effects/lpe-text_label.cpp b/src/live_effects/lpe-text_label.cpp index 602a6897c..0c1db2f04 100644 --- a/src/live_effects/lpe-text_label.cpp +++ b/src/live_effects/lpe-text_label.cpp @@ -11,10 +11,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glibmm/i18n.h> - #include "live_effects/lpe-text_label.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -22,7 +23,7 @@ LPETextLabel::LPETextLabel(LivePathEffectObject *lpeobject) : Effect(lpeobject), label(_("Label:"), _("Text label attached to the path"), "label", &wr, this, "This is a label") { - registerParameter( dynamic_cast<Parameter *>(&label) ); + registerParameter(&label); } LPETextLabel::~LPETextLabel() diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp index 1cd59b7fa..ab05b880c 100644 --- a/src/live_effects/lpe-transform_2pts.cpp +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -14,15 +14,13 @@ #include "live_effects/lpe-transform_2pts.h" #include "display/curve.h" -#include <2geom/transforms.h> -#include <2geom/pathvector.h> -#include "sp-path.h" #include "ui/icon-names.h" #include "svg/svg.h" #include "verbs.h" // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> + namespace Inkscape { namespace LivePathEffect { @@ -36,7 +34,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : flip_vertical(_("Flip vertical"), _("Flip vertical"), "flip_vertical", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), start(_("Start"), _("Start point"), "start", &wr, this, "Start point"), end(_("End"), _("End point"), "end", &wr, this, "End point"), - strech(_("Stretch"), _("Stretch the result"), "strech", &wr, this, 1), + stretch(_("Stretch"), _("Stretch the result"), "stretch", &wr, this, 1), offset(_("Offset"), _("Offset from knots"), "offset", &wr, this, 0), first_knot(_("First Knot"), _("First Knot"), "first_knot", &wr, this, 1), last_knot(_("Last Knot"), _("Last Knot"), "last_knot", &wr, this, 1), @@ -54,7 +52,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : registerParameter(&first_knot); registerParameter(&last_knot); registerParameter(&helper_size); - registerParameter(&strech); + registerParameter(&stretch); registerParameter(&offset); registerParameter(&start); registerParameter(&end); @@ -66,18 +64,18 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : registerParameter(&lock_angle); first_knot.param_make_integer(true); - first_knot.param_overwrite_widget(true); + first_knot.param_set_undo(false); last_knot.param_make_integer(true); - last_knot.param_overwrite_widget(true); + last_knot.param_set_undo(false); helper_size.param_set_range(0, 999); helper_size.param_set_increments(1, 1); helper_size.param_set_digits(0); offset.param_set_range(-999999.0, 999999.0); offset.param_set_increments(1, 1); offset.param_set_digits(2); - strech.param_set_range(0, 999.0); - strech.param_set_increments(0.01, 0.01); - strech.param_set_digits(4); + stretch.param_set_range(0, 999.0); + stretch.param_set_increments(0.01, 0.01); + stretch.param_set_digits(4); apply_to_clippath_and_mask = true; } @@ -90,7 +88,6 @@ LPETransform2Pts::doOnApply(SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - point_a = Point(boundingbox_X.min(), boundingbox_Y.middle()); point_b = Point(boundingbox_X.max(), boundingbox_Y.middle()); SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); @@ -141,14 +138,22 @@ LPETransform2Pts::doBeforeEffect (SPLPEItem const* lpeitem) size_t nnodes = nodeCount(pathvector); first_knot.param_set_range(1, last_knot-1); last_knot.param_set_range(first_knot+1, nnodes); - from_original_width.param_setValue(false); + if (from_original_width){ + from_original_width.param_setValue(false); + } } else { - first_knot.param_set_value(1); - last_knot.param_set_value(2); + if (first_knot != 1){ + first_knot.param_set_value(1); + } + if (last_knot != 2){ + last_knot.param_set_value(2); + } first_knot.param_set_range(1,1); last_knot.param_set_range(2,2); - from_original_width.param_setValue(true); append_path = false; + if (!from_original_width){ + from_original_width.param_setValue(true); + } } if(lock_lenght && !lock_angle && previous_lenght != -1) { Geom::Ray transformed((Geom::Point)start,(Geom::Point)end); @@ -254,6 +259,8 @@ LPETransform2Pts::reset() first_knot.param_set_value(1); last_knot.param_set_value(2); } + offset.param_set_value(0.0); + stretch.param_set_value(1.0); Geom::Ray transformed(point_a, point_b); previous_angle = transformed.angle(); previous_lenght = Geom::distance(point_a, point_b); @@ -382,9 +389,9 @@ LPETransform2Pts::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const m *= Geom::Scale(-1,1); m *= Geom::Rotate(original_angle); } - if(strech != 1){ + if(stretch != 1){ m *= Geom::Rotate(-original_angle); - m *= Geom::Scale(1,strech); + m *= Geom::Scale(1,stretch); m *= Geom::Rotate(original_angle); } if(elastic) { @@ -434,7 +441,7 @@ LPETransform2Pts::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector< } if(!lock_angle && lock_lenght) { char const * svgd; - svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12"; + svgd = "M 0,9.94 C -2.56,9.91 -5.17,8.98 -7.07,7.07 c -3.91,-3.9 -3.91,-10.24 0,-14.14 1.97,-1.97 4.51,-3.02 7.07,-3.04 2.56,0.02 5.1,1.07 7.07,3.04 3.91,3.9 3.91,10.24 0,14.14 C 5.17,8.98 2.56,9.91 0,9.94 Z"; PathVector pathv_turn = sp_svg_read_pathv(svgd); pathv_turn *= Geom::Rotate(previous_angle); pathv_turn *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(end)); diff --git a/src/live_effects/lpe-transform_2pts.h b/src/live_effects/lpe-transform_2pts.h index c20d56206..0f88e6b00 100644 --- a/src/live_effects/lpe-transform_2pts.h +++ b/src/live_effects/lpe-transform_2pts.h @@ -57,7 +57,7 @@ private: ToggleButtonParam flip_vertical; PointParam start; PointParam end; - ScalarParam strech; + ScalarParam stretch; ScalarParam offset; ScalarParam first_knot; ScalarParam last_knot; diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 7eda7446e..b9fd8908a 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -5,11 +5,9 @@ */ #include "live_effects/lpe-vonkoch.h" - +// TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> -#include <2geom/transforms.h> - //using std::vector; namespace Inkscape { namespace LivePathEffect { @@ -55,15 +53,15 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : maxComplexity(_("_Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000) { //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug. - registerParameter( dynamic_cast<Parameter *>(&ref_path) ); - //registerParameter( dynamic_cast<Parameter *>(&refA) ); - //registerParameter( dynamic_cast<Parameter *>(&refB) ); - registerParameter( dynamic_cast<Parameter *>(&generator) ); - registerParameter( dynamic_cast<Parameter *>(&similar_only) ); - registerParameter( dynamic_cast<Parameter *>(&nbgenerations) ); - registerParameter( dynamic_cast<Parameter *>(&drawall) ); - registerParameter( dynamic_cast<Parameter *>(&maxComplexity) ); - //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) ); + registerParameter(&ref_path); + //registerParameter(&refA) ); + //registerParameter(&refB) ); + registerParameter(&generator); + registerParameter(&similar_only); + registerParameter(&nbgenerations); + registerParameter(&drawall); + registerParameter(&maxComplexity); + //registerParameter(&draw_boxes) ); apply_to_clippath_and_mask = true; nbgenerations.param_make_integer(); nbgenerations.param_set_range(0, Geom::infinity()); diff --git a/src/live_effects/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp index 2a1b70a6a..3862ebcc8 100644 --- a/src/live_effects/lpegroupbbox.cpp +++ b/src/live_effects/lpegroupbbox.cpp @@ -7,8 +7,6 @@ #include "live_effects/lpegroupbbox.h" -#include "sp-item.h" - namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpeobject-reference.cpp b/src/live_effects/lpeobject-reference.cpp index d9de6e77f..83cd6623c 100644 --- a/src/live_effects/lpeobject-reference.cpp +++ b/src/live_effects/lpeobject-reference.cpp @@ -6,10 +6,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information. */ +#include "live_effects/lpeobject-reference.h" + #include <string.h> -#include "enums.h" -#include "live_effects/lpeobject-reference.h" +#include "bad-uri-exception.h" #include "live_effects/lpeobject.h" #include "uri.h" diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index 8e5ae568f..ca3ae46e0 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -11,13 +11,10 @@ #include "xml/repr.h" #include "xml/node-event-vector.h" -#include "sp-object.h" #include "attributes.h" #include "document.h" #include "document-private.h" -#include <glibmm/i18n.h> - //#define LIVEPATHEFFECT_VERBOSE static void livepatheffect_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data); @@ -115,6 +112,7 @@ void LivePathEffectObject::set(unsigned key, gchar const *value) { this->effecttype_set = true; } else { this->effecttype = Inkscape::LivePathEffect::INVALID_LPE; + this->lpe = NULL; this->effecttype_set = false; } diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h index 2e62707e3..e468b4080 100644 --- a/src/live_effects/lpeobject.h +++ b/src/live_effects/lpeobject.h @@ -38,8 +38,12 @@ public: /* Note that the returned pointer can be NULL in a valid LivePathEffectObject contained in a valid list of lpeobjects in an lpeitem! * So one should always check whether the returned value is NULL or not */ - Inkscape::LivePathEffect::Effect * get_lpe() { return lpe; }; - Inkscape::LivePathEffect::Effect const * get_lpe() const { return lpe; }; + Inkscape::LivePathEffect::Effect * get_lpe() { + return lpe; + } + Inkscape::LivePathEffect::Effect const * get_lpe() const { + return lpe; + }; Inkscape::LivePathEffect::Effect *lpe; // this can be NULL in a valid LivePathEffectObject diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert deleted file mode 100644 index bd1c5b600..000000000 --- a/src/live_effects/parameter/Makefile_insert +++ /dev/null @@ -1,36 +0,0 @@ -## Makefile.am fragment sourced by src/Makefile.am. - -ink_common_sources += \ - live_effects/parameter/parameter.cpp \ - live_effects/parameter/parameter.h \ - live_effects/parameter/array.cpp \ - live_effects/parameter/array.h \ - live_effects/parameter/bool.cpp \ - live_effects/parameter/bool.h \ - live_effects/parameter/random.cpp \ - live_effects/parameter/random.h \ - live_effects/parameter/point.cpp \ - live_effects/parameter/point.h \ - live_effects/parameter/enum.h \ - live_effects/parameter/path-reference.cpp \ - live_effects/parameter/path-reference.h \ - live_effects/parameter/path.cpp \ - live_effects/parameter/path.h \ - live_effects/parameter/originalpath.cpp \ - live_effects/parameter/originalpath.h \ - live_effects/parameter/originalpatharray.cpp \ - live_effects/parameter/originalpatharray.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/transformedpoint.cpp \ - live_effects/parameter/transformedpoint.h \ - live_effects/parameter/togglebutton.cpp \ - live_effects/parameter/togglebutton.h \ - live_effects/parameter/unit.cpp \ - live_effects/parameter/unit.h \ - live_effects/parameter/vector.cpp \ - live_effects/parameter/vector.h diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp index 1b8f742da..7470f54cd 100644 --- a/src/live_effects/parameter/array.cpp +++ b/src/live_effects/parameter/array.cpp @@ -5,10 +5,7 @@ */ #include "live_effects/parameter/array.h" - -#include "svg/svg.h" -#include "svg/stringstream.h" - +#include "helper-fns.h" #include <2geom/coord.h> #include <2geom/point.h> @@ -49,6 +46,45 @@ ArrayParam<Geom::Point>::readsvg(const gchar * str) return Geom::Point(Geom::infinity(),Geom::infinity()); } + +template <> +std::vector<Satellite> +ArrayParam<std::vector<Satellite > >::readsvg(const gchar * str) +{ + std::vector<Satellite> subpath_satellites; + if (!str) { + return subpath_satellites; + } + gchar ** strarray = g_strsplit(str, "@", 0); + gchar ** iter = strarray; + while (*iter != NULL) { + gchar ** strsubarray = g_strsplit(*iter, ",", 8); + if (*strsubarray[7]) {//steps always > 0 + Satellite *satellite = new Satellite(); + satellite->setSatelliteType(g_strstrip(strsubarray[0])); + satellite->is_time = strncmp(strsubarray[1],"1",1) == 0; + satellite->selected = strncmp(strsubarray[2],"1",1) == 0; + satellite->has_mirror = strncmp(strsubarray[3],"1",1) == 0; + satellite->hidden = strncmp(strsubarray[4],"1",1) == 0; + double amount,angle; + float stepsTmp; + sp_svg_number_read_d(strsubarray[5], &amount); + sp_svg_number_read_d(strsubarray[6], &angle); + sp_svg_number_read_f(g_strstrip(strsubarray[7]), &stepsTmp); + unsigned int steps = (unsigned int)stepsTmp; + satellite->amount = amount; + satellite->angle = angle; + satellite->steps = steps; + subpath_satellites.push_back(*satellite); + } + g_strfreev (strsubarray); + iter++; + } + g_strfreev (strarray); + return subpath_satellites; +} + + } /* namespace LivePathEffect */ } /* namespace Inkscape */ diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index a600f0257..e65d3b55c 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -15,6 +15,7 @@ #include "live_effects/parameter/parameter.h" +#include "helper/geom-satellite.h" #include "svg/svg.h" #include "svg/stringstream.h" @@ -59,7 +60,7 @@ public: g_strfreev (strarray); return true; } - + virtual void param_update_default(const gchar * default_value){}; virtual gchar * param_getSVGValue() const { Inkscape::SVGOStringStream os; writesvg(os, _vector); @@ -93,7 +94,43 @@ protected: // separate items with pipe symbol str << " | "; } - str << vector[i]; + writesvgData(str,vector[i]); + } + } + + void writesvgData(SVGOStringStream &str, float const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, double const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, Geom::Point const &vector_data) const { + str << vector_data; + } + + void writesvgData(SVGOStringStream &str, std::vector<Satellite> const &vector_data) const { + for (size_t i = 0; i < vector_data.size(); ++i) { + if (i != 0) { + // separate items with @ symbol ¿Any other? + str << " @ "; + } + str << vector_data[i].getSatelliteTypeGchar(); + str << ","; + str << vector_data[i].is_time; + str << ","; + str << vector_data[i].selected; + str << ","; + str << vector_data[i].has_mirror; + str << ","; + str << vector_data[i].hidden; + str << ","; + str << vector_data[i].amount; + str << ","; + str << vector_data[i].angle; + str << ","; + str << static_cast<int>(vector_data[i].steps); } } diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index 9ecadbdeb..954947cf4 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -21,8 +21,8 @@ namespace LivePathEffect { BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value , bool no_widget) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), hide_widget(no_widget) + Effect* effect, bool default_value) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) { } @@ -36,6 +36,18 @@ BoolParam::param_set_default() param_setValue(defvalue); } +void +BoolParam::param_update_default(bool const default_value) +{ + defvalue = default_value; +} + +void +BoolParam::param_update_default(const gchar * default_value) +{ + param_update_default(helperfns_read_bool(default_value, defvalue)); +} + bool BoolParam::param_readSVGValue(const gchar * strvalue) { @@ -53,7 +65,7 @@ BoolParam::param_getSVGValue() const Gtk::Widget * BoolParam::param_newWidget() { - if(!hide_widget){ + if(widget_is_visible){ Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredCheckButton( param_label, param_tooltip, @@ -66,7 +78,6 @@ BoolParam::param_newWidget() checkwdg->setActive(value); checkwdg->setProgrammatically = false; checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter")); - return dynamic_cast<Gtk::Widget *> (checkwdg); } else { return NULL; @@ -76,6 +87,9 @@ BoolParam::param_newWidget() void BoolParam::param_setValue(bool newvalue) { + if (value != newvalue) { + param_effect->upd_params = true; + } value = newvalue; } diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 403dd0b87..417752050 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -25,8 +25,7 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - bool default_value = false, - bool no_widget = false); + bool default_value = false); virtual ~BoolParam(); virtual Gtk::Widget * param_newWidget(); @@ -36,9 +35,9 @@ public: void param_setValue(bool newvalue); virtual void param_set_default(); - + void param_update_default(bool const default_value); + virtual void param_update_default(const gchar * default_value); bool get_value() const { return value; }; - inline operator bool() const { return value; }; private: @@ -47,7 +46,6 @@ private: bool value; bool defvalue; - bool hide_widget; }; diff --git a/src/live_effects/parameter/enum.h b/src/live_effects/parameter/enum.h index 2340663c3..78fa87a4f 100644 --- a/src/live_effects/parameter/enum.h +++ b/src/live_effects/parameter/enum.h @@ -27,12 +27,14 @@ public: const Util::EnumDataConverter<E>& c, Inkscape::UI::Widget::Registry* wr, Effect* effect, - E default_value) + E default_value, + bool sort = true) : Parameter(label, tip, key, wr, effect) { enumdataconv = &c; defvalue = default_value; value = defvalue; + sorted = sort; }; virtual ~EnumParam() { }; @@ -40,12 +42,11 @@ public: virtual Gtk::Widget * param_newWidget() { Inkscape::UI::Widget::RegisteredEnum<E> *regenum = Gtk::manage ( new Inkscape::UI::Widget::RegisteredEnum<E>( param_label, param_tooltip, - param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); + param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc(), sorted ) ); regenum->set_active_by_id(value); regenum->combobox()->setProgrammatically = false; regenum->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change enumeration parameter")); - return dynamic_cast<Gtk::Widget *> (regenum); }; @@ -75,8 +76,19 @@ public: void param_set_default() { param_set_value(defvalue); } - + + void param_update_default(E default_value) { + defvalue = default_value; + } + + virtual void param_update_default(const gchar * default_value) { + param_update_default(enumdataconv->get_id_from_key(Glib::ustring(default_value))); + } + void param_set_value(E val) { + if (value != val) { + param_effect->upd_params = true; + } value = val; } @@ -86,6 +98,7 @@ private: E value; E defvalue; + bool sorted; const Util::EnumDataConverter<E> * enumdataconv; }; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp deleted file mode 100644 index b321a5831..000000000 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ /dev/null @@ -1,877 +0,0 @@ -/* - * 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 <2geom/line.h> -#include <2geom/path-intersection.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 next_is_line = is_straight_curve(*curve_it1); - bool 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.size() > counterPaths && - last_pathv[counterPaths].size() > counter - offset && - !are_near(curve_it1->initialPoint(), - last_pathv[counterPaths][counter - offset].initialPoint(), - 0.1))) { - if ( curve_it2 == curve_endit) { - if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) { - offset = (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].reversed(); - } - } 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_time(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_time(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; - if(_vector.size() == 0){ - return; - } - 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 next_is_line = is_straight_curve(*curve_it1); - bool 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; - counter++; - if (curve_it2 != curve_endit) { - ++curve_it2; - } - 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_chamfer_steps(int value_chamfer_steps) -{ - chamfer_steps = value_chamfer_steps; -} - -void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) -{ - use_distance = use_knot_distance; -} - -void FilletChamferPointArrayParam::updateCanvasIndicators() -{ - std::vector<Point> ts = data(); - hp.clear(); - unsigned int i = 0; - for (std::vector<Point>::const_iterator point_it = ts.begin(); - point_it != ts.end(); ++point_it) { - double Xvalue = to_time(i, (*point_it)[X]) -i; - if (Xvalue == 0) { - i++; - continue; - } - Geom::Point ptA = last_pwd2[i].valueAt(Xvalue); - Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue)); - Geom::Rotate rot(Geom::Rotate::from_degrees(-90)); - derivA = derivA * rot; - Geom::Point C = ptA - derivA * helper_size; - Geom::Point D = ptA + derivA * helper_size; - Geom::Ray ray1(C, D); - char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5"; - Geom::PathVector pathv = sp_svg_read_pathv(svgd); - Geom::Affine aff = Geom::Affine(); - aff *= Geom::Scale(helper_size); - aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270)); - aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue)); - pathv *= aff; - hp.push_back(pathv[0]); - hp.push_back(pathv[1]); - i++; - } -} - -void FilletChamferPointArrayParam::addCanvasIndicators( - SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) -{ - hp_vec.push_back(hp); -} - -double FilletChamferPointArrayParam::rad_to_len(int index, double rad) -{ - double len = 0; - Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - D2<SBasis> A = last_pwd2[last_index(index, subpaths)]; - if(positions.second != 0){ - A = last_pwd2[index-1]; - }else{ - if(!subpaths[positions.first].closed()){ - return len; - } - } - D2<SBasis> B = last_pwd2[index]; - Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad); - Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad); - Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; - Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; - Geom::Crossings cs = Geom::crossings(p0, p1); - if(cs.size() > 0){ - Point cp =p0(cs[0].ta); - double p0pt = nearest_time(cp, B); - len = time_to_len(index,p0pt); - } else { - if(rad < 0){ - len = rad_to_len(index, rad * -1); - } - } - return len; -} - -double FilletChamferPointArrayParam::len_to_rad(int index, double len) -{ - double rad = 0; - double tmp_len = _vector[index][X]; - _vector[index] = Geom::Point(len,_vector[index][Y]); - Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - Piecewise<D2<SBasis> > u; - u.push_cut(0); - u.push(last_pwd2[last_index(index, subpaths)], 1); - Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); - Geom::Curve * B = subpaths[positions.first][positions.second].duplicate(); - std::vector<double> times; - if(positions.second != 0){ - A = subpaths[positions.first][positions.second-1].duplicate(); - times = get_times(index-1, subpaths, false); - }else{ - if(!subpaths[positions.first].closed()){ - return rad; - } - times = get_times(last_index(index, subpaths), subpaths, true); - } - _vector[index] = Geom::Point(tmp_len,_vector[index][Y]); - Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]); - Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]); - Curve *knotCurve1 = A->portion(times[0], times[1]); - Curve *knotCurve2 = B->portion(times[2], 1); - Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1); - Ray ray1(startArcPoint, A->finalPoint()); - if (cubic1) { - ray1.setPoints((*cubic1)[2], startArcPoint); - } - Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2); - Ray ray2(B->initialPoint(), endArcPoint); - if (cubic2) { - ray2.setPoints(endArcPoint, (*cubic2)[1]); - } - bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0; - double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint)); - double angleBetween = angle_between(ray1, ray2, ccwToggle); - rad = distanceArc/sin(angleBetween/2.0); - return rad * -1; -} - -std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last) -{ - const double tolerance = 0.001; - const double gapHelper = 0.00001; - std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); - Curve *curve_it1; - curve_it1 = subpaths[positions.first][positions.second].duplicate(); - Coord it1_length = (*curve_it1).length(tolerance); - double time_it1, time_it2, time_it1_B, intpart; - if (static_cast<int>(_vector.size()) <= index){ - std::vector<double> out; - out.push_back(0); - out.push_back(1); - out.push_back(0); - return out; - } - time_it1 = modf(to_time(index, _vector[index][X]), &intpart); - if (_vector[index][Y] == 0) { - time_it1 = 0; - } - double resultLenght = 0; - if (subpaths[positions.first].closed() && last) { - time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart); - resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]); - } else if (!subpaths[positions.first].closed() && last){ - time_it2 = 0; - resultLenght = 0; - } else { - time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart); - resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]); - } - if (resultLenght > 0 && time_it2 != 0) { - time_it1_B = modf(to_time(index, -resultLenght), &intpart); - } else { - if (time_it2 == 0) { - time_it1_B = 1; - } else { - time_it1_B = gapHelper; - } - } - - if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) { - time_it1_B = 1; - time_it2 = 0; - } - if (time_it1_B < time_it1) { - time_it1_B = time_it1 + gapHelper; - } - std::vector<double> out; - out.push_back(time_it1); - out.push_back(time_it1_B); - out.push_back(time_it2); - return out; -} - -std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths) -{ - int counter = -1; - std::size_t first = 0; - std::size_t second = 0; - for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { - if (path_it->empty()) - continue; - Geom::Path::const_iterator curve_it1 = 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(); - } - } - first++; - second = 0; - while (curve_it1 != curve_endit) { - counter++; - second++; - if(counter == index){ - break; - } - ++curve_it1; - } - if(counter == index){ - break; - } - } - first--; - second--; - std::pair<std::size_t, std::size_t> out(first, second); - return out; -} - -int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths) -{ - int counter = -1; - bool inSubpath = false; - for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { - if (path_it->empty()) - continue; - Geom::Path::const_iterator curve_it1 = 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(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - while (curve_it1 != curve_endit) { - counter++; - if(counter == index){ - inSubpath = true; - } - ++curve_it1; - } - if(inSubpath){ - break; - } - } - if(!inSubpath){ - counter = -1; - } - return counter; -} - - -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; -} - -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; - } - Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2(); - double t = nearest_time(p, pwd2[_index]); - Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state); - t = nearest_time(s, 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) { - if (state & GDK_MOD1_MASK) { - _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]); - _pparam->param_set_and_write_new_value(_pparam->_vector); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); - }else{ - using namespace Geom; - int type = (int)_pparam->_vector.at(_index)[Y]; - if (type >=3000 && type < 4000){ - type = 3; - } - if (type >=4000 && type < 5000){ - type = 4; - } - switch(type){ - case 1: - type = 2; - break; - case 2: - type = _pparam->chamfer_steps + 3000; - break; - case 3: - type = _pparam->chamfer_steps + 4000; - break; - default: - type = 1; - break; - } - _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)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 >=3000 && type < 4000){ - tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (type >=4000 && type < 5000) { - tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (type == 2) { - tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else { - tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } - this->knot->tip = g_strdup(tip); - this->knot->show(); - } - } else if (state & GDK_SHIFT_MASK) { - double xModified = _pparam->_vector.at(_index).x(); - if(xModified < 0 && !_pparam->use_distance){ - xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x()); - } - Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); - std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths); - D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)]; - if(positions.second != 0){ - A = _pparam->last_pwd2[_index-1]; - } - D2<SBasis> B = _pparam->last_pwd2[_index]; - bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; - Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); - Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->use_distance, aprox); - } - -} - -void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( - Geom::Point offset) -{ - double xModified = offset.x(); - if(xModified < 0 && !_pparam->use_distance){ - xModified = _pparam->rad_to_len(_index, offset.x()); - } - _pparam->_vector.at(_index) = Geom::Point(xModified, 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] >=3000 && _vector[i][Y] < 4000){ - tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) { - tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else if (_vector[i][Y] == 2) { - tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } else { - tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggle type, " - "<b>Shift+Click</b> open dialog, " - "<b>Ctrl+Alt+Click</b> reset"); - } - 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 deleted file mode 100644 index 48cd26d2d..000000000 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ /dev/null @@ -1,123 +0,0 @@ -#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 rad_to_len(int index, double rad); - virtual double len_to_rad(int index, double len); - virtual double len_to_time(int index, double len); - virtual double time_to_len(int index, double time); - virtual std::pair<std::size_t, std::size_t> get_positions(int index, Geom::PathVector subpaths); - virtual int last_index(int index, Geom::PathVector subpaths); - std::vector<double> get_times(int index, Geom::PathVector subpaths, bool last); - virtual void set_helper_size(int hs); - virtual void set_use_distance(bool use_knot_distance); - virtual void set_chamfer_steps(int value_chamfer_steps); - 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; - int chamfer_steps; - bool use_distance; - 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_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/fontbutton.cpp b/src/live_effects/parameter/fontbutton.cpp new file mode 100644 index 000000000..ca8908f0e --- /dev/null +++ b/src/live_effects/parameter/fontbutton.cpp @@ -0,0 +1,97 @@ +/* + * Authors: + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtkmm.h> +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/fontbutton.h" +#include "live_effects/effect.h" +#include "ui/widget/font-button.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "verbs.h" + +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +FontButtonParam::FontButtonParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const Glib::ustring default_value ) + : Parameter(label, tip, key, wr, effect), + value(default_value), + defvalue(default_value) +{ +} + +void +FontButtonParam::param_set_default() +{ + param_setValue(defvalue); +} + +void +FontButtonParam::param_update_default(const gchar * default_value) +{ + defvalue = (Glib::ustring)strdup(default_value); +} + +bool +FontButtonParam::param_readSVGValue(const gchar * strvalue) +{ + Inkscape::SVGOStringStream os; + os << strvalue; + param_setValue((Glib::ustring)os.str()); + return true; +} + +gchar * +FontButtonParam::param_getSVGValue() const +{ + return g_strdup(value.c_str()); +} + +Gtk::Widget * +FontButtonParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredFontButton * fontbuttonwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredFontButton( param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() ) ); + Glib::ustring fontspec = param_getSVGValue(); + fontbuttonwdg->setValue( fontspec); + fontbuttonwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change font button parameter")); + return dynamic_cast<Gtk::Widget *> (fontbuttonwdg); +} + +void +FontButtonParam::param_setValue(const Glib::ustring newvalue) +{ + if (value != newvalue) { + param_effect->upd_params = true; + } + value = newvalue; +} + + +} /* 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/fontbutton.h b/src/live_effects/parameter/fontbutton.h new file mode 100644 index 000000000..60e1aa46e --- /dev/null +++ b/src/live_effects/parameter/fontbutton.h @@ -0,0 +1,61 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H + +/* + * Inkscape::LivePathEffectParameters + * + * Authors: + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include <glib.h> +#include "live_effects/parameter/parameter.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class FontButtonParam : public Parameter { +public: + FontButtonParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const Glib::ustring default_value = "Sans 10"); + virtual ~FontButtonParam() {} + + virtual Gtk::Widget * param_newWidget(); + virtual bool param_readSVGValue(const gchar * strvalue); + void param_update_default(const gchar * default_value); + virtual gchar * param_getSVGValue() const; + + void param_setValue(Glib::ustring newvalue); + + virtual void param_set_default(); + + const Glib::ustring get_value() const { return defvalue; }; + +private: + FontButtonParam(const FontButtonParam&); + FontButtonParam& operator=(const FontButtonParam&); + Glib::ustring value; + Glib::ustring defvalue; + +}; + +} //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/parameter/hidden.cpp b/src/live_effects/parameter/hidden.cpp new file mode 100644 index 000000000..e8c55ebd3 --- /dev/null +++ b/src/live_effects/parameter/hidden.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) jabiertxof 2017 <jabier.arraiza@marker.es> + * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com> + * + * Authors: + * Jabiertxof + * Maximilian Albert + * Johan Engelen + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + + +#include "live_effects/parameter/hidden.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" + +namespace Inkscape { + +namespace LivePathEffect { + +HiddenParam::HiddenParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const Glib::ustring default_value, bool is_visible) + : Parameter(label, tip, key, wr, effect), + value(default_value), + defvalue(default_value) +{ + param_widget_is_visible(is_visible); +} + +void +HiddenParam::param_set_default() +{ + param_setValue(defvalue); +} + +void +HiddenParam::param_update_default(const gchar * default_value) +{ + defvalue = (Glib::ustring)default_value; +} + + +bool +HiddenParam::param_readSVGValue(const gchar * strvalue) +{ + param_setValue(strvalue); + return true; +} + +gchar * +HiddenParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + os << value; + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +Gtk::Widget * +HiddenParam::param_newWidget() +{ + return NULL; +} + +void +HiddenParam::param_setValue(const Glib::ustring newvalue, bool write) +{ + value = newvalue; + if (write) { + param_write_to_repr(value.c_str()); + } +} + +} /* 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/hidden.h b/src/live_effects/parameter/hidden.h new file mode 100644 index 000000000..c3fba5575 --- /dev/null +++ b/src/live_effects/parameter/hidden.h @@ -0,0 +1,69 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_HIDDEN_H +#define INKSCAPE_LIVEPATHEFFECT_HIDDEN_H + +/* + * Inkscape::LivePathEffectParameters + * + * Authors: + * Jabiertxof + * Maximilian Albert + * Johan Engelen + * + * Copyright (C) jabiertxof 2017 <jabier.arraiza@marker.es> + * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/parameter.h" + + +namespace Inkscape { + +namespace LivePathEffect { + +class HiddenParam : public Parameter { +public: + HiddenParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const Glib::ustring default_value = "", + bool widget_is_visible = false); + virtual ~HiddenParam() {} + + virtual Gtk::Widget * param_newWidget(); + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + void param_setValue(Glib::ustring newvalue, bool write = false); + virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); + + const Glib::ustring get_value() const { return value; }; + +private: + HiddenParam(const HiddenParam&); + HiddenParam& operator=(const HiddenParam&); + Glib::ustring value; + Glib::ustring defvalue; +}; + +} //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/parameter/item-reference.cpp b/src/live_effects/parameter/item-reference.cpp new file mode 100644 index 000000000..a775d93b7 --- /dev/null +++ b/src/live_effects/parameter/item-reference.cpp @@ -0,0 +1,44 @@ +/* + * The reference corresponding to href of LPE Item parameter. + * + * Copyright (C) 2008 Johan Engelen + * + * Released under GNU GPL, read the file 'COPYING' for more information. + */ + +#include "live_effects/parameter/item-reference.h" + +#include "sp-shape.h" +#include "sp-text.h" +#include "sp-item-group.h" + +namespace Inkscape { +namespace LivePathEffect { + +bool ItemReference::_acceptObject(SPObject * const obj) const +{ + if (SP_IS_SHAPE(obj) || SP_IS_TEXT(obj) || SP_IS_GROUP(obj)) { + /* Refuse references to lpeobject */ + if (obj == getOwner()) { + return false; + } + // TODO: check whether the referred item has this LPE applied, if so: deny deny deny! + return URIReference::_acceptObject(obj); + } else { + return false; + } +} + +} // 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/item-reference.h b/src/live_effects/parameter/item-reference.h new file mode 100644 index 000000000..91231455a --- /dev/null +++ b/src/live_effects/parameter/item-reference.h @@ -0,0 +1,56 @@ +#ifndef SEEN_LPE_ITEM_REFERENCE_H +#define SEEN_LPE_ITEM_REFERENCE_H + +/* + * Copyright (C) 2008-2012 Authors + * Authors: Johan Engelen + * Abhishek Sharma + * + * Released under GNU GPL, read the file 'COPYING' for more information. + */ + +#include <uri-references.h> + +class SPItem; +namespace Inkscape { +namespace XML { class Node; } + +namespace LivePathEffect { + +/** + * The reference corresponding to href of LPE ItemParam. + */ +class ItemReference : public Inkscape::URIReference { +public: + ItemReference(SPObject *owner) : URIReference(owner) {} + + SPItem *getObject() const { + return (SPItem *)URIReference::getObject(); + } + +protected: + virtual bool _acceptObject(SPObject * const obj) const; + +private: + ItemReference(const ItemReference&); + ItemReference& operator=(const ItemReference&); +}; + +} // namespace LivePathEffect + +} // namespace Inkscape + + + +#endif /* !SEEN_LPE_PATH_REFERENCE_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 : diff --git a/src/live_effects/parameter/item.cpp b/src/live_effects/parameter/item.cpp new file mode 100644 index 000000000..7b40f4540 --- /dev/null +++ b/src/live_effects/parameter/item.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Abhishek Sharma + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/item.h" + +#include <glibmm/i18n.h> + +#include <gtkmm/button.h> +#include <gtkmm/label.h> + +#include "bad-uri-exception.h" +#include "ui/widget/point.h" + +#include "live_effects/effect.h" +#include "svg/svg.h" + +#include "widgets/icon.h" +#include "selection-chemistry.h" +#include "xml/repr.h" +#include "desktop.h" +#include "inkscape.h" +#include "message-stack.h" + +// clipboard support +#include "ui/clipboard.h" +// required for linking to other paths +#include "uri.h" + +#include "ui/icon-names.h" + +namespace Inkscape { + +namespace LivePathEffect { + +ItemParam::ItemParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const gchar * default_value) + : Parameter(label, tip, key, wr, effect), + changed(true), + href(NULL), + ref( (SPObject*)effect->getLPEObj() ) +{ + defvalue = g_strdup(default_value); + ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &ItemParam::ref_changed)); +} + +ItemParam::~ItemParam() +{ + remove_link(); + g_free(defvalue); +} + +void +ItemParam::param_set_default() +{ + param_readSVGValue(defvalue); +} + +void +ItemParam::param_update_default(const gchar * default_value){ + defvalue = strdup(default_value); +} + +void +ItemParam::param_set_and_write_default() +{ + param_write_to_repr(defvalue); +} + +bool +ItemParam::param_readSVGValue(const gchar * strvalue) +{ + if (strvalue) { + remove_link(); + if (strvalue[0] == '#') { + if (href) + g_free(href); + href = g_strdup(strvalue); + try { + ref.attach(Inkscape::URI(href)); + //lp:1299948 + SPItem* i = ref.getObject(); + if (i) { + linked_modified_callback(i, SP_OBJECT_MODIFIED_FLAG); + } // else: document still processing new events. Repr of the linked object not created yet. + } catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + ref.detach(); + } + } + emit_changed(); + return true; + } + + return false; +} + +gchar * +ItemParam::param_getSVGValue() const +{ + return g_strdup(href); +} + +Gtk::Widget * +ItemParam::param_newWidget() +{ + Gtk::HBox * _widget = Gtk::manage(new Gtk::HBox()); + Gtk::Widget* pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button * pButton = Gtk::manage(new Gtk::Button()); + Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true); + pLabel->set_tooltip_text(param_tooltip); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &ItemParam::on_link_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Link to item on clipboard")); + + static_cast<Gtk::HBox*>(_widget)->show_all_children(); + + return dynamic_cast<Gtk::Widget *> (_widget); +} + +void +ItemParam::emit_changed() +{ + changed = true; + signal_item_changed.emit(); +} + + +void +ItemParam::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ +} + + +void +ItemParam::start_listening(SPObject * to) +{ + if ( to == NULL ) { + return; + } + linked_delete_connection = to->connectDelete(sigc::mem_fun(*this, &ItemParam::linked_delete)); + linked_modified_connection = to->connectModified(sigc::mem_fun(*this, &ItemParam::linked_modified)); + if (SP_IS_ITEM(to)) { + linked_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::mem_fun(*this, &ItemParam::linked_transformed)); + } + linked_modified(to, SP_OBJECT_MODIFIED_FLAG); // simulate linked_modified signal, so that path data is updated +} + +void +ItemParam::quit_listening(void) +{ + linked_modified_connection.disconnect(); + linked_delete_connection.disconnect(); + linked_transformed_connection.disconnect(); +} + +void +ItemParam::ref_changed(SPObject */*old_ref*/, SPObject *new_ref) +{ + quit_listening(); + if ( new_ref ) { + start_listening(new_ref); + } +} + +void +ItemParam::remove_link() +{ + if (href) { + ref.detach(); + g_free(href); + href = NULL; + } +} + +void +ItemParam::linked_delete(SPObject */*deleted*/) +{ + quit_listening(); + remove_link(); +} + +void ItemParam::linked_modified(SPObject *linked_obj, guint flags) +{ + linked_modified_callback(linked_obj, flags); +} + +void ItemParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item) +{ + linked_transformed_callback(rel_transf, moved_item); +} + +void +ItemParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) +{ + emit_changed(); + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); +} + +void +ItemParam::on_link_button_click() +{ + Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); + const gchar * iid = cm->getFirstObjectID(); + if (!iid) { + return; + } + + Glib::ustring itemid(iid); + + if (itemid.empty()) { + return; + } + + // add '#' at start to make it an uri. + itemid.insert(itemid.begin(), '#'); + if ( href && strcmp(itemid.c_str(), href) == 0 ) { + // no change, do nothing + return; + } else { + // TODO: + // check if id really exists in document, or only in clipboard document: if only in clipboard then invalid + // check if linking to object to which LPE is applied (maybe delegated to PathReference + + param_write_to_repr(itemid.c_str()); + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Link item parameter to path")); + } +} + +} /* 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/item.h b/src/live_effects/parameter/item.h new file mode 100644 index 000000000..89c32f9bd --- /dev/null +++ b/src/live_effects/parameter/item.h @@ -0,0 +1,80 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ITEM_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ITEM_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> + + +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/item-reference.h" +#include <stddef.h> +#include <sigc++/sigc++.h> + +namespace Inkscape { + +namespace LivePathEffect { + +class ItemParam : public Parameter { +public: + ItemParam ( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const gchar * default_value = ""); + virtual ~ItemParam(); + virtual Gtk::Widget * param_newWidget(); + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); + void param_set_and_write_default(); + virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec); + + sigc::signal <void> signal_item_pasted; + sigc::signal <void> signal_item_changed; + bool changed; /* this gets set whenever the path is changed (this is set to true, and then the signal_item_changed signal is emitted). + * the user must set it back to false if she wants to use it sensibly */ +protected: + + gchar * href; // contains link to other object, e.g. "#path2428", NULL if ItemParam contains pathdata itself + ItemReference ref; + sigc::connection ref_changed_connection; + sigc::connection linked_delete_connection; + sigc::connection linked_modified_connection; + sigc::connection linked_transformed_connection; + void ref_changed(SPObject *old_ref, SPObject *new_ref); + void remove_link(); + void start_listening(SPObject * to); + void quit_listening(void); + void linked_delete(SPObject *deleted); + void linked_modified(SPObject *linked_obj, guint flags); + void linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item); + virtual void linked_modified_callback(SPObject *linked_obj, guint flags); + virtual void linked_transformed_callback(Geom::Affine const * /*rel_transf*/, SPItem * /*moved_item*/) {}; + void on_link_button_click(); + + void emit_changed(); + + gchar * defvalue; + +private: + ItemParam(const ItemParam&); + ItemParam& operator=(const ItemParam&); +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/originalitem.cpp b/src/live_effects/parameter/originalitem.cpp new file mode 100644 index 000000000..053062128 --- /dev/null +++ b/src/live_effects/parameter/originalitem.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) Johan Engelen 2012 <j.b.c.engelen@alumnus.utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtkmm/box.h> +#include "live_effects/parameter/originalitem.h" + +#include "widgets/icon.h" +#include <glibmm/i18n.h> +#include <gtkmm/button.h> +#include <gtkmm/label.h> + +#include "uri.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "display/curve.h" +#include "live_effects/effect.h" + +#include "inkscape.h" +#include "desktop.h" +#include "selection.h" +#include "ui/icon-names.h" + +namespace Inkscape { + +namespace LivePathEffect { + +OriginalItemParam::OriginalItemParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect) + : ItemParam(label, tip, key, wr, effect, "") +{ +} + +OriginalItemParam::~OriginalItemParam() +{ + +} + +Gtk::Widget * +OriginalItemParam::param_newWidget() +{ + Gtk::HBox *_widget = Gtk::manage(new Gtk::HBox()); + + { // Label + Gtk::Label *pLabel = Gtk::manage(new Gtk::Label(param_label)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true); + pLabel->set_tooltip_text(param_tooltip); + } + + { // Paste item to link button + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalItemParam::on_link_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Link to item")); + } + + { // Select original button + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("edit-select-original", Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalItemParam::on_select_original_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Select original")); + } + + static_cast<Gtk::HBox*>(_widget)->show_all_children(); + + return dynamic_cast<Gtk::Widget *> (_widget); +} + +void +OriginalItemParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) +{ + if (!inverse) { + emit_changed(); + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); + } +} + +void +OriginalItemParam::linked_transformed_callback(Geom::Affine const * /*rel_transf*/, SPItem * /*moved_item*/) +{ +/** \todo find good way to compensate for referenced item transform, like done for normal clones. + * See sp-use.cpp: sp_use_move_compensate */ +} + + +void +OriginalItemParam::on_select_original_button_click() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPItem *original = ref.getObject(); + if (desktop == NULL || original == NULL) { + return; + } + Inkscape::Selection *selection = desktop->getSelection(); + selection->clear(); + selection->set(original); +} + +} /* 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/originalitem.h b/src/live_effects/parameter/originalitem.h new file mode 100644 index 000000000..58d04e05a --- /dev/null +++ b/src/live_effects/parameter/originalitem.h @@ -0,0 +1,49 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINAL_ITEM_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINAL_ITEM_H + +/* + * Inkscape::LiveItemEffectParameters + * +* Copyright (C) Johan Engelen 2012 <j.b.c.engelen@alumnus.utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/item.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class OriginalItemParam: public ItemParam { +public: + OriginalItemParam ( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect); + virtual ~OriginalItemParam(); + void setInverse(bool inversed) { inverse = inversed; } + bool linksToItem() const { return (href != NULL); } + SPItem * getObject() const { return ref.getObject(); } + + virtual Gtk::Widget * param_newWidget(); + +protected: + virtual void linked_modified_callback(SPObject *linked_obj, guint flags); + virtual void linked_transformed_callback(Geom::Affine const *rel_transf, SPItem *moved_item); + + void on_select_original_button_click(); + +private: + bool inverse; + OriginalItemParam(const OriginalItemParam&); + OriginalItemParam& operator=(const OriginalItemParam&); +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/originalpath.cpp b/src/live_effects/parameter/originalpath.cpp index 2741461be..1e78f7fe1 100644 --- a/src/live_effects/parameter/originalpath.cpp +++ b/src/live_effects/parameter/originalpath.cpp @@ -56,7 +56,7 @@ OriginalPathParam::param_newWidget() } { // Paste path to link button - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); @@ -89,7 +89,7 @@ OriginalPathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags* { SPCurve *curve = NULL; if (SP_IS_SHAPE(linked_obj)) { - curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); + curve = SP_SHAPE(linked_obj)->getCurve(); } if (SP_IS_TEXT(linked_obj)) { curve = SP_TEXT(linked_obj)->getNormalizedBpath(); diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 4ee068ebf..693821ed2 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -144,7 +144,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() { // Paste path to link button - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("gtk-stock", Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("edit-clone", Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); @@ -386,7 +386,7 @@ void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint /*flags*/ } SPCurve *curve = NULL; if (SP_IS_SHAPE(linked_obj)) { - curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); + curve = SP_SHAPE(linked_obj)->getCurve(); } if (SP_IS_TEXT(linked_obj)) { curve = SP_TEXT(linked_obj)->getNormalizedBpath(); diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 296c0f7f7..fe9371644 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -65,12 +65,11 @@ public: virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; virtual void param_set_default(); - + virtual void param_update_default(const gchar * default_value){}; /** Disable the canvas indicators of parent class by overriding this method */ virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; /** Disable the canvas indicators of parent class by overriding this method */ virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector<Geom::PathVector> & /*hp_vec*/) {}; - std::vector<PathAndDirection*> _vector; protected: diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index d4e213948..2f73488aa 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -4,11 +4,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/widget/registered-widget.h" -#include <glibmm/i18n.h> -#include "live_effects/parameter/parameter.h" #include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" #include "svg/svg.h" #include "xml/repr.h" @@ -16,6 +14,8 @@ #include "verbs.h" +#include <glibmm/i18n.h> + #define noLPEREALPARAM_DEBUG namespace Inkscape { @@ -39,6 +39,7 @@ Parameter::Parameter( const Glib::ustring& label, const Glib::ustring& tip, void Parameter::param_write_to_repr(const char * svgd) { + param_effect->upd_params = true; param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } @@ -54,7 +55,7 @@ void Parameter::write_to_SVG(void) */ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, gdouble default_value, bool no_widget) + Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), min(-SCALARPARAM_G_MAXDOUBLE), @@ -65,8 +66,7 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, inc_step(0.1), inc_page(1), add_slider(false), - overwrite_widget(false), - hide_widget(no_widget) + _set_undo(true) { } @@ -101,9 +101,28 @@ ScalarParam::param_set_default() param_set_value(defvalue); } +void +ScalarParam::param_update_default(gdouble default_value) +{ + defvalue = default_value; +} + +void +ScalarParam::param_update_default(const gchar * default_value) +{ + double newval; + unsigned int success = sp_svg_number_read_d(default_value, &newval); + if (success == 1) { + param_update_default(newval); + } +} + void ScalarParam::param_set_value(gdouble val) { + if (value != val) { + param_effect->upd_params = true; + } value = val; if (integer) value = round(value); @@ -121,7 +140,6 @@ ScalarParam::param_set_range(gdouble min, gdouble max) // 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 { @@ -130,9 +148,8 @@ ScalarParam::param_set_range(gdouble min, gdouble max) if (max <= SCALARPARAM_G_MAXDOUBLE) { this->max = max; } else { - this->max = SCALARPARAM_G_MAXDOUBLE; + this->max = SCALARPARAM_G_MAXDOUBLE; } - param_set_value(value); // reset value to see whether it is in ranges } @@ -146,15 +163,15 @@ ScalarParam::param_make_integer(bool yes) } void -ScalarParam::param_overwrite_widget(bool overwrite_widget) +ScalarParam::param_set_undo(bool set_undo) { - this->overwrite_widget = overwrite_widget; + _set_undo = set_undo; } Gtk::Widget * ScalarParam::param_newWidget() { - if(!hide_widget){ + if(widget_is_visible){ Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); @@ -166,7 +183,7 @@ ScalarParam::param_newWidget() if (add_slider) { rsu->addSlider(); } - if(!overwrite_widget){ + if(_set_undo){ rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } return dynamic_cast<Gtk::Widget *> (rsu); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 0ef28650a..7ab7e30dd 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -12,6 +12,7 @@ #include <glibmm/ustring.h> #include <2geom/forward.h> #include <2geom/pathvector.h> +#include "ui/widget/registered-widget.h" // In gtk2, this wasn't an issue; we could toss around // G_MAXDOUBLE and not worry about size allocations. But @@ -56,10 +57,11 @@ public: virtual bool param_readSVGValue(const gchar * strvalue) = 0; // returns true if new value is valid / accepted. virtual gchar * param_getSVGValue() const = 0; + virtual void param_widget_is_visible(bool is_visible) {widget_is_visible = is_visible;} void write_to_SVG(); virtual void param_set_default() = 0; - + virtual void param_update_default(const gchar * default_value) = 0; // This creates a new widget (newed with Gtk::manage(new ...);) virtual Gtk::Widget * param_newWidget() = 0; @@ -67,7 +69,7 @@ public: // overload these for your particular parameter to make it provide knotholder handles or canvas helperpaths virtual bool providesKnotHolderEntities() const { return false; } - virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPDesktop */*desktop*/, SPItem */*item*/) {}; + virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPItem */*item*/) {}; virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/) {}; virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; @@ -76,6 +78,7 @@ public: virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) {}; Glib::ustring param_key; + Glib::ustring param_tooltip; Inkscape::UI::Widget::Registry * param_wr; Glib::ustring param_label; @@ -83,7 +86,6 @@ public: bool widget_is_visible; protected: - Glib::ustring param_tooltip; Effect* param_effect; @@ -102,23 +104,24 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - gdouble default_value = 1.0, - bool no_widget = false); + gdouble default_value = 1.0); virtual ~ScalarParam(); virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; virtual void param_set_default(); + void param_update_default(gdouble default_value); + virtual void param_update_default(const gchar * default_value); void param_set_value(gdouble val); void param_make_integer(bool yes = true); void param_set_range(gdouble min, gdouble max); void param_set_digits(unsigned digits); void param_set_increments(double step, double page); - void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; }; - - void param_overwrite_widget(bool overwrite_widget); + double param_get_max() { return max; }; + double param_get_min() { return min; }; + void param_set_undo(bool set_undo); virtual Gtk::Widget * param_newWidget(); inline operator gdouble() const { return value; }; @@ -133,8 +136,7 @@ protected: double inc_step; double inc_page; bool add_slider; - bool overwrite_widget; - bool hide_widget; + bool _set_undo; private: ScalarParam(const ScalarParam&); diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index bed191e83..54f5d93e8 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -5,10 +5,16 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/widget/point.h" +#include "live_effects/parameter/path.h" + #include <glibmm/i18n.h> -#include "live_effects/parameter/path.h" +#include <gtkmm/button.h> +#include <gtkmm/label.h> + +#include "bad-uri-exception.h" +#include "ui/widget/point.h" + #include "live_effects/effect.h" #include "svg/svg.h" #include <2geom/svg-path-parser.h> @@ -17,7 +23,6 @@ #include <2geom/d2.h> #include "widgets/icon.h" -#include <gtk/gtk.h> #include "selection-chemistry.h" #include "xml/repr.h" #include "desktop.h" @@ -44,8 +49,6 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/shape-record.h" -#include <gtkmm/button.h> -#include <gtkmm/label.h> #include "ui/icon-names.h" namespace Inkscape { @@ -66,7 +69,10 @@ PathParam::PathParam( const Glib::ustring& label, const Glib::ustring& tip, defvalue = g_strdup(default_value); param_readSVGValue(defvalue); oncanvas_editable = true; - + _edit_button = true; + _copy_button = true; + _paste_button = true; + _link_button = true; ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &PathParam::ref_changed)); } @@ -164,6 +170,15 @@ PathParam::param_getSVGValue() const } } +void +PathParam::set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button) +{ + _edit_button = edit_button; + _copy_button = copy_button; + _paste_button = paste_button; + _link_button = link_button; +} + Gtk::Widget * PathParam::param_newWidget() { @@ -172,47 +187,55 @@ PathParam::param_newWidget() Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label)); static_cast<Gtk::HBox*>(_widget)->pack_start(*pLabel, true, true); pLabel->set_tooltip_text(param_tooltip); - - Gtk::Widget* pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) ); - Gtk::Button * pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click)); - static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Edit on-canvas")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click)); - static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Copy path")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click)); - static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Paste path")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); - static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Link to path on clipboard")); - + Gtk::Widget * pIcon = NULL; + Gtk::Button * pButton = NULL; + if (_edit_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Edit on-canvas")); + } + + if (_copy_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Copy path")); + } + + if (_paste_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Paste path")); + } + if (_link_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); + static_cast<Gtk::HBox*>(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Link to path on clipboard")); + } + static_cast<Gtk::HBox*>(_widget)->show_all_children(); return dynamic_cast<Gtk::Widget *> (_widget); @@ -237,14 +260,14 @@ PathParam::param_editOncanvas(SPItem *item, SPDesktop * dt) r.role = SHAPE_ROLE_LPE_PARAM; r.edit_transform = item->i2dt_affine(); // TODO is it right? - r.edit_transform *= item->transform.inverse(); if (!href) { r.item = reinterpret_cast<SPItem*>(param_effect->getLPEObj()); r.lpe_key = param_key; Geom::PathVector stored_pv = _pathvector; param_write_to_repr("M0,0 L1,0"); - const char *svgd = sp_svg_write_path(stored_pv); + gchar *svgd = sp_svg_write_path(stored_pv); param_write_to_repr(svgd); + g_free(svgd); } else { r.item = ref.getObject(); } @@ -437,6 +460,10 @@ PathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); } +void +PathParam::param_update_default(const gchar * default_value){ + defvalue = strdup(default_value); +} /* CALLBACK FUNCTIONS FOR THE BUTTONS */ void @@ -458,8 +485,7 @@ PathParam::paste_param_path(const char *svgd) SPItem * item = SP_ACTIVE_DESKTOP->getSelection()->singleItem(); if (item != NULL) { Geom::PathVector path_clipboard = sp_svg_read_pathv(svgd); - path_clipboard *= item->i2doc_affine().inverse() * item->transform; - path_clipboard *= Geom::Translate(path_clipboard.initialPoint() - _pathvector.initialPoint()).inverse(); + path_clipboard *= item->i2doc_affine().inverse(); svgd = sp_svg_write_path( path_clipboard ); } diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index d2dddbe97..ff5e4f1b8 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -40,10 +40,11 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); void param_set_and_write_default(); void set_new_value (Geom::PathVector const &newpath, bool write_to_svg); void set_new_value (Geom::Piecewise<Geom::D2<Geom::SBasis> > const &newpath, bool write_to_svg); - + void set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button); virtual void param_editOncanvas(SPItem * item, SPDesktop * dt); virtual void param_setup_nodepath(Inkscape::NodePath::Path *np); virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec); @@ -90,6 +91,10 @@ protected: gchar * defvalue; private: + bool _edit_button; + bool _copy_button; + bool _paste_button; + bool _link_button; PathParam(const PathParam&); PathParam& operator=(const PathParam&); }; diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index ca3471b29..4ca88a6b8 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -4,7 +4,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/widget/registered-widget.h" #include "live_effects/parameter/point.h" #include "live_effects/effect.h" #include "svg/svg.h" @@ -16,9 +15,6 @@ #include "knotholder.h" #include <glibmm/i18n.h> -// needed for on-canvas editting: -#include "desktop.h" - namespace Inkscape { namespace LivePathEffect { @@ -62,9 +58,22 @@ PointParam::param_get_default() const{ } void -PointParam::param_update_default(Geom::Point newpoint) +PointParam::param_update_default(Geom::Point default_point) { - defvalue = newpoint; + defvalue = default_point; +} + +void +PointParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } } void @@ -123,9 +132,8 @@ PointParam::param_newWidget() *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; - Geom::Affine transf = desktop->doc2dt(); + Geom::Affine transf = Geom::Scale(1, -1); + transf[5] = SP_ACTIVE_DOCUMENT->getHeight().value("px"); pointwdg->setTransform(transf); pointwdg->setValue( *this ); pointwdg->clearProgrammatically(); @@ -134,7 +142,6 @@ PointParam::param_newWidget() 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); } @@ -174,7 +181,7 @@ PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &or s = A; } } - pparam->param_setValue(s, this->pparam->liveupdate); + pparam->param_setValue(s); SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); if(splpeitem && this->pparam->liveupdate){ sp_lpe_item_update_patheffect(splpeitem, false, false); @@ -191,23 +198,23 @@ void PointParamKnotHolderEntity::knot_click(guint state) { if (state & GDK_CONTROL_MASK) { - if (state & GDK_MOD1_MASK) { - this->pparam->param_set_default(); - SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); - if(splpeitem){ - sp_lpe_item_update_patheffect(splpeitem, false, false); - } + if (state & GDK_MOD1_MASK) { + this->pparam->param_set_default(); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); } + } } } void -PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { knoth = knotholder; PointParamKnotHolderEntity *e = new PointParamKnotHolderEntity(this); // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); knotholder->add(e); } diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index 4329e0bcd..a5153ad80 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -11,7 +11,7 @@ #include <glib.h> #include <2geom/point.h> - +#include "ui/widget/registered-widget.h" #include "live_effects/parameter/parameter.h" #include "knot-holder-entity.h" @@ -43,14 +43,15 @@ public: void param_set_default(); Geom::Point param_get_default() const; void param_set_liveupdate(bool live_update); - void param_update_default(Geom::Point newpoint); + void param_update_default(Geom::Point default_point); + + virtual void param_update_default(const gchar * default_point); virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); virtual bool providesKnotHolderEntities() const { return true; } - virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); friend class PointParamKnotHolderEntity; private: PointParam(const PointParam&); diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index c61e8f9cb..7753d819d 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -248,11 +248,11 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) } } -void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { for (unsigned int i = 0; i < _vector.size(); ++i) { PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it, <b>Shift+click</b> launches width dialog."), knot_shape, knot_mode, knot_color); knotholder->add(e); diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index 70b22e27e..a34163ca1 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -38,14 +38,14 @@ public: float median_width(); virtual bool providesKnotHolderEntities() const { return true; } - virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); + virtual void param_update_default(const gchar * default_value){}; 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); - friend class PowerStrokePointArrayParamKnotHolderEntity; private: diff --git a/src/live_effects/parameter/random.cpp b/src/live_effects/parameter/random.cpp index 075e85ee1..b1375adda 100644 --- a/src/live_effects/parameter/random.cpp +++ b/src/live_effects/parameter/random.cpp @@ -78,8 +78,23 @@ RandomParam::param_set_default() } void +RandomParam::param_update_default(gdouble default_value){ + defvalue = default_value; +} + +void +RandomParam::param_update_default(const gchar * default_value){ + double newval; + unsigned int success = sp_svg_number_read_d(default_value, &newval); + if (success == 1) { + param_update_default(newval); + } +} + +void RandomParam::param_set_value(gdouble val, long newseed) { + param_effect->upd_params = true; value = val; if (integer) value = round(value); diff --git a/src/live_effects/parameter/random.h b/src/live_effects/parameter/random.h index ca4440336..5fb6027ac 100644 --- a/src/live_effects/parameter/random.h +++ b/src/live_effects/parameter/random.h @@ -38,9 +38,9 @@ public: void param_set_value(gdouble val, long newseed); void param_make_integer(bool yes = true); void param_set_range(gdouble min, gdouble max); - + void param_update_default(gdouble default_value); + virtual void param_update_default(const gchar * default_value); void resetRandomizer(); - operator gdouble(); inline gdouble get_value() { return value; } ; diff --git a/src/live_effects/parameter/satellitesarray.cpp b/src/live_effects/parameter/satellitesarray.cpp new file mode 100644 index 000000000..ce4da243e --- /dev/null +++ b/src/live_effects/parameter/satellitesarray.cpp @@ -0,0 +1,584 @@ +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "knotholder.h" +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/satellitesarray.h" +#include "live_effects/effect.h" +#include "sp-lpe-item.h" +#include "inkscape.h" +#include <preferences.h> +// TODO due to internal breakage in glibmm headers, +// this has to be included last. +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label, + const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, + Effect *effect) + : ArrayParam<std::vector<Satellite> >(label, tip, key, wr, effect, 0), _knoth(NULL) +{ + _knot_shape = SP_KNOT_SHAPE_DIAMOND; + _knot_mode = SP_KNOT_MODE_XOR; + _knot_color = 0xAAFF8800; + _helper_size = 0; + _use_distance = false; + _global_knot_hide = false; + _current_zoom = 0; + _effectType = FILLET_CHAMFER; + _last_pathvector_satellites = NULL; + param_widget_is_visible(false); +} + + +void SatellitesArrayParam::set_oncanvas_looks(SPKnotShapeType shape, + SPKnotModeType mode, + guint32 color) +{ + _knot_shape = shape; + _knot_mode = mode; + _knot_color = color; +} + +void SatellitesArrayParam::setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write) +{ + _last_pathvector_satellites = pathVectorSatellites; + if (write) { + param_set_and_write_new_value(_last_pathvector_satellites->getSatellites()); + } else { + param_setValue(_last_pathvector_satellites->getSatellites()); + } +} + +void SatellitesArrayParam::setUseDistance(bool use_knot_distance) +{ + _use_distance = use_knot_distance; +} + +void SatellitesArrayParam::setCurrentZoom(double current_zoom) +{ + _current_zoom = current_zoom; +} + +void SatellitesArrayParam::setGlobalKnotHide(bool global_knot_hide) +{ + _global_knot_hide = global_knot_hide; +} +void SatellitesArrayParam::setEffectType(EffectType et) +{ + _effectType = et; +} + +void SatellitesArrayParam::setHelperSize(int hs) +{ + _helper_size = hs; + updateCanvasIndicators(); +} + +void SatellitesArrayParam::updateCanvasIndicators(bool mirror) +{ + if (!_last_pathvector_satellites) { + return; + } + + if (!_hp.empty()) { + _hp.clear(); + } + Geom::PathVector pathv = _last_pathvector_satellites->getPathVector(); + if (pathv.empty()) { + return; + } + if (mirror == true) { + _hp.clear(); + } + if (_effectType == FILLET_CHAMFER) { + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (_vector[i][j].hidden || //Ignore if hidden + (!_vector[i][j].has_mirror && mirror == true) || //Ignore if not have mirror and we are in mirror loop + _vector[i][j].amount == 0 || //no helper in 0 value + pathv[i].size() == j || //ignore last satellite in open paths with fillet chamfer effect + (!pathv[i].closed() && j == 0)) //ignore first satellites on open paths + { + continue; + } + Geom::Curve *curve_in = pathv[i][j].duplicate(); + double pos = 0; + bool overflow = false; + double size_out = _vector[i][j].arcDistance(*curve_in); + double lenght_out = curve_in->length(); + gint previous_index = j - 1; //Always are previous index because we skip first satellite on open paths + if (j == 0 && pathv[i].closed()) { + previous_index = pathv[i].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + double lenght_in = pathv.curveAt(previous_index).length(); + if (mirror) { + curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index)); + pos = _vector[i][j].time(size_out, true, *curve_in); + if (lenght_out < size_out) { + overflow = true; + } + } else { + pos = _vector[i][j].time(*curve_in); + if (lenght_in < size_out) { + overflow = true; + } + } + if (pos <= 0 || pos >= 1) { + continue; + } + Geom::Point point_a = curve_in->pointAt(pos); + Geom::Point deriv_a = unit_vector(derivative(curve_in->toSBasis()).pointAt(pos)); + Geom::Rotate rot(Geom::Rotate::from_degrees(-90)); + deriv_a = deriv_a * rot; + Geom::Point point_c = point_a - deriv_a * _helper_size; + Geom::Point point_d = point_a + deriv_a * _helper_size; + Geom::Ray ray_1(point_c, point_d); + char const *svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + Geom::Affine aff = Geom::Affine(); + aff *= Geom::Scale(_helper_size); + if (mirror) { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90)); + } else { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270)); + } + aff *= Geom::Translate(curve_in->pointAt(pos)); + pathv *= aff; + _hp.push_back(pathv[0]); + _hp.push_back(pathv[1]); + if (overflow) { + double diameter = _helper_size; + if (_helper_size == 0) { + diameter = 15; + char const *svgd; + svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 " + "0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + aff = Geom::Affine(); + aff *= Geom::Scale(diameter); + aff *= Geom::Translate(point_a - Geom::Point(diameter * 0.35, diameter * 0.35)); + pathv *= aff; + _hp.push_back(pathv[0]); + } else { + char const *svgd; + svgd = "M 0 -1.32 A 1.32 1.32 0 0 0 -1.32 0 A 1.32 1.32 0 0 0 0 1.32 A " + "1.32 1.32 0 0 0 1.18 0.59 L 0 0 L 1.18 -0.59 A 1.32 1.32 0 0 0 " + "0 -1.32 z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + aff = Geom::Affine(); + aff *= Geom::Scale(_helper_size / 2.0); + if (mirror) { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(90)); + } else { + aff *= Geom::Rotate(ray_1.angle() - Geom::rad_from_deg(270)); + } + aff *= Geom::Translate(curve_in->pointAt(pos)); + pathv *= aff; + _hp.push_back(pathv[0]); + } + } + } + } + } + if (!_knot_reset_helper.empty()) { + _hp.insert(_hp.end(), _knot_reset_helper.begin(), _knot_reset_helper.end() ); + } + if (mirror) { + updateCanvasIndicators(false); + } +} +void SatellitesArrayParam::updateCanvasIndicators() +{ + updateCanvasIndicators(true); +} + +void SatellitesArrayParam::addCanvasIndicators( + SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + hp_vec.push_back(_hp); +} + +void SatellitesArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if (prefs->getBool("/options/transform/rectcorners", true)) { + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (!_vector[i][j].is_time && _vector[i][j].amount > 0) { + _vector[i][j].amount = _vector[i][j].amount * ((postmul.expansionX() + postmul.expansionY()) / 2); + } + } + } + param_set_and_write_new_value(_vector); + } +} + +void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPItem *item, + bool mirror) +{ + if (!_last_pathvector_satellites) { + return; + } + Geom::PathVector pathv = _last_pathvector_satellites->getPathVector(); + size_t index = 0; + for (size_t i = 0; i < _vector.size(); ++i) { + for (size_t j = 0; j < _vector[i].size(); ++j) { + if (!_vector[i][j].has_mirror && mirror) { + continue; + } + SatelliteType type = _vector[i][j].satellite_type; + if (mirror && i == 0 && j == 0) { + index = index + _last_pathvector_satellites->getTotalSatellites(); + } + using namespace Geom; + //If is for filletChamfer effect... + if (_effectType == FILLET_CHAMFER) { + const gchar *tip; + if (type == CHAMFER) { + tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else if (type == INVERSE_CHAMFER) { + tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else if (type == INVERSE_FILLET) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } else { + tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> reset"); + } + FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index); + e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),_knot_shape, _knot_mode, _knot_color); + knotholder->add(e); + } + index++; + } + } + if (mirror) { + addKnotHolderEntities(knotholder, item, false); + } +} + +void SatellitesArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPItem *item) +{ + _knoth = knotholder; + addKnotHolderEntities(knotholder, item, true); +} + +FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity( + SatellitesArrayParam *p, size_t index) + : _pparam(p), _index(index) {} + +void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p, + Geom::Point const &/*origin*/, + guint state) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + + Geom::Point s = snap_knot_position(p, state); + if (!valid_index(path_index, curve_index)) { + return; + } + Satellite satellite = _pparam->_vector[path_index][curve_index]; + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + Geom::Curve const &curve_in = pathv[path_index][previous_index]; + double mirror_time = Geom::nearest_time(s, curve_in); + Geom::Point mirror = curve_in.pointAt(mirror_time); + double normal_time = Geom::nearest_time(s, pathv[path_index][curve_index]); + Geom::Point normal = pathv[path_index][curve_index].pointAt(normal_time); + double distance_mirror = Geom::distance(mirror,s); + double distance_normal = Geom::distance(normal,s); + if (Geom::are_near(s, pathv[path_index][curve_index].initialPoint(), 1.5 / _pparam->_current_zoom)) { + satellite.amount = 0; + } else if (distance_mirror < distance_normal) { + double time_start = 0; + Satellites satellites = _pparam->_last_pathvector_satellites->getSatellites(); + time_start = satellites[path_index][previous_index].time(curve_in); + if (time_start > mirror_time) { + mirror_time = time_start; + } + double size = arcLengthAt(mirror_time, curve_in); + double amount = curve_in.length() - size; + if (satellite.is_time) { + amount = timeAtArcLength(amount, pathv[path_index][curve_index]); + } + satellite.amount = amount; + } else { + satellite.setPosition(s, pathv[path_index][curve_index]); + } + _pparam->_knot_reset_helper.clear(); + if (satellite.amount == 0) { + char const *svgd; + svgd = "M -5.39,8.78 -9.13,5.29 -10.38,10.28 Z M -7.22,7.07 -3.43,3.37 m -1.95,-12.16 -3.74,3.5 -1.26,-5 z " + "m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z " + "M 7.07,7.07 3.29,3.37 M 5.24,-8.78 l 3.74,3.5 1.26,-5 z M 7.07,-7.07 3.29,-3.37"; + _pparam->_knot_reset_helper = sp_svg_read_pathv(svgd); + _pparam->_knot_reset_helper *= Geom::Affine(_pparam->_helper_size * 0.1,0,0,_pparam->_helper_size * 0.1,0,0) * Geom::Translate(pathv[path_index][curve_index].initialPoint()); + } + _pparam->_vector[path_index][curve_index] = satellite; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Geom::Point FilletChamferKnotHolderEntity::knot_get() const +{ + if (!_pparam->_last_pathvector_satellites || _pparam->_global_knot_hide) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Geom::Point tmp_point; + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Satellite satellite = _pparam->_vector[path_index][curve_index]; + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + this->knot->show(); + if (is_mirror) { + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return Geom::Point(Geom::infinity(), Geom::infinity()); + } + Geom::Curve const &curve_in = pathv[path_index][previous_index]; + double s = satellite.arcDistance(pathv[path_index][curve_index]); + double t = satellite.time(s, true, curve_in); + if (t > 1) { + t = 1; + } + if (t < 0) { + t = 0; + } + double time_start = 0; + time_start = _pparam->_last_pathvector_satellites->getSatellites()[path_index][previous_index].time(curve_in); + if (time_start > t) { + t = time_start; + } + tmp_point = (curve_in).pointAt(t); + } else { + tmp_point = satellite.getPosition(pathv[path_index][curve_index]); + } + Geom::Point const canvas_point = tmp_point; + _pparam->updateCanvasIndicators(); + return canvas_point; +} + +void FilletChamferKnotHolderEntity::knot_click(guint state) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return; + } + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if ((!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + if (state & GDK_CONTROL_MASK) { + if (state & GDK_MOD1_MASK) { + _pparam->_vector[path_index][curve_index].amount = 0.0; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + } else { + using namespace Geom; + SatelliteType type = _pparam->_vector[path_index][curve_index].satellite_type; + switch (type) { + case FILLET: + type = INVERSE_FILLET; + break; + case INVERSE_FILLET: + type = CHAMFER; + break; + case CHAMFER: + type = INVERSE_CHAMFER; + break; + default: + type = FILLET; + break; + } + _pparam->_vector[path_index][curve_index].satellite_type = type; + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + const gchar *tip; + if (type == CHAMFER) { + tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else if (type == INVERSE_CHAMFER) { + tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else if (type == INVERSE_FILLET) { + tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } else { + tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, " + "<b>Shift+Click</b> open dialog, " + "<b>Ctrl+Alt+Click</b> resets"); + } + this->knot->tip = g_strdup(tip); + this->knot->show(); + } + } else if (state & GDK_SHIFT_MASK) { + double amount = _pparam->_vector[path_index][curve_index].amount; + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + if (!_pparam->_use_distance && !_pparam->_vector[path_index][curve_index].is_time) { + amount = _pparam->_vector[path_index][curve_index].lenToRad(amount, pathv[path_index][previous_index], pathv[path_index][curve_index], _pparam->_vector[path_index][previous_index]); + } + bool aprox = false; + Geom::D2<Geom::SBasis> d2_out = pathv[path_index][curve_index].toSBasis(); + Geom::D2<Geom::SBasis> d2_in = pathv[path_index][previous_index].toSBasis(); + aprox = ((d2_in)[0].degreesOfFreedom() != 2 || + d2_out[0].degreesOfFreedom() != 2) && + !_pparam->_use_distance + ? true + : false; + Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( + this->desktop, amount, this, _pparam->_use_distance, + aprox, _pparam->_vector[path_index][curve_index]); + + } +} + +void FilletChamferKnotHolderEntity::knot_set_offset(Satellite satellite) +{ + if (!_pparam->_last_pathvector_satellites) { + return; + } + size_t total_satellites = _pparam->_last_pathvector_satellites->getTotalSatellites(); + bool is_mirror = false; + size_t index = _index; + if (_index >= total_satellites) { + index = _index - total_satellites; + is_mirror = true; + } + std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_satellites->getIndexData(index); + size_t path_index = index_data.first; + size_t curve_index = index_data.second; + if (!valid_index(path_index, curve_index)) { + return; + } + Geom::PathVector pathv = _pparam->_last_pathvector_satellites->getPathVector(); + if (satellite.hidden || + (!pathv[path_index].closed() && curve_index == 0) ||//ignore first satellites on open paths + pathv[path_index].size() == curve_index) //ignore last satellite in open paths with fillet chamfer effect + { + return; + } + double amount = satellite.amount; + double max_amount = amount; + if (!_pparam->_use_distance && !satellite.is_time) { + gint previous_index = curve_index - 1; + if (curve_index == 0 && pathv[path_index].closed()) { + previous_index = pathv[path_index].size() - 1; + } + if ( previous_index < 0 ) { + return; + } + amount = _pparam->_vector[path_index][curve_index].radToLen(amount, pathv[path_index][previous_index], pathv[path_index][curve_index]); + if (max_amount > 0 && amount == 0) { + amount = _pparam->_vector[path_index][curve_index].amount; + } + } + satellite.amount = amount; + _pparam->_vector[path_index][curve_index] = satellite; + this->parent_holder->knot_ungrabbed_handler(this->knot, 0); + SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item); + if (splpeitem) { + sp_lpe_item_update_patheffect(splpeitem, false, false); + } +} + +} /* 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/satellitesarray.h b/src/live_effects/parameter/satellitesarray.h new file mode 100644 index 000000000..5ae372ac2 --- /dev/null +++ b/src/live_effects/parameter/satellitesarray.h @@ -0,0 +1,114 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_SATELLITES_ARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_SATELLITES_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 + * To Nathan Hurst for his review and help on refactor + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * + * + * This parameter act as bridge from pathVectorSatellites class to serialize it as a LPE + * parameter + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/array.h" +#include "live_effects/effect-enum.h" +#include "helper/geom-pathvectorsatellites.h" +#include "knot-holder-entity.h" +#include <glib.h> + +namespace Inkscape { + +namespace LivePathEffect { + +class FilletChamferKnotHolderEntity; + +class SatellitesArrayParam : public ArrayParam<std::vector<Satellite> > { +public: + SatellitesArrayParam(const Glib::ustring &label, const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, Effect *effect); + + virtual Gtk::Widget *param_newWidget() + { + return NULL; + } + virtual void setHelperSize(int hs); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror); + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); + virtual void updateCanvasIndicators(); + virtual void updateCanvasIndicators(bool mirror); + virtual bool providesKnotHolderEntities() const + { + return true; + } + void param_transform_multiply(Geom::Affine const &postmul, bool /*set*/); + void setUseDistance(bool use_knot_distance); + void setCurrentZoom(double current_zoom); + void setGlobalKnotHide(bool global_knot_hide); + void setEffectType(EffectType et); + void setPathVectorSatellites(PathVectorSatellites *pathVectorSatellites, bool write = true); + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + + friend class FilletChamferKnotHolderEntity; + friend class LPEFilletChamfer; + +protected: + KnotHolder *_knoth; + +private: + SatellitesArrayParam(const SatellitesArrayParam &); + SatellitesArrayParam &operator=(const SatellitesArrayParam &); + + SPKnotShapeType _knot_shape; + SPKnotModeType _knot_mode; + guint32 _knot_color; + Geom::PathVector _hp; + Geom::PathVector _knot_reset_helper; + int _helper_size; + bool _use_distance; + bool _global_knot_hide; + double _current_zoom; + EffectType _effectType; + PathVectorSatellites *_last_pathvector_satellites; + +}; + +class FilletChamferKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferKnotHolderEntity(SatellitesArrayParam *p, size_t index); + virtual ~FilletChamferKnotHolderEntity() + { + _pparam->_knoth = NULL; + } + + 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); + void knot_set_offset(Satellite); + /** Checks whether the index falls within the size of the parameter's vector + */ + bool valid_index(size_t index,size_t subindex) const + { + return (_pparam->_vector.size() > index && _pparam->_vector[index].size() > subindex); + }; + +private: + SatellitesArrayParam *_pparam; + size_t _index; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index 234a6174d..d633666aa 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -31,12 +31,16 @@ TextParam::TextParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, const Glib::ustring default_value ) : Parameter(label, tip, key, wr, effect), value(default_value), - defvalue(default_value) + defvalue(default_value), + _hide_canvas_text(false) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; // FIXME: we shouldn't use this! - canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), ""); - sp_canvastext_set_text (canvas_text, default_value.c_str()); - sp_canvastext_set_coords (canvas_text, 0, 0); + if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) { // FIXME: we shouldn't use this! + canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), ""); + sp_canvastext_set_text (canvas_text, default_value.c_str()); + sp_canvastext_set_coords (canvas_text, 0, 0); + } else { + _hide_canvas_text = true; + } } void @@ -46,9 +50,26 @@ TextParam::param_set_default() } void +TextParam::param_update_default(const gchar * default_value) +{ + defvalue = (Glib::ustring)default_value; +} + +void +TextParam::param_hide_canvas_text() +{ + if (!_hide_canvas_text) { + sp_canvastext_set_text(canvas_text, " "); + _hide_canvas_text = true; + } +} + +void TextParam::setPos(Geom::Point pos) { - sp_canvastext_set_coords (canvas_text, pos); + if (!_hide_canvas_text) { + sp_canvastext_set_coords (canvas_text, pos); + } } void @@ -63,9 +84,10 @@ TextParam::setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, Point dir = unit_vector(derivative(pwd2_reparam).valueAt(t_reparam)); Point n = -rot90(dir); double angle = Geom::angle_between(dir, Point(1,0)); - - sp_canvastext_set_coords(canvas_text, pos + n * length); - sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle)); + if (!_hide_canvas_text) { + sp_canvastext_set_coords(canvas_text, pos + n * length); + sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle)); + } } void @@ -73,7 +95,9 @@ TextParam::setAnchor(double x_value, double y_value) { anchor_x = x_value; anchor_y = y_value; - sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y); + if (!_hide_canvas_text) { + sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y); + } } bool @@ -86,7 +110,10 @@ TextParam::param_readSVGValue(const gchar * strvalue) gchar * TextParam::param_getSVGValue() const { - return g_strdup(value.c_str()); + Inkscape::SVGOStringStream os; + os << value; + gchar * str = g_strdup(os.str().c_str()); + return str; } Gtk::Widget * @@ -94,21 +121,23 @@ TextParam::param_newWidget() { Inkscape::UI::Widget::RegisteredText *rsu = Gtk::manage(new Inkscape::UI::Widget::RegisteredText( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc())); - - rsu->setText(value.c_str()); + rsu->setText(value); rsu->setProgrammatically = false; rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change text parameter")); - return dynamic_cast<Gtk::Widget *> (rsu); } void TextParam::param_setValue(const Glib::ustring newvalue) { + if (value != newvalue) { + param_effect->upd_params = true; + } value = newvalue; - - sp_canvastext_set_text (canvas_text, newvalue.c_str()); + if (!_hide_canvas_text) { + sp_canvastext_set_text (canvas_text, newvalue.c_str()); + } } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h index 62de70eec..137f3ee02 100644 --- a/src/live_effects/parameter/text.h +++ b/src/live_effects/parameter/text.h @@ -39,21 +39,23 @@ public: virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; - void param_setValue(const Glib::ustring newvalue); + void param_setValue(Glib::ustring newvalue); + void param_hide_canvas_text(); virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); void setPos(Geom::Point pos); void setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, const double t, const double length, bool use_curvature = false); void setAnchor(double x_value, double y_value); - const Glib::ustring get_value() const { return defvalue; }; + const Glib::ustring get_value() const { return value; }; private: TextParam(const TextParam&); TextParam& operator=(const TextParam&); double anchor_x; double anchor_y; - + bool _hide_canvas_text; Glib::ustring value; Glib::ustring defvalue; diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index 47a8b5615..eb40a7e41 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -12,6 +12,7 @@ #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" +#include "selection.h" #include "widgets/icon.h" #include "inkscape.h" #include "verbs.h" @@ -24,10 +25,10 @@ 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, const Glib::ustring& inactive_label, - char const * icon_active, char const * icon_inactive, - Inkscape::IconSize icon_size) + 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) + inactive_label(inactive_label), _icon_active(_icon_active), _icon_inactive(_icon_inactive), _icon_size(_icon_size) { checkwdg = NULL; } @@ -59,6 +60,18 @@ ToggleButtonParam::param_getSVGValue() const return str; } +void +ToggleButtonParam::param_update_default(bool default_value) +{ + defvalue = default_value; +} + +void +ToggleButtonParam::param_update_default(const gchar * default_value) +{ + param_update_default(helperfns_read_bool(default_value, defvalue)); +} + Gtk::Widget * ToggleButtonParam::param_newWidget() { @@ -67,52 +80,50 @@ ToggleButtonParam::param_newWidget() } checkwdg = Gtk::manage( - new Inkscape::UI::Widget::RegisteredToggleButton( param_label, + new Inkscape::UI::Widget::RegisteredToggleButton(param_label, param_tooltip, param_key, *param_wr, false, param_effect->getRepr(), param_effect->getSPDoc()) ); -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget * boxButton = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(boxButton), false); -#else - GtkWidget * boxButton = gtk_hbox_new (false, 0); -#endif - GtkWidget * labelButton = gtk_label_new (""); + auto box_button = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous(GTK_BOX(box_button), false); + GtkWidget * label_button = gtk_label_new (""); if (!param_label.empty()) { - if(value || inactiveLabel.empty()){ - gtk_label_set_text(GTK_LABEL(labelButton), param_label.c_str()); + if(value || inactive_label.empty()){ + gtk_label_set_text(GTK_LABEL(label_button), param_label.c_str()); }else{ - gtk_label_set_text(GTK_LABEL(labelButton), inactiveLabel.c_str()); + gtk_label_set_text(GTK_LABEL(label_button), inactive_label.c_str()); } } - gtk_widget_show(labelButton); - if ( iconActive ) { - if(!iconInactive){ - iconInactive = iconActive; + gtk_widget_show(label_button); + if ( _icon_active ) { + if(!_icon_inactive){ + _icon_inactive = _icon_active; } - gtk_widget_show(boxButton); - GtkWidget *iconButton = sp_icon_new(iconSize, iconActive); + gtk_widget_show(box_button); + GtkWidget *icon_button = NULL; if(!value){ - iconButton = sp_icon_new(iconSize, iconInactive); + icon_button = sp_icon_new(_icon_size, _icon_inactive); + } else { + icon_button = sp_icon_new(_icon_size, _icon_active); } - gtk_widget_show(iconButton); - gtk_box_pack_start (GTK_BOX(boxButton), iconButton, false, false, 1); + gtk_widget_show(icon_button); + gtk_box_pack_start (GTK_BOX(box_button), icon_button, false, false, 1); if (!param_label.empty()) { - gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); + gtk_box_pack_start (GTK_BOX(box_button), label_button, false, false, 1); } }else{ - gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); + gtk_box_pack_start (GTK_BOX(box_button), label_button, false, false, 1); } - checkwdg->add(*Gtk::manage(Glib::wrap(boxButton))); + + checkwdg->add(*Gtk::manage(Glib::wrap(box_button))); checkwdg->setActive(value); checkwdg->setProgrammatically = false; checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); - return checkwdg; } @@ -126,37 +137,46 @@ ToggleButtonParam::refresh_button() if(!checkwdg){ return; } - Gtk::Widget * boxButton = checkwdg->get_child(); - if(!boxButton){ + Gtk::Widget * box_button = checkwdg->get_child(); + if(!box_button){ return; } - GList * childs = gtk_container_get_children(GTK_CONTAINER(boxButton->gobj())); - guint totalWidgets = g_list_length (childs); + GList * childs = gtk_container_get_children(GTK_CONTAINER(box_button->gobj())); + guint total_widgets = 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()); + if(value || inactive_label.empty()){ + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, total_widgets-1)), param_label.c_str()); }else{ - gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), inactiveLabel.c_str()); + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, total_widgets-1)), inactive_label.c_str()); } } - if ( iconActive ) { - GdkPixbuf * iconPixbuf = sp_pixbuf_new( iconSize, iconActive ); + if ( _icon_active ) { + GdkPixbuf * icon_pixbuf = NULL; if(!value){ - iconPixbuf = sp_pixbuf_new( iconSize, iconInactive); + icon_pixbuf = sp_pixbuf_new( _icon_size, _icon_inactive ); + } else { + icon_pixbuf = sp_pixbuf_new( _icon_size, _icon_active ); } - gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), iconPixbuf); + gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), icon_pixbuf); } } void ToggleButtonParam::param_setValue(bool newvalue) { + if (value != newvalue) { + param_effect->upd_params = true; + } value = newvalue; refresh_button(); } void ToggleButtonParam::toggled() { + if (SP_ACTIVE_DESKTOP) { + Inkscape::Selection *selection = SP_ACTIVE_DESKTOP->getSelection(); + selection->emitModified(); + } _signal_toggled.emit(); } diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h index 4e545bcfd..d6ca15e75 100644 --- a/src/live_effects/parameter/togglebutton.h +++ b/src/live_effects/parameter/togglebutton.h @@ -51,6 +51,8 @@ public: sigc::signal<void>& signal_toggled() { return _signal_toggled; } virtual void toggled(); + void param_update_default(bool default_value); + virtual void param_update_default(const gchar * default_value); private: ToggleButtonParam(const ToggleButtonParam&); @@ -59,10 +61,10 @@ private: void refresh_button(); bool value; bool defvalue; - const Glib::ustring inactiveLabel; - const char * iconActive; - const char * iconInactive; - Inkscape::IconSize iconSize; + const Glib::ustring inactive_label; + const char * _icon_active; + const char * _icon_inactive; + Inkscape::IconSize _icon_size; Inkscape::UI::Widget::RegisteredToggleButton * checkwdg; sigc::signal<void> _signal_toggled; diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp index 0d03432c3..22d5ba3a4 100644 --- a/src/live_effects/parameter/transformedpoint.cpp +++ b/src/live_effects/parameter/transformedpoint.cpp @@ -82,6 +82,25 @@ TransformedPointParam::param_getSVGValue() const return str; } +void +TransformedPointParam::param_update_default(Geom::Point default_point) +{ + defvalue = default_point; +} + +void +TransformedPointParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } +} + Gtk::Widget * TransformedPointParam::param_newWidget() { diff --git a/src/live_effects/parameter/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h index c96bedb53..269cc508e 100644 --- a/src/live_effects/parameter/transformedpoint.h +++ b/src/live_effects/parameter/transformedpoint.h @@ -51,7 +51,9 @@ public: void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_oncanvas_color(guint32 color); - + Geom::Point param_get_default() { return defvalue; } + void param_update_default(Geom::Point default_point); + virtual void param_update_default(const gchar * default_point); virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); diff --git a/src/live_effects/parameter/unit.cpp b/src/live_effects/parameter/unit.cpp index 0ee553e2c..b9b91c1e6 100644 --- a/src/live_effects/parameter/unit.cpp +++ b/src/live_effects/parameter/unit.cpp @@ -54,9 +54,16 @@ UnitParam::param_set_default() param_set_value(*defunit); } +void +UnitParam::param_update_default(const gchar * default_unit) +{ + defunit = unit_table.getUnit((Glib::ustring)default_unit); +} + void UnitParam::param_set_value(Inkscape::Util::Unit const &val) { + param_effect->upd_params = true; unit = new Inkscape::Util::Unit(val); } diff --git a/src/live_effects/parameter/unit.h b/src/live_effects/parameter/unit.h index 59a483018..c662b6edc 100644 --- a/src/live_effects/parameter/unit.h +++ b/src/live_effects/parameter/unit.h @@ -33,10 +33,10 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); void param_set_value(Inkscape::Util::Unit const &val); + virtual void param_update_default(const gchar * default_unit); const gchar *get_abbreviation() const; - virtual Gtk::Widget * param_newWidget(); - + operator Inkscape::Util::Unit const *() const { return unit; } private: diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp index cfaa9e7e7..470fa9c2d 100644 --- a/src/live_effects/parameter/vector.cpp +++ b/src/live_effects/parameter/vector.cpp @@ -14,7 +14,6 @@ #include "svg/stringstream.h" #include "live_effects/effect.h" -#include "desktop.h" #include "verbs.h" namespace Inkscape { @@ -49,6 +48,25 @@ VectorParam::param_set_default() setVector(defvalue); } +void +VectorParam::param_update_default(Geom::Point default_point) +{ + defvalue = default_point; +} + +void +VectorParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } +} + bool VectorParam::param_readSVGValue(const gchar * strvalue) { @@ -117,7 +135,7 @@ VectorParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point void VectorParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { - set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() ); + set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() ); } @@ -188,14 +206,14 @@ private: }; void -VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { VectorParamKnotHolderEntity_Origin *origin_e = new VectorParamKnotHolderEntity_Origin(this); - origin_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color); + origin_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color); knotholder->add(origin_e); VectorParamKnotHolderEntity_Vector *vector_e = new VectorParamKnotHolderEntity_Vector(this); - vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color); + vector_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color); knotholder->add(vector_e); } diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h index 35ca04437..d270e9f43 100644 --- a/src/live_effects/parameter/vector.h +++ b/src/live_effects/parameter/vector.h @@ -51,9 +51,10 @@ public: void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_oncanvas_color(guint32 color); - + void param_update_default(Geom::Point default_point); + virtual void param_update_default(const gchar * default_point); virtual bool providesKnotHolderEntities() const { return true; } - virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); private: VectorParam(const VectorParam&); diff --git a/src/live_effects/spiro.cpp b/src/live_effects/spiro.cpp index 0ac2815bf..a2ff4813e 100644 --- a/src/live_effects/spiro.cpp +++ b/src/live_effects/spiro.cpp @@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #include <string.h> #include "display/curve.h" -#include <2geom/math-utils.h> #define SPIRO_SHOW_INFINITE_COORDINATE_CALLS |
