summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiam P. White <inkscapebronyat-signgmaildotcom>2014-07-05 13:28:06 +0000
committerLiam P. White <inkscapebronyat-signgmaildotcom>2014-07-05 13:28:06 +0000
commit6456d475232772dac4f22f7e31b9b43a0155b335 (patch)
treed954c8837a33d62df2bc3df930e75f9234fc8691 /src
parentFix make check (diff)
parentPut correctly doubles in a function (diff)
downloadinkscape-6456d475232772dac4f22f7e31b9b43a0155b335.tar.gz
inkscape-6456d475232772dac4f22f7e31b9b43a0155b335.zip
Update to experimental r13418
(bzr r13090.1.87)
Diffstat (limited to 'src')
-rw-r--r--src/box3d-side.cpp2
-rw-r--r--src/display/nr-filter-blend.cpp9
-rw-r--r--src/display/nr-filter-blend.h2
-rw-r--r--src/file.cpp10
-rw-r--r--src/filter-enums.cpp8
-rw-r--r--src/filters/blend.cpp8
-rw-r--r--src/knotholder.h2
-rw-r--r--src/libavoid/connector.cpp18
-rw-r--r--src/live_effects/CMakeLists.txt4
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/effect-enum.h1
-rw-r--r--src/live_effects/effect.cpp4
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp687
-rw-r--r--src/live_effects/lpe-fillet-chamfer.h68
-rw-r--r--src/live_effects/parameter/Makefile_insert2
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp655
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h117
-rw-r--r--src/selection-chemistry.cpp4
-rw-r--r--src/sp-ellipse.cpp2
-rw-r--r--src/sp-item-group.cpp36
-rw-r--r--src/sp-item-group.h2
-rw-r--r--src/sp-lpe-item.cpp64
-rw-r--r--src/sp-lpe-item.h11
-rw-r--r--src/sp-path.cpp2
-rw-r--r--src/sp-spiral.cpp2
-rw-r--r--src/sp-star.cpp2
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/dialog/Makefile_insert2
-rw-r--r--src/ui/dialog/filedialogimpl-win32.h3
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.cpp257
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.h104
-rw-r--r--src/ui/dialog/print.cpp9
-rw-r--r--src/ui/tool/multi-path-manipulator.h3
-rw-r--r--src/ui/tool/path-manipulator.cpp20
-rw-r--r--src/ui/tools/pen-tool.cpp61
-rw-r--r--src/ui/widget/filter-effect-chooser.cpp13
-rw-r--r--src/ui/widget/preferences-widget.cpp8
37 files changed, 2034 insertions, 172 deletions
diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp
index a5e7eaa94..dfccb63bf 100644
--- a/src/box3d-side.cpp
+++ b/src/box3d-side.cpp
@@ -213,8 +213,6 @@ void Box3DSide::set_shape() {
bool success = this->performPathEffect(c_lpe);
if (success) {
- sp_lpe_item_apply_to_mask(this);
- sp_lpe_item_apply_to_clippath(this);
this->setCurveInsync(c_lpe, TRUE);
}
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp
index 099816bce..25aea6f13 100644
--- a/src/display/nr-filter-blend.cpp
+++ b/src/display/nr-filter-blend.cpp
@@ -83,8 +83,7 @@ void FilterBlend::render_cairo(FilterSlot &slot)
case BLEND_LIGHTEN:
cairo_set_operator(out_ct, CAIRO_OPERATOR_LIGHTEN);
break;
-#ifdef WITH_CSSBLEND
- // NEW
+ // New in CSS Compositing and Blending Level 1
case BLEND_OVERLAY:
cairo_set_operator(out_ct, CAIRO_OPERATOR_OVERLAY);
break;
@@ -118,7 +117,6 @@ void FilterBlend::render_cairo(FilterSlot &slot)
case BLEND_LUMINOSITY:
cairo_set_operator(out_ct, CAIRO_OPERATOR_HSL_LUMINOSITY);
break;
-#endif
case BLEND_NORMAL:
default:
@@ -167,15 +165,12 @@ void FilterBlend::set_input(int input, int slot) {
void FilterBlend::set_mode(FilterBlendMode mode) {
if (mode == BLEND_NORMAL || mode == BLEND_MULTIPLY ||
mode == BLEND_SCREEN || mode == BLEND_DARKEN ||
- mode == BLEND_LIGHTEN
-#ifdef WITH_CSSBLEND
- || mode == BLEND_OVERLAY ||
+ mode == BLEND_LIGHTEN || mode == BLEND_OVERLAY ||
mode == BLEND_COLORDODGE || mode == BLEND_COLORBURN ||
mode == BLEND_HARDLIGHT || mode == BLEND_SOFTLIGHT ||
mode == BLEND_DIFFERENCE || mode == BLEND_EXCLUSION ||
mode == BLEND_HUE || mode == BLEND_SATURATION ||
mode == BLEND_COLOR || mode == BLEND_LUMINOSITY
-#endif
)
{
_blend_mode = mode;
diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h
index 0a2927d87..c0504993b 100644
--- a/src/display/nr-filter-blend.h
+++ b/src/display/nr-filter-blend.h
@@ -28,7 +28,6 @@ enum FilterBlendMode {
BLEND_SCREEN,
BLEND_DARKEN,
BLEND_LIGHTEN,
-#ifdef WITH_CSSBLEND
// New in CSS Compositing and Blending Level 1
BLEND_OVERLAY,
BLEND_COLORDODGE,
@@ -41,7 +40,6 @@ enum FilterBlendMode {
BLEND_SATURATION,
BLEND_COLOR,
BLEND_LUMINOSITY,
-#endif
BLEND_ENDMODE,
};
diff --git a/src/file.cpp b/src/file.cpp
index 51e629c7d..d8671c5d5 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -669,7 +669,7 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri,
sp_ui_error_dialog(text);
g_free(text);
g_free(safeUri);
- return FALSE;
+ return false;
} catch (Inkscape::Extension::Output::file_read_only &e) {
gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
gchar *text = g_strdup_printf(_("File %s is write protected. Please remove write protection and try again."), safeUri);
@@ -677,7 +677,7 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri,
sp_ui_error_dialog(text);
g_free(text);
g_free(safeUri);
- return FALSE;
+ return false;
} catch (Inkscape::Extension::Output::save_failed &e) {
gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
gchar *text = g_strdup_printf(_("File %s could not be saved."), safeUri);
@@ -685,15 +685,15 @@ file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri,
sp_ui_error_dialog(text);
g_free(text);
g_free(safeUri);
- return FALSE;
+ return false;
} catch (Inkscape::Extension::Output::save_cancelled &e) {
SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
- return FALSE;
+ return false;
} catch (Inkscape::Extension::Output::no_overwrite &e) {
return sp_file_save_dialog(parentWindow, doc, save_method);
} catch (...) {
SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
- return FALSE;
+ return false;
}
if (SP_ACTIVE_DESKTOP) {
diff --git a/src/filter-enums.cpp b/src/filter-enums.cpp
index 7ee57f7fa..09a1a7614 100644
--- a/src/filter-enums.cpp
+++ b/src/filter-enums.cpp
@@ -53,7 +53,6 @@ const EnumData<Inkscape::Filters::FilterBlendMode> BlendModeData[Inkscape::Filte
{Inkscape::Filters::BLEND_SCREEN, _("Screen"), "screen"},
{Inkscape::Filters::BLEND_DARKEN, _("Darken"), "darken"},
{Inkscape::Filters::BLEND_LIGHTEN, _("Lighten"), "lighten"},
-#ifdef WITH_CSSBLEND
// New in Compositing and Blending Level 1
{Inkscape::Filters::BLEND_OVERLAY, _("Overlay"), "overlay"},
{Inkscape::Filters::BLEND_COLORDODGE, _("Color Dodge"), "color-dodge"},
@@ -66,10 +65,13 @@ const EnumData<Inkscape::Filters::FilterBlendMode> BlendModeData[Inkscape::Filte
{Inkscape::Filters::BLEND_SATURATION, _("Saturation"), "saturation"},
{Inkscape::Filters::BLEND_COLOR, _("Color"), "color"},
{Inkscape::Filters::BLEND_LUMINOSITY, _("Luminosity"), "luminosity"}
-#endif
};
+#ifdef WITH_CSSBLEND
const EnumDataConverter<Inkscape::Filters::FilterBlendMode> BlendModeConverter(BlendModeData, Inkscape::Filters::BLEND_ENDMODE);
-
+#else
+// Disable new blend modes in GUI until widely implemented.
+const EnumDataConverter<Inkscape::Filters::FilterBlendMode> BlendModeConverter(BlendModeData, Inkscape::Filters::BLEND_OVERLAY);
+#endif
const EnumData<Inkscape::Filters::FilterColorMatrixType> ColorMatrixTypeData[Inkscape::Filters::COLORMATRIX_ENDTYPE] = {
{Inkscape::Filters::COLORMATRIX_MATRIX, _("Matrix"), "matrix"},
diff --git a/src/filters/blend.cpp b/src/filters/blend.cpp
index 5c78f4f9f..fd5a9871e 100644
--- a/src/filters/blend.cpp
+++ b/src/filters/blend.cpp
@@ -96,23 +96,18 @@ static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value
case 's':
if (strncmp(value, "screen", 6) == 0)
return Inkscape::Filters::BLEND_SCREEN;
-#ifdef WITH_CSSBLEND
if (strncmp(value, "saturation", 6) == 0)
return Inkscape::Filters::BLEND_SATURATION;
-#endif
break;
case 'd':
if (strncmp(value, "darken", 6) == 0)
return Inkscape::Filters::BLEND_DARKEN;
-#ifdef WITH_CSSBLEND
if (strncmp(value, "difference", 10) == 0)
return Inkscape::Filters::BLEND_DIFFERENCE;
-#endif
break;
case 'l':
if (strncmp(value, "lighten", 7) == 0)
return Inkscape::Filters::BLEND_LIGHTEN;
-#ifdef WITH_CSSBLEND
if (strncmp(value, "luminosity", 10) == 0)
return Inkscape::Filters::BLEND_LUMINOSITY;
break;
@@ -137,7 +132,6 @@ static Inkscape::Filters::FilterBlendMode sp_feBlend_readmode(gchar const *value
case 'e':
if (strncmp(value, "exclusion", 10) == 0)
return Inkscape::Filters::BLEND_EXCLUSION;
-#endif
default:
std::cout << "Inkscape::Filters::FilterBlendMode: Unimplemented mode: " << value << std::endl;
// do nothing by default
@@ -244,7 +238,6 @@ Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XM
mode = "darken"; break;
case Inkscape::Filters::BLEND_LIGHTEN:
mode = "lighten"; break;
-#ifdef WITH_CSSBLEND
// New
case Inkscape::Filters::BLEND_OVERLAY:
mode = "overlay"; break;
@@ -268,7 +261,6 @@ Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XM
mode = "color"; break;
case Inkscape::Filters::BLEND_LUMINOSITY:
mode = "luminosity"; break;
-#endif
default:
mode = 0;
}
diff --git a/src/knotholder.h b/src/knotholder.h
index 3632635f5..dc2300105 100644
--- a/src/knotholder.h
+++ b/src/knotholder.h
@@ -28,6 +28,7 @@ class Node;
}
namespace LivePathEffect {
class PowerStrokePointArrayParamKnotHolderEntity;
+class FilletPointArrayParamKnotHolderEntity;
}
}
@@ -60,6 +61,7 @@ public:
friend class ShapeEditor;
friend class Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity;
+ friend class Inkscape::LivePathEffect::FilletPointArrayParamKnotHolderEntity;
protected:
diff --git a/src/libavoid/connector.cpp b/src/libavoid/connector.cpp
index 8dcb66f2d..b8c99a48c 100644
--- a/src/libavoid/connector.cpp
+++ b/src/libavoid/connector.cpp
@@ -442,11 +442,11 @@ void ConnRef::makeActive(void)
void ConnRef::makeInactive(void)
{
- COLA_ASSERT(_active);
-
- // Remove from connRefs list.
- _router->connRefs.erase(_pos);
- _active = false;
+ if (_active) {
+ // Remove from connRefs list.
+ _router->connRefs.erase(_pos);
+ _active = false;
+ }
}
@@ -553,8 +553,12 @@ void ConnRef::unInitialise(void)
void ConnRef::removeFromGraph(void)
{
- _srcVert->removeFromGraph();
- _dstVert->removeFromGraph();
+ if (_srcVert) {
+ _srcVert->removeFromGraph();
+ }
+ if (_dstVert) {
+ _dstVert->removeFromGraph();
+ }
}
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index c3ce31cfc..6195da31b 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -19,6 +19,7 @@ set(live_effects_SRC
lpe-extrude.cpp
lpe-fill-between-many.cpp
lpe-fill-between-strokes.cpp
+ lpe-fillet-chamfer.cpp
lpe-gears.cpp
lpe-interpolate.cpp
lpe-knot.cpp
@@ -53,6 +54,7 @@ set(live_effects_SRC
parameter/array.cpp
parameter/bool.cpp
+ parameter/filletchamferpointarray.cpp
parameter/parameter.cpp
parameter/path.cpp
parameter/originalpath.cpp
@@ -89,6 +91,7 @@ set(live_effects_SRC
lpe-extrude.h
lpe-fill-between-many.h
lpe-fill-between-strokes.h
+ lpe-fillet-chamfer.h
lpe-gears.h
lpe-interpolate.h
lpe-knot.h
@@ -124,6 +127,7 @@ set(live_effects_SRC
parameter/array.h
parameter/bool.h
+ parameter/filletchamferpointarray.h
parameter/enum.h
parameter/parameter.h
parameter/path-reference.h
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index 3d474d00c..cf0358afa 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -32,6 +32,8 @@ ink_common_sources += \
live_effects/lpe-curvestitch.h \
live_effects/lpe-constructgrid.cpp \
live_effects/lpe-constructgrid.h \
+ live_effects/lpe-fillet-chamfer.cpp \
+ live_effects/lpe-fillet-chamfer.h \
live_effects/lpe-gears.cpp \
live_effects/lpe-gears.h \
live_effects/lpe-interpolate.cpp \
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 92f35fc72..a244edfa0 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -61,6 +61,7 @@ enum EffectType {
JOIN_TYPE,
TAPER_STROKE,
ENVELOPE_PERSPECTIVE,
+ FILLET_CHAMFER,
INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan)
};
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index e51fb186e..01621822d 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -58,6 +58,7 @@
#include "live_effects/lpe-jointype.h"
#include "live_effects/lpe-taperstroke.h"
#include "live_effects/lpe-envelope-perspective.h"
+#include "live_effects/lpe-fillet-chamfer.h"
#include "xml/node-event-vector.h"
#include "sp-object.h"
@@ -302,6 +303,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case ENVELOPE_PERSPECTIVE:
neweffect = static_cast<Effect*> ( new LPEEnvelopePerspective(lpeobj) );
break;
+ case FILLET_CHAMFER:
+ neweffect = static_cast<Effect*> ( new LPEFilletChamfer(lpeobj) );
+ break;
default:
g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
neweffect = NULL;
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp
new file mode 100644
index 000000000..1fb68020d
--- /dev/null
+++ b/src/live_effects/lpe-fillet-chamfer.cpp
@@ -0,0 +1,687 @@
+/*
+ * 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
+ * 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 <glibmm/i18n.h>
+#include "style.h"
+#include "live_effects/parameter/filletchamferpointarray.h"
+//for update knot
+#include <2geom/svg-elliptical-arc.h>
+#include <2geom/line.h>
+#include "selection.h"
+#include "ui/tool/control-point-selection.h"
+#include "ui/tool/selectable-control-point.h"
+#include <2geom/sbasis-to-bezier.h>
+#include "ui/tool/node.h"
+// FIXME: The following are only needed to convert the path's SPCurve* to pwd2.
+// There must be a more convenient way to achieve this.
+#include "display/curve.h"
+#include "helper/geom-nodetype.h"
+#include "desktop.h"
+#include "ui/tools/node-tool.h"
+#include <iostream>
+#include <tools-switch.h>
+#include <cmath>
+
+using namespace Geom;
+namespace Inkscape {
+namespace LivePathEffect {
+
+const double tolerance = 0.001;
+const double gapHelper = 0.00001;
+
+LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ fillet_chamfer_values(_("Fillet point"), _("Fillet point"),
+ "fillet_chamfer_values", &wr, this),
+ hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this,
+ false),
+ ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"),
+ "ignore_radius_0", &wr, this, false),
+ only_selected(_("Change only selected nodes"),
+ _("Change only selected nodes"), "only_selected", &wr, this,
+ false),
+ flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"),
+ "flexible", &wr, this, false),
+ unit(_("Unit"), _("Unit"), "unit", &wr, this),
+ radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr,
+ this, 0.),
+ helper_size(_("Helper size with direction"),
+ _("Helper size with direction"), "helper_size", &wr, this,
+ 0)
+{
+ registerParameter(dynamic_cast<Parameter *>(&fillet_chamfer_values));
+ registerParameter(dynamic_cast<Parameter *>(&unit));
+ registerParameter(dynamic_cast<Parameter *>(&radius));
+ registerParameter(dynamic_cast<Parameter *>(&helper_size));
+ registerParameter(dynamic_cast<Parameter *>(&flexible));
+ registerParameter(dynamic_cast<Parameter *>(&ignore_radius_0));
+ registerParameter(dynamic_cast<Parameter *>(&only_selected));
+ registerParameter(dynamic_cast<Parameter *>(&hide_knots));
+ radius.param_set_range(0., infinity());
+ radius.param_set_increments(1, 1);
+ radius.param_set_digits(4);
+ helper_size.param_set_range(0, infinity());
+ helper_size.param_set_increments(5, 5);
+ helper_size.param_set_digits(0);
+}
+
+LPEFilletChamfer::~LPEFilletChamfer() {}
+
+Gtk::Widget *LPEFilletChamfer::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(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 = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ if (widg) {
+ Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> childList =
+ scalarParameter->get_children();
+ Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entryWidg->set_width_chars(6);
+ }
+ }
+ 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));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
+ 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));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+
+ }
+ 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));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
+ if (param->param_key == "only_selected") {
+ Gtk::CheckButton *widgRegistered =
+ Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
+ if (param->param_key == "ignore_radius_0") {
+ Gtk::CheckButton *widgRegistered =
+ Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+
+ Gtk::HBox *filletButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::Button *fillet =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet"))));
+ fillet->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet));
+ filletButtonsContainer->pack_start(*fillet, true, true, 2);
+ Gtk::Button *inverse =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet"))));
+ inverse->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse));
+ filletButtonsContainer->pack_start(*inverse, true, true, 2);
+
+ Gtk::HBox *chamferButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::Button *chamfer =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer"))));
+ chamfer->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer));
+ chamferButtonsContainer->pack_start(*chamfer, true, true, 2);
+ Gtk::Button *doubleChamfer =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer"))));
+ doubleChamfer->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer));
+ chamferButtonsContainer->pack_start(*doubleChamfer, true, true, 2);
+ vbox->pack_start(*filletButtonsContainer, true, true, 2);
+ vbox->pack_start(*chamferButtonsContainer, true, true, 2);
+
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void LPEFilletChamfer::toggleHide()
+{
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
+ point_it != filletChamferData.end(); ++point_it) {
+ if (hide_knots) {
+ result.push_back(Point((*point_it)[X], abs((*point_it)[Y]) * -1));
+ } else {
+ result.push_back(Point((*point_it)[X], abs((*point_it)[Y])));
+ }
+ }
+ fillet_chamfer_values.param_set_and_write_new_value(result);
+ refreshKnots();
+}
+
+void LPEFilletChamfer::toggleFlexFixed()
+{
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ unsigned int i = 0;
+ for (std::vector<Point>::const_iterator point_it = filletChamferData.begin();
+ point_it != filletChamferData.end(); ++point_it) {
+ if (flexible) {
+ result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]),
+ (*point_it)[Y]));
+ } else {
+ result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]),
+ (*point_it)[Y]));
+ }
+ i++;
+ }
+ if (flexible) {
+ radius.param_set_range(0., 100);
+ radius.param_set_value(0);
+ } else {
+ radius.param_set_range(0., infinity());
+ radius.param_set_value(0);
+ }
+ fillet_chamfer_values.param_set_and_write_new_value(result);
+}
+
+void LPEFilletChamfer::updateFillet()
+{
+ double power = 0;
+ if (!flexible) {
+ power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(),
+ "px") * -1;
+ } else {
+ power = radius;
+ }
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);
+}
+
+void LPEFilletChamfer::fillet()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 1);
+}
+
+void LPEFilletChamfer::inverse()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 2);
+}
+
+void LPEFilletChamfer::chamfer()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 3);
+}
+
+void LPEFilletChamfer::doubleChamfer()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 4);
+}
+
+void LPEFilletChamfer::refreshKnots()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ fillet_chamfer_values.recalculate_knots(pwd2);
+ SPDesktop *desktop = inkscape_active_desktop();
+ if (tools_isactive(desktop, TOOLS_NODES)) {
+ tools_switch(desktop, TOOLS_SELECT);
+ tools_switch(desktop, TOOLS_NODES);
+ }
+}
+
+bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint,
+ std::vector<Geom::Point> point)
+{
+ if (point.size() > 0) {
+ for (std::vector<Geom::Point>::iterator i = point.begin(); i != point.end();
+ ++i) {
+ Geom::Point p = *i;
+ if (Geom::are_near(p, nodePoint, 2)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> original_pathv,
+ double power)
+{
+ std::vector<Geom::Point> point;
+ SPDesktop *desktop = inkscape_active_desktop();
+ if (INK_IS_NODE_TOOL(desktop->event_context)) {
+ Inkscape::UI::Tools::NodeTool *nodeTool =
+ INK_NODE_TOOL(desktop->event_context);
+ Inkscape::UI::ControlPointSelection::Set &selection =
+ nodeTool->_selected_nodes->allPoints();
+ std::vector<Geom::Point>::iterator pBegin;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i =
+ selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
+ pBegin = point.begin();
+ point.insert(pBegin, desktop->doc2dt(n->position()));
+ }
+ }
+ }
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ int counter = 0;
+ for (PathVector::const_iterator path_it = original_pathv.begin();
+ path_it != original_pathv.end(); ++path_it) {
+ int pathCounter = 0;
+ if (path_it->empty())
+ continue;
+
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed() && path_it->back_closed().isDegenerate()) {
+ const Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ double powerend = 0;
+ while (curve_it1 != curve_endit) {
+ powerend = power;
+ if (power > 0) {
+ powerend = counter + (power / 100);
+ }
+ if (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
+ filletChamferData[counter][X] == counter)) {
+ powerend = filletChamferData[counter][X];
+ }
+ if (filletChamferData[counter][Y] == 0) {
+ powerend = filletChamferData[counter][X];
+ }
+ if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), point)) {
+ powerend = filletChamferData[counter][X];
+ }
+ result.push_back(Point(powerend, filletChamferData[counter][Y]));
+ ++curve_it1;
+ ++curve_it2;
+ counter++;
+ pathCounter++;
+ }
+ }
+ fillet_chamfer_values.param_set_and_write_new_value(result);
+}
+
+void LPEFilletChamfer::doChangeType(std::vector<Geom::Path> original_pathv,
+ int type)
+{
+ std::vector<Geom::Point> point;
+ SPDesktop *desktop = inkscape_active_desktop();
+ if (INK_IS_NODE_TOOL(desktop->event_context)) {
+ Inkscape::UI::Tools::NodeTool *nodeTool =
+ INK_NODE_TOOL(desktop->event_context);
+ Inkscape::UI::ControlPointSelection::Set &selection =
+ nodeTool->_selected_nodes->allPoints();
+ std::vector<Geom::Point>::iterator pBegin;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i =
+ selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
+ pBegin = point.begin();
+ point.insert(pBegin, desktop->doc2dt(n->position()));
+ }
+ }
+ }
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ int counter = 0;
+ for (PathVector::const_iterator path_it = original_pathv.begin();
+ path_it != original_pathv.end(); ++path_it) {
+ int pathCounter = 0;
+ if (path_it->empty())
+ continue;
+
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed() && path_it->back_closed().isDegenerate()) {
+ const Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ while (curve_it1 != curve_endit) {
+ bool toggle = true;
+ if (filletChamferData[counter][Y] == 0 ||
+ (ignore_radius_0 && (filletChamferData[counter][X] == 0 ||
+ filletChamferData[counter][X] == counter)) ||
+ (only_selected &&
+ !nodeIsSelected(curve_it1->initialPoint(), point))) {
+ toggle = false;
+ }
+ if (toggle) {
+ result.push_back(Point(filletChamferData[counter][X], type));
+ } else {
+ result.push_back(filletChamferData[counter]);
+ }
+ ++curve_it1;
+ if (curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ counter++;
+ pathCounter++;
+ }
+ }
+ fillet_chamfer_values.param_set_and_write_new_value(result);
+}
+
+void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem)
+{
+ if (SP_IS_SHAPE(lpeItem)) {
+ std::vector<Point> point;
+ PathVector const &original_pathv =
+ SP_SHAPE(lpeItem)->_curve->get_pathvector();
+ Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
+ for (PathVector::const_iterator path_it = original_pathv.begin();
+ path_it != original_pathv.end(); ++path_it) {
+ if (path_it->empty())
+ continue;
+
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed()) {
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
+ }
+ int counter = 0;
+ while (curve_it1 != curve_endit) {
+ Geom::NodeType nodetype;
+ if (counter == 0) {
+ if (path_it->closed()) {
+ nodetype = get_nodetype(path_it->back_default(), *curve_it1);
+ } else {
+ nodetype = NODE_NONE;
+ }
+ } else {
+ nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1);
+ }
+ if (nodetype == NODE_CUSP) {
+ point.push_back(Point(0, 1));
+ } else {
+ point.push_back(Point(0, 0));
+ }
+ ++curve_it1;
+ if (curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ counter++;
+ }
+ }
+ fillet_chamfer_values.param_set_and_write_new_value(point);
+ } else {
+ g_warning("LPE Fillet can only be applied to shapes (not groups).");
+ }
+}
+
+void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem)
+{
+ if (SP_IS_SHAPE(lpeItem)) {
+ fillet_chamfer_values.set_helper_size(helper_size);
+ fillet_chamfer_values.set_unit(unit.get_abbreviation());
+ SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)
+ ->get_original_curve()
+ : SP_SHAPE(lpeItem)->getCurve();
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ if (!filletChamferData.empty() && getKnotsNumber(c) != (int)
+ filletChamferData.size()) {
+ PathVector const original_pathv = c->get_pathvector();
+ Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv);
+ fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in);
+ }
+ } else {
+ g_warning("LPE Fillet can only be applied to shapes (not groups).");
+ }
+}
+
+int LPEFilletChamfer::getKnotsNumber(SPCurve const *c)
+{
+ int nKnots = c->nodes_in_path();
+ PathVector const pv = c->get_pathvector();
+ for (std::vector<Geom::Path>::const_iterator path_it = pv.begin();
+ path_it != pv.end(); ++path_it) {
+ if (!(*path_it).closed()) {
+ nKnots--;
+ }
+ }
+ return nKnots;
+}
+
+void
+LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in)
+{
+ if (!path_in.empty()) {
+ fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0]
+ .toPwSb());
+ }
+}
+
+std::vector<Geom::Path>
+LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in)
+{
+ std::vector<Geom::Path> pathvector_out;
+ Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(path_in);
+ pwd2_in = remove_short_cuts(pwd2_in, .01);
+ Piecewise<D2<SBasis> > der = derivative(pwd2_in);
+ Piecewise<D2<SBasis> > n = rot90(unitVector(der));
+ fillet_chamfer_values.set_pwd2(pwd2_in, n);
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ int counter = 0;
+ //from http://launchpadlibrarian.net/12692602/rcp.svg
+ const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);
+ for (PathVector::const_iterator path_it = path_in.begin();
+ path_it != path_in.end(); ++path_it) {
+ if (path_it->empty())
+ continue;
+ Geom::Path path_out;
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed()) {
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
+ }
+ int counterCurves = 0;
+ while (curve_it1 != curve_endit) {
+ Coord it1_length = (*curve_it1).length(tolerance);
+ double time_it1, time_it2, time_it1_B, intpart;
+ time_it1 = modf(
+ fillet_chamfer_values.to_time(counter, filletChamferData[counter][X]),
+ &intpart);
+ if (filletChamferData[counter][Y] == 0) {
+ time_it1 = 0;
+ }
+ time_it2 = modf(fillet_chamfer_values.to_time(
+ counter + 1, filletChamferData[counter + 1][X]),
+ &intpart);
+ if (curve_it2 == curve_endit) {
+ time_it2 = modf(fillet_chamfer_values.to_time(
+ counter - counterCurves,
+ filletChamferData[counter - counterCurves][X]),
+ &intpart);
+ }
+ double resultLenght =
+ it1_length + fillet_chamfer_values.to_len(
+ counter + 1, filletChamferData[counter + 1][X]);
+ time_it1_B = 1;
+ if (path_it->closed() && curve_it2 == curve_endit) {
+ resultLenght =
+ it1_length + fillet_chamfer_values.to_len(
+ counter - counterCurves,
+ filletChamferData[counter - counterCurves][X]);
+ }
+ if (resultLenght > 0 && time_it2 != 0) {
+ time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght),
+ &intpart);
+ } else {
+ if (time_it2 == 0) {
+ time_it1_B = 1;
+ } else {
+ time_it1_B = gapHelper;
+ }
+ }
+ if (filletChamferData[counter + 1][Y] == 0) {
+ time_it1_B = 1;
+ time_it2 = 0;
+ }
+ if (time_it1_B < time_it1) {
+ time_it1_B = time_it1 + gapHelper;
+ }
+ Curve *knotCurve1 = curve_it1->portion(time_it1, time_it1_B);
+ if (counterCurves > 0) {
+ knotCurve1->setInitial(path_out.finalPoint());
+ } else {
+ path_out.start((*curve_it1).pointAt(time_it1));
+ }
+ Curve *knotCurve2 = (*path_it).front().portion(time_it2, 1);
+ if (curve_it2 != curve_endit) {
+ knotCurve2 = (*curve_it2).portion(time_it2, 1);
+ }
+ Point startArcPoint = knotCurve1->finalPoint();
+ Point endArcPoint = (*path_it).front().pointAt(time_it2);
+ if (curve_it2 != curve_endit) {
+ endArcPoint = (*curve_it2).pointAt(time_it2);
+ }
+ double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K;
+ double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K;
+ Geom::CubicBezier const *cubic1 =
+ dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
+ Ray ray1(startArcPoint, curve_it1->finalPoint());
+ if (cubic1) {
+ ray1.setPoints((*cubic1)[2], startArcPoint);
+ }
+ Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint;
+ Geom::CubicBezier const *cubic2 =
+ dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
+ Ray ray2(curve_it1->finalPoint(), endArcPoint);
+ if (cubic2) {
+ ray2.setPoints(endArcPoint, (*cubic2)[1]);
+ }
+ Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2);
+ bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint,
+ endArcPoint - startArcPoint) < 0;
+ double angle = angle_between(ray1, ray2, ccwToggle);
+ double handleAngle = ray1.angle() - angle;
+ if (ccwToggle) {
+ handleAngle = ray1.angle() + angle;
+ }
+ Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint;
+ handleAngle = ray2.angle() + angle;
+ if (ccwToggle) {
+ handleAngle = ray2.angle() - angle;
+ }
+ Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2);
+ if (time_it1_B != 1) {
+ if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) {
+ path_out.append(*knotCurve1);
+ }
+ int type = abs(filletChamferData[counter + 1][Y]);
+ if (type == 3 || type == 4) {
+ if (type == 4) {
+ Geom::Point central = middle_point(startArcPoint, endArcPoint);
+ LineSegment chamferCenter(central, curve_it1->finalPoint());
+ path_out.appendNew<Geom::LineSegment>(chamferCenter.pointAt(0.5));
+ }
+ path_out.appendNew<Geom::LineSegment>(endArcPoint);
+ } else if (type == 2) {
+ path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2,
+ endArcPoint);
+ } else {
+ path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint);
+ }
+ } else {
+ path_out.append(*knotCurve1);
+ }
+ if (path_it->closed() && curve_it2 == curve_endit) {
+ path_out.close();
+ }
+ ++curve_it1;
+ if (curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ counter++;
+ counterCurves++;
+ }
+ pathvector_out.push_back(path_out);
+ }
+ return pathvector_out;
+}
+
+}; //namespace LivePathEffect
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offset:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h
new file mode 100644
index 000000000..f5eee0205
--- /dev/null
+++ b/src/live_effects/lpe-fillet-chamfer.h
@@ -0,0 +1,68 @@
+#ifndef INKSCAPE_LPE_FILLET_CHAMFER_H
+#define INKSCAPE_LPE_FILLET_CHAMFER_H
+
+/*
+ * Inkscape::LPEFilletChamfer
+ * 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 "live_effects/parameter/enum.h"
+#include "live_effects/parameter/unit.h"
+#include "live_effects/effect.h"
+#include "live_effects/parameter/bool.h"
+#include "live_effects/parameter/filletchamferpointarray.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEFilletChamfer : public Effect {
+
+public:
+ LPEFilletChamfer(LivePathEffectObject *lpeobject);
+ virtual ~LPEFilletChamfer();
+
+ std::vector<Geom::Path> doEffect_path(std::vector<Geom::Path> const &path_in);
+
+ virtual void doOnApply(SPLPEItem const *lpeItem);
+ virtual void doBeforeEffect(SPLPEItem const *lpeItem);
+ virtual int getKnotsNumber(SPCurve const *c);
+ virtual void adjustForNewPath(std::vector<Geom::Path> const &path_in);
+ virtual void toggleHide();
+ virtual void toggleFlexFixed();
+ virtual void chamfer();
+ virtual void fillet();
+ virtual void doubleChamfer();
+ virtual void inverse();
+ virtual void updateFillet();
+ virtual void doUpdateFillet(std::vector<Geom::Path> original_pathv,
+ double power);
+ virtual void doChangeType(std::vector<Geom::Path> original_pathv, int type);
+ virtual bool nodeIsSelected(Geom::Point nodePoint,
+ std::vector<Geom::Point> points);
+ virtual void refreshKnots();
+ virtual Gtk::Widget *newWidget();
+ FilletChamferPointArrayParam fillet_chamfer_values;
+
+private:
+
+ BoolParam hide_knots;
+ BoolParam ignore_radius_0;
+ BoolParam only_selected;
+ BoolParam flexible;
+ UnitParam unit;
+ ScalarParam radius;
+ ScalarParam helper_size;
+
+ LPEFilletChamfer(const LPEFilletChamfer &);
+ LPEFilletChamfer &operator=(const LPEFilletChamfer &);
+
+};
+
+}; //namespace LivePathEffect
+}; //namespace Inkscape
+#endif
diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert
index 330035ad6..f990f41c7 100644
--- a/src/live_effects/parameter/Makefile_insert
+++ b/src/live_effects/parameter/Makefile_insert
@@ -24,6 +24,8 @@ ink_common_sources += \
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 \
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
new file mode 100644
index 000000000..5eb87aad5
--- /dev/null
+++ b/src/live_effects/parameter/filletchamferpointarray.cpp
@@ -0,0 +1,655 @@
+/*
+ * 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 <gtkmm.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 <cmath>
+#include "ui/tools/node-tool.h"
+#include <glibmm/i18n.h>
+
+using namespace Geom;
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+FilletChamferPointArrayParam::FilletChamferPointArrayParam(
+ const Glib::ustring &label, const Glib::ustring &tip,
+ const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
+ Effect *effect)
+ : ArrayParam<Point>(label, tip, key, wr, effect, 0)
+{
+ knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ knot_mode = SP_KNOT_MODE_XOR;
+ knot_color = 0x00ff0000;
+}
+
+FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {}
+
+Gtk::Widget *FilletChamferPointArrayParam::param_newWidget()
+{
+ return NULL;
+ /*
+ Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg =
+ Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredTransformedPoint(
+ param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ param_effect->getRepr(),
+ param_effect->getSPDoc()
+ ) );
+ // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Affine transf = desktop->doc2dt();
+ pointwdg->setTransform(transf);
+ pointwdg->setValue( *this );
+ pointwdg->clearProgrammatically();
+ pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Change point parameter"));
+
+ Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
+ static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
+ static_cast<Gtk::HBox*>(hbox)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (hbox);
+ */
+}
+
+void
+FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul,
+ bool /*set*/)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ if (prefs->getBool("/options/transform/rectcorners", true) &&
+ _vector[1][X] <= 0) {
+ std::vector<Geom::Point> result;
+ for (std::vector<Point>::const_iterator point_it = _vector.begin();
+ point_it != _vector.end(); ++point_it) {
+ Coord A =
+ (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2);
+ result.push_back(Point(A, (*point_it)[Y]));
+ }
+ param_set_and_write_new_value(result);
+ }
+
+ // param_set_and_write_new_value( (*this) * postmul );
+}
+
+/** call this method to recalculate the controlpoints such that they stay at the
+ * same location relative to the new path. Useful after adding/deleting nodes to
+ * the path.*/
+void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
+ Piecewise<D2<SBasis> > const &pwd2_in)
+{
+ if (!last_pwd2.empty()) {
+ PathVector const pathv =
+ path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
+ PathVector last_pathv =
+ path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001);
+ std::vector<Point> result;
+ unsigned long counter = 0;
+ unsigned long counterPaths = 0;
+ unsigned long counterCurves = 0;
+ long offset = 0;
+ long offsetPaths = 0;
+ Geom::NodeType nodetype;
+ for (PathVector::const_iterator path_it = pathv.begin();
+ path_it != pathv.end(); ++path_it) {
+ if (path_it->empty()) {
+ counterPaths++;
+ counter++;
+ continue;
+ }
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed() && path_it->back_closed().isDegenerate()) {
+ const Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ counterCurves = 0;
+ while (curve_it1 != curve_endit) {
+ //if start a path get node type
+ if (counterCurves == 0) {
+ if (path_it->closed()) {
+ if (path_it->back_closed().isDegenerate()) {
+ nodetype = get_nodetype(path_it->back_open(), *curve_it1);
+ } else {
+ nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
+ }
+ } else {
+ nodetype = NODE_NONE;
+ }
+ } else {
+ //check node type also whith straight lines because get_nodetype
+ //return non cusp node in a node inserted inside a straight line
+ //todo: if the path remove some nodes whith the result of a straight
+ //line but with handles, the node inserted into dont fire the knot
+ // because is not handle as cusp node by get_nodetype function
+ bool this_is_line = true;
+ bool next_is_line = is_straight_curve(*curve_it1);
+ this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
+ nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
+ if (this_is_line || next_is_line) {
+ nodetype = NODE_CUSP;
+ }
+ }
+ if (last_pathv.size() > pathv.size() ||
+ (last_pathv[counterPaths].size() > counter - offset &&
+ !are_near(curve_it1->initialPoint(),
+ last_pathv[counterPaths][counter - offset].initialPoint(),
+ 0.1))) {
+ if (last_pathv.size() > counterPaths && curve_it2 == curve_endit) {
+ if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) {
+ offset = abs(last_pathv[counterPaths].size() -
+ pathv[counterPaths].size());
+ } else if (last_pathv[counterPaths].size() >
+ pathv[counterPaths].size()) {
+ offset = (abs(last_pathv[counterPaths].size() -
+ pathv[counterPaths].size())) * -1;
+ } else {
+ offset = 0;
+ }
+ offsetPaths += offset;
+ offset = offsetPaths;
+ } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() &&
+ counter - offset <= last_pathv[counterPaths].size() &&
+ are_near(curve_it1->initialPoint(),
+ last_pathv[counterPaths].finalPoint(), 0.1) &&
+ !last_pathv[counterPaths].closed()) {
+ long e = counter - offset + 1;
+ std::vector<Point> tmp = _vector;
+ for (unsigned long i =
+ last_pathv[counterPaths].size() + counter - offset;
+ i > counterCurves - offset + 1; i--) {
+
+ if (tmp[i - 1][X] > 0) {
+ double fractpart, intpart;
+ fractpart = modf(tmp[i - 1][X], &intpart);
+ _vector[e] = Point(e + fractpart, tmp[i - 1][Y]);
+ } else {
+ _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]);
+ }
+ e++;
+ }
+ //delete temp vector
+ std::vector<Point>().swap(tmp);
+ if (last_pathv.size() > counterPaths) {
+ last_pathv[counterPaths] = last_pathv[counterPaths].reverse();
+ }
+ } else {
+ if (last_pathv.size() > counterPaths) {
+ if (last_pathv[counterPaths].size() <
+ pathv[counterPaths].size()) {
+ offset++;
+ } else if (last_pathv[counterPaths].size() >
+ pathv[counterPaths].size()) {
+ offset--;
+ continue;
+ }
+ } else {
+ offset++;
+ }
+ }
+ double xPos = 0;
+ if (_vector[1][X] > 0) {
+ xPos = nearest_point(curve_it1->initialPoint(), pwd2_in);
+ }
+ if (nodetype == NODE_CUSP) {
+ result.push_back(Point(xPos, 1));
+ } else {
+ result.push_back(Point(xPos, 0));
+ }
+ } else {
+ double xPos = _vector[counter - offset][X];
+ if (_vector.size() <= (unsigned)(counter - offset)) {
+ if (_vector[1][X] > 0) {
+ xPos = nearest_point(curve_it1->initialPoint(), pwd2_in);
+ } else {
+ xPos = 0;
+ }
+ }
+ if (nodetype == NODE_CUSP) {
+ double vectorY = _vector[counter - offset][Y];
+ if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) {
+ vectorY = 1;
+ }
+ result.push_back(Point(xPos, vectorY));
+ } else {
+ if (_vector[1][X] < 0) {
+ xPos = 0;
+ }
+ result.push_back(Point(floor(xPos), 0));
+ }
+ }
+ ++curve_it1;
+ if (curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ counter++;
+ counterCurves++;
+ }
+ counterPaths++;
+ }
+ _vector = result;
+ write_to_SVG();
+ }
+}
+
+void FilletChamferPointArrayParam::recalculate_knots(
+ Piecewise<D2<SBasis> > const &pwd2_in)
+{
+ bool change = false;
+ PathVector pathv = path_from_piecewise(pwd2_in, 0.001);
+ if (!pathv.empty()) {
+ std::vector<Point> result;
+ int counter = 0;
+ int counterCurves = 0;
+ Geom::NodeType nodetype;
+ for (PathVector::const_iterator path_it = pathv.begin();
+ path_it != pathv.end(); ++path_it) {
+ if (path_it->empty()) {
+ counter++;
+ continue;
+ }
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed() && path_it->back_closed().isDegenerate()) {
+ const Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ counterCurves = 0;
+ while (curve_it1 != curve_endit) {
+ //if start a path get node type
+ if (counterCurves == 0) {
+ if (path_it->closed()) {
+ if (path_it->back_closed().isDegenerate()) {
+ nodetype = get_nodetype(path_it->back_open(), *curve_it1);
+ } else {
+ nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
+ }
+ } else {
+ nodetype = NODE_NONE;
+ }
+ } else {
+ bool this_is_line = true;
+ bool next_is_line = is_straight_curve(*curve_it1);
+ this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
+ nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
+ if (this_is_line || next_is_line) {
+ nodetype = NODE_CUSP;
+ }
+ }
+ if (nodetype == NODE_CUSP) {
+ double vectorY = _vector[counter][Y];
+ if (vectorY == 0) {
+ vectorY = 1;
+ change = true;
+ }
+ result.push_back(Point(_vector[counter][X], vectorY));
+ } else {
+ double xPos = floor(_vector[counter][X]);
+ if (_vector[1][X] < 0) {
+ xPos = 0;
+ }
+ double vectorY = _vector[counter][Y];
+ if (vectorY != 0) {
+ change = true;
+ }
+ result.push_back(Point(xPos, 0));
+ }
+ ++curve_it1;
+ ++curve_it2;
+ if (curve_it2 != curve_endit) {
+ counter++;
+ }
+ counterCurves++;
+ }
+ }
+ if (change) {
+ _vector = result;
+ write_to_SVG();
+ }
+ }
+}
+
+void FilletChamferPointArrayParam::set_pwd2(
+ Piecewise<D2<SBasis> > const &pwd2_in,
+ Piecewise<D2<SBasis> > const &pwd2_normal_in)
+{
+ last_pwd2 = pwd2_in;
+ last_pwd2_normal = pwd2_normal_in;
+}
+
+void FilletChamferPointArrayParam::set_helper_size(int hs)
+{
+ helper_size = hs;
+}
+
+void FilletChamferPointArrayParam::set_unit(const gchar *abbr)
+{
+ unit = abbr;
+}
+
+void FilletChamferPointArrayParam::updateCanvasIndicators()
+{
+ std::vector<Point> ts = data();
+ hp.clear();
+ unsigned int i = 0;
+ Piecewise<D2<SBasis> > const &n = get_pwd2_normal();
+ for (std::vector<Point>::const_iterator point_it = ts.begin();
+ point_it != ts.end(); ++point_it) {
+ double Xvalue = to_time(i, (*point_it)[X]);
+ double XPlusValue = to_time(i, -helper_size) - i;
+ if (Xvalue == i) {
+ i++;
+ continue;
+ }
+ Point canvas_point = last_pwd2.valueAt(Xvalue) + 0 * n.valueAt(Xvalue);
+ Point start_point = last_pwd2.valueAt(Xvalue + XPlusValue) +
+ helper_size * n.valueAt(Xvalue + XPlusValue);
+ Point end_point = last_pwd2.valueAt(Xvalue + XPlusValue) -
+ helper_size * n.valueAt(Xvalue + XPlusValue);
+ Geom::Path arrow;
+ arrow.start(start_point);
+ arrow.appendNew<Geom::LineSegment>(canvas_point);
+ arrow.appendNew<Geom::LineSegment>(end_point);
+ hp.push_back(arrow);
+ i++;
+ }
+}
+
+void FilletChamferPointArrayParam::addCanvasIndicators(
+ SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(hp);
+}
+
+double FilletChamferPointArrayParam::len_to_time(int index, double len)
+{
+ double t = 0;
+ if (last_pwd2.size() > (unsigned) index) {
+ if (len != 0) {
+ if (last_pwd2[index][0].degreesOfFreedom() != 2) {
+ Piecewise<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[index], 1);
+ std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len));
+ if (t_roots.size() > 0) {
+ t = t_roots[0];
+ }
+ } else {
+ double lenghtPart = 0;
+ if (last_pwd2.size() > (unsigned) index) {
+ lenghtPart = length(last_pwd2[index], EPSILON);
+ }
+ if (std::abs(len) < lenghtPart && lenghtPart != 0) {
+ t = std::abs(len) / lenghtPart;
+ }
+ }
+ }
+ t = double(index) + t;
+ } else {
+ t = double(last_pwd2.size() - 1);
+ }
+
+ return t;
+}
+
+double FilletChamferPointArrayParam::time_to_len(int index, double time)
+{
+ double intpart;
+ double len = 0;
+ time = modf(time, &intpart);
+ double lenghtPart = 0;
+ if (last_pwd2.size() <= (unsigned) index || time == 0) {
+ return len;
+ }
+ if (last_pwd2[index][0].degreesOfFreedom() != 2) {
+ Piecewise<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[index], 1);
+ u = portion(u, 0, time);
+ return length(u, 0.001) * -1;
+ }
+ lenghtPart = length(last_pwd2[index], EPSILON);
+ return (time * lenghtPart) * -1;
+}
+
+double FilletChamferPointArrayParam::to_time(int index, double A)
+{
+ if (A > 0) {
+ return A;
+ } else {
+ return len_to_time(index, A);
+ }
+}
+
+double FilletChamferPointArrayParam::to_len(int index, double A)
+{
+ if (A > 0) {
+ return time_to_len(index, A);
+ } else {
+ return A;
+ }
+}
+
+void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
+ SPKnotModeType mode,
+ guint32 color)
+{
+ knot_shape = shape;
+ knot_mode = mode;
+ knot_color = color;
+}
+/*
+class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity {
+public:
+ FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam
+*p, unsigned int index);
+ virtual ~FilletChamferPointArrayParamKnotHolderEntity() {}
+
+ virtual void knot_set(Point const &p, Point const &origin, guint state);
+ virtual Point knot_get() const;
+ virtual void knot_click(guint state);
+ virtual void knot_doubleclicked(guint state);
+
+ /Checks whether the index falls within the size of the parameter's vector/
+ bool valid_index(unsigned int index) const {
+ return (_pparam->_vector.size() > index);
+ };
+
+private:
+ FilletChamferPointArrayParam *_pparam;
+ unsigned int _index;
+};
+/*/
+
+FilletChamferPointArrayParamKnotHolderEntity::
+FilletChamferPointArrayParamKnotHolderEntity(
+ FilletChamferPointArrayParam *p, unsigned int index)
+ : _pparam(p), _index(index) {}
+
+void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p,
+ Point const &origin,
+ guint state)
+{
+ using namespace Geom;
+
+ if (!valid_index(_index)) {
+ return;
+ }
+ /// @todo how about item transforms???
+ Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
+ //todo: add snapping
+ //Geom::Point const s = snap_knot_position(p, state);
+ double t = nearest_point(p, pwd2[_index]);
+ if (t == 1) {
+ t = 0.9999;
+ }
+ t += _index;
+
+ if (_pparam->_vector.at(_index)[X] <= 0) {
+ _pparam->_vector.at(_index) =
+ Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]);
+ } else {
+ _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]);
+ }
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+}
+
+Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const
+{
+ using namespace Geom;
+
+ if (!valid_index(_index)) {
+ return Point(infinity(), infinity());
+ }
+
+ Piecewise<D2<SBasis> > const &pwd2 = _pparam->get_pwd2();
+
+ double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]);
+ Point canvas_point = pwd2.valueAt(time_it);
+
+ _pparam->updateCanvasIndicators();
+ return canvas_point;
+
+}
+
+void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state)
+{
+ if (state & GDK_CONTROL_MASK) {
+ using namespace Geom;
+ double type = _pparam->_vector.at(_index)[Y] + 1;
+ if (type > 4) {
+ type = 1;
+ }
+ _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type);
+ _pparam->param_set_and_write_new_value(_pparam->_vector);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ const gchar *tip;
+ if (type == 3) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (type == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (type == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ }
+ this->knot->tip = g_strdup(tip);
+ this->knot->show();
+ //}
+ } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) {
+ Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(),
+ _pparam->_vector.at(_index).y());
+ Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
+ this->desktop, offset, this, _pparam->unit);
+ }
+
+}
+
+void
+FilletChamferPointArrayParamKnotHolderEntity::knot_doubleclicked(guint state)
+{
+ //todo: fill the double click dialog whith this parameters in the added file
+ //src/ui/dialog/lpe-fillet-chamfer-properties.cpp(.h)
+ //My idea for when have enought time is:
+ //label whith radius in percent
+ //label whith radius in size -maybe handle units-
+ //entry whith actual radius -in flexible % mode or fixed -?px-
+ //2 radio options to switch entry from fixed or flexible, also update the
+ //entry
+ //Checkbox or two radios to swith fillet or chamfer
+
+}
+
+void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
+ Geom::Point offset)
+{
+ _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y());
+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
+}
+
+void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
+ SPDesktop *desktop,
+ SPItem *item)
+{
+ recalculate_knots(get_pwd2());
+ for (unsigned int i = 0; i < _vector.size(); ++i) {
+ if (_vector[i][Y] <= 0) {
+ continue;
+ }
+ const gchar *tip;
+ if (_vector[i][Y] == 3) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (_vector[i][Y] == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (_vector[i][Y] == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ }
+ FilletChamferPointArrayParamKnotHolderEntity *e =
+ new FilletChamferPointArrayParamKnotHolderEntity(this, i);
+ e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
+ knot_shape, knot_mode, knot_color);
+ knotholder->add(e);
+ }
+ updateCanvasIndicators();
+}
+
+} /* namespace LivePathEffect */
+
+} /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h
new file mode 100644
index 000000000..93d6e9f4c
--- /dev/null
+++ b/src/live_effects/parameter/filletchamferpointarray.h
@@ -0,0 +1,117 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
+#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * Special thanks to Johan Engelen for the base of the effect -powerstroke-
+ * Also to ScislaC for point me to the idea
+ * Also su_v for his construvtive feedback and time
+ * and finaly to Liam P. White for his big help on coding, that save me a lot of
+ * hours
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <2geom/point.h>
+
+#include "live_effects/parameter/array.h"
+
+#include "knot-holder-entity.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class FilletChamferPointArrayParamKnotHolderEntity;
+
+class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> {
+public:
+ FilletChamferPointArrayParam(const Glib::ustring &label,
+ const Glib::ustring &tip,
+ const Glib::ustring &key,
+ Inkscape::UI::Widget::Registry *wr,
+ Effect *effect);
+ virtual ~FilletChamferPointArrayParam();
+
+ virtual Gtk::Widget *param_newWidget();
+
+ virtual void param_transform_multiply(Geom::Affine const &postmul,
+ bool /*set*/);
+
+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode,
+ guint32 color);
+ virtual double to_time(int index, double A);
+ virtual double to_len(int index, double A);
+ virtual double len_to_time(int index, double len);
+ virtual double time_to_len(int index, double time);
+ virtual void set_helper_size(int hs);
+ virtual void set_unit(const gchar *abbr);
+ virtual void addCanvasIndicators(SPLPEItem const *lpeitem,
+ std::vector<Geom::PathVector> &hp_vec);
+ virtual bool providesKnotHolderEntities() const {
+ return true;
+ }
+ virtual void updateCanvasIndicators();
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop,
+ SPItem *item);
+
+ void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in,
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const {
+ return last_pwd2;
+ }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const {
+ return last_pwd2_normal;
+ }
+
+ void recalculate_controlpoints_for_new_pwd2(
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
+ void recalculate_knots(
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
+ friend class FilletChamferPointArrayParamKnotHolderEntity;
+
+private:
+ FilletChamferPointArrayParam(const FilletChamferPointArrayParam &);
+ FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &);
+
+ SPKnotShapeType knot_shape;
+ SPKnotModeType knot_mode;
+ guint32 knot_color;
+ int helper_size;
+ const gchar *unit;
+ Geom::PathVector hp;
+
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2;
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
+};
+
+class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity {
+public:
+ FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p,
+ unsigned int index);
+ virtual ~FilletChamferPointArrayParamKnotHolderEntity() {}
+
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin,
+ guint state);
+ virtual Geom::Point knot_get() const;
+ virtual void knot_click(guint state);
+ virtual void knot_doubleclicked(guint state);
+ virtual void knot_set_offset(Geom::Point offset);
+
+ /*Checks whether the index falls within the size of the parameter's vector*/
+ bool valid_index(unsigned int index) const {
+ return (_pparam->_vector.size() > index);
+ }
+ ;
+
+private:
+ FilletChamferPointArrayParam *_pparam;
+ unsigned int _index;
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index d2f6d692a..3f5925d83 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -4062,10 +4062,6 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) {
for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) {
// Collect all clipped paths and masks within a single group
Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc);
- if(copy->attribute("inkscape:original-d"))
- {
- copy->setAttribute("d", copy->attribute("inkscape:original-d"));
- }
items_to_move = g_slist_prepend(items_to_move, copy);
}
diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp
index 428e0e3dd..cda59e057 100644
--- a/src/sp-ellipse.cpp
+++ b/src/sp-ellipse.cpp
@@ -467,8 +467,6 @@ void SPGenericEllipse::set_shape()
bool success = this->performPathEffect(c_lpe);
if (success) {
- sp_lpe_item_apply_to_mask(this);
- sp_lpe_item_apply_to_clippath(this);
this->setCurveInsync(c_lpe, TRUE);
}
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index 8c8a1e45d..fbd9a6538 100644
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
@@ -790,31 +790,17 @@ void SPGroup::update_patheffect(bool write) {
}
}
-
-void
-sp_gslist_update_by_clip_or_mask(GSList *item_list,SPItem * item)
-{
- if(item->mask_ref->getObject()) {
- SPObject * clipormask = item->mask_ref->getObject()->firstChild();
- item_list = g_slist_append(item_list,clipormask);
- }
- if(item->clip_ref->getObject()) {
- SPObject * clipormask = item->clip_ref->getObject()->firstChild();
- item_list = g_slist_append(item_list,clipormask);
- }
-}
-
static void
sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write)
{
- GSList *item_list = sp_item_group_item_list(group);
- sp_gslist_update_by_clip_or_mask(item_list,group);
- for ( GSList *iter = item_list; iter; iter = iter->next ) {
+ GSList const *item_list = sp_item_group_item_list(SP_GROUP(group));
+
+ for ( GSList const *iter = item_list; iter; iter = iter->next ) {
SPObject *subitem = static_cast<SPObject *>(iter->data);
+
if (SP_IS_GROUP(subitem)) {
sp_group_perform_patheffect(SP_GROUP(subitem), topgroup, write);
} else if (SP_IS_SHAPE(subitem)) {
- sp_gslist_update_by_clip_or_mask(item_list,SP_ITEM(subitem));
SPCurve * c = NULL;
if (SP_IS_PATH(subitem)) {
@@ -825,17 +811,9 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write)
// only run LPEs when the shape has a curve defined
if (c) {
- if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) {
- c->transform(i2anc_affine(group, topgroup));
- } else {
- c->transform(i2anc_affine(subitem, topgroup));
- }
+ c->transform(i2anc_affine(subitem, topgroup));
SP_LPE_ITEM(topgroup)->performPathEffect(c);
- if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) {
- c->transform(i2anc_affine(group, topgroup).inverse());
- } else {
- c->transform(i2anc_affine(subitem, topgroup).inverse());
- }
+ c->transform(i2anc_affine(subitem, topgroup).inverse());
SP_SHAPE(subitem)->setCurve(c, TRUE);
if (write) {
@@ -843,7 +821,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write)
gchar *str = sp_svg_write_path(c->get_pathvector());
repr->setAttribute("d", str);
#ifdef GROUP_VERBOSE
- g_message("sp_group_perform_patheffect writes 'd' attribute");
+g_message("sp_group_perform_patheffect writes 'd' attribute");
#endif
g_free(str);
}
diff --git a/src/sp-item-group.h b/src/sp-item-group.h
index ee3cd75f9..68bbd083a 100644
--- a/src/sp-item-group.h
+++ b/src/sp-item-group.h
@@ -96,7 +96,7 @@ public:
void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true);
-void sp_gslist_update_by_clip_or_mask(GSList *item_list, SPItem * item);
+
GSList *sp_item_group_item_list (SPGroup *group);
SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const gchar *name);
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index 74eb2af75..3d9bbd8ce 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -50,6 +50,8 @@
#include <algorithm>
/* LPEItem base class */
+static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
+
static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
@@ -113,7 +115,7 @@ void SPLPEItem::set(unsigned int key, gchar const* value) {
this->current_path_effect = NULL;
// Disable the path effects while populating the LPE list
- enablePathEffects(false);
+ sp_lpe_item_enable_path_effects(this, false);
// disconnect all modified listeners:
for ( std::list<sigc::connection>::iterator mod_it = this->lpe_modified_connection_list->begin();
@@ -166,7 +168,7 @@ void SPLPEItem::set(unsigned int key, gchar const* value) {
}
}
- enablePathEffects(true);
+ sp_lpe_item_enable_path_effects(this, true);
}
break;
@@ -341,22 +343,6 @@ static void
sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
{
g_return_if_fail(lpeitem != NULL);
- SPMask * mask = lpeitem->mask_ref->getObject();
-
- if (mask)
- {
- if (SPLPEItem* maskChild = dynamic_cast<SPLPEItem*>(mask->firstChild())) {
- sp_lpe_item_create_original_path_recursive(maskChild);
- }
- }
-
- SPClipPath * clipPath = lpeitem->clip_ref->getObject();
- if (clipPath)
- {
- if (SPLPEItem* clipChild = dynamic_cast<SPLPEItem*>(clipPath->firstChild())) {
- sp_lpe_item_create_original_path_recursive(clipChild);
- }
- }
if (SP_IS_GROUP(lpeitem)) {
GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
for ( GSList const *iter = item_list; iter; iter = iter->next ) {
@@ -378,23 +364,6 @@ static void
sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
{
g_return_if_fail(lpeitem != NULL);
- SPMask * mask = lpeitem->mask_ref->getObject();
-
- if (mask)
- {
- if (SPLPEItem* maskChild = dynamic_cast<SPLPEItem*>(mask->firstChild())) {
- sp_lpe_item_cleanup_original_path_recursive(maskChild);
- }
- }
-
- SPClipPath * clipPath = lpeitem->clip_ref->getObject();
- if (clipPath)
- {
- if (SPLPEItem* clipChild = dynamic_cast<SPLPEItem*>(clipPath->firstChild())) {
- sp_lpe_item_cleanup_original_path_recursive(clipChild);
- }
- }
-
if (SP_IS_GROUP(lpeitem)) {
GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
for ( GSList const *iter = item_list; iter; iter = iter->next ) {
@@ -424,7 +393,7 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset)
sp_lpe_item_update_patheffect(this, false, true);
// Disable the path effects while preparing the new lpe
- enablePathEffects(false);
+ sp_lpe_item_enable_path_effects(this, false);
// Add the new reference to the list of LPE references
HRefList hreflist;
@@ -461,7 +430,7 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset)
}
//Enable the path effects now that everything is ready to apply the new path effect
- enablePathEffects(true);
+ sp_lpe_item_enable_path_effects(this, true);
// Apply the path effect
sp_lpe_item_update_patheffect(this, true, true);
@@ -643,6 +612,9 @@ bool SPLPEItem::hasPathEffectRecursive() const
}
}
+//The next 3 functions are because the revert of the bug 1241902
+//for the moment not used
+
void
sp_lpe_item_apply_to_clippath(SPItem * item)
{
@@ -976,6 +948,24 @@ bool SPLPEItem::forkPathEffectsIfNecessary(unsigned int nr_of_allowed_users)
return forked;
}
+// Enable or disable the path effects of the item.
+// The counter allows nested calls
+static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
+{
+ if (enable) {
+ lpeitem->path_effects_enabled++;
+ }
+ else {
+ lpeitem->path_effects_enabled--;
+ }
+}
+
+// Are the path effects enabled on this item ?
+bool SPLPEItem::pathEffectsEnabled() const
+{
+ return path_effects_enabled > 0;
+}
+
/*
Local Variables:
mode:c++
diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h
index 2bde25be8..3e858748d 100644
--- a/src/sp-lpe-item.h
+++ b/src/sp-lpe-item.h
@@ -39,13 +39,11 @@ namespace LivePathEffect{
typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList;
class SPLPEItem : public SPItem {
-private:
- mutable bool path_effects_enabled; // (mutable because preserves logical const-ness)
-
public:
- SPLPEItem();
- virtual ~SPLPEItem();
+ SPLPEItem();
+ virtual ~SPLPEItem();
+ int path_effects_enabled;
PathEffectList* path_effect_list;
std::list<sigc::connection> *lpe_modified_connection_list; // this list contains the connections for listening to lpeobject parameter changes
@@ -74,8 +72,7 @@ public:
bool performPathEffect(SPCurve *curve);
- void enablePathEffects(bool enable) const { path_effects_enabled = enable; }; // (const because logically const)
- bool pathEffectsEnabled() const { return path_effects_enabled; };
+ bool pathEffectsEnabled() const;
bool hasPathEffect() const;
bool hasPathEffectOfType(int const type) const;
bool hasPathEffectRecursive() const;
diff --git a/src/sp-path.cpp b/src/sp-path.cpp
index 9d88ec732..d1fb850e1 100644
--- a/src/sp-path.cpp
+++ b/src/sp-path.cpp
@@ -325,8 +325,6 @@ g_message("sp_path_update_patheffect");
bool success = this->performPathEffect(curve);
if (success && write) {
- sp_lpe_item_apply_to_mask(this);
- sp_lpe_item_apply_to_clippath(this);
// could also do this->getRepr()->updateRepr(); but only the d attribute needs updating.
#ifdef PATH_VERBOSE
g_message("sp_path_update_patheffect writes 'd' attribute");
diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp
index 8d4a37bf0..9ef73d56d 100644
--- a/src/sp-spiral.cpp
+++ b/src/sp-spiral.cpp
@@ -385,8 +385,6 @@ void SPSpiral::set_shape() {
bool success = this->performPathEffect(c_lpe);
if (success) {
- sp_lpe_item_apply_to_mask(this);
- sp_lpe_item_apply_to_clippath(this);
this->setCurveInsync( c_lpe, TRUE);
}
diff --git a/src/sp-star.cpp b/src/sp-star.cpp
index 170a863b5..eac33ed7b 100644
--- a/src/sp-star.cpp
+++ b/src/sp-star.cpp
@@ -465,8 +465,6 @@ void SPStar::set_shape() {
bool success = this->performPathEffect(c_lpe);
if (success) {
- sp_lpe_item_apply_to_mask(this);
- sp_lpe_item_apply_to_clippath(this);
this->setCurveInsync( c_lpe, TRUE);
}
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 7d80f1e36..125755c48 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -78,6 +78,7 @@ set(ui_SRC
dialog/layers.cpp
dialog/livepatheffect-add.cpp
dialog/livepatheffect-editor.cpp
+ dialog/lpe-fillet-chamfer-properties.cpp
dialog/memory.cpp
dialog/messages.cpp
dialog/new-from-template.cpp
@@ -198,6 +199,7 @@ set(ui_SRC
dialog/layers.h
dialog/livepatheffect-add.h
dialog/livepatheffect-editor.h
+ dialog/lpe-fillet-chamfer-properties.h
dialog/memory.h
dialog/messages.h
dialog/new-from-template.h
diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index 1aa73dc5b..26a59ce2c 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -120,4 +120,6 @@ ink_common_sources += \
ui/dialog/lpe-powerstroke-properties.h \
ui/dialog/objects.cpp \
ui/dialog/objects.h \
+ ui/dialog/lpe-fillet-chamfer-properties.cpp \
+ ui/dialog/lpe-fillet-chamfer-properties.h \
$(inkboard_dialogs)
diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h
index c523f041d..f77249abd 100644
--- a/src/ui/dialog/filedialogimpl-win32.h
+++ b/src/ui/dialog/filedialogimpl-win32.h
@@ -22,13 +22,14 @@
#endif
#endif
+#include "filedialogimpl-gtkmm.h"
+
#include "gc-core.h"
// define WINVER high enough so we get the correct OPENFILENAMEW size
#ifndef WINVER
#define WINVER 0x0500
#endif
#include <windows.h>
-#include "filedialogimpl-gtkmm.h"
namespace Inkscape
diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
new file mode 100644
index 000000000..e65b63e68
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
@@ -0,0 +1,257 @@
+/**
+ * From the code of Liam P.White from his Power Stroke Knot dialog
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if GLIBMM_DISABLE_DEPRECATED &&HAVE_GLIBMM_THREADS_H
+#include <glibmm/threads.h>
+#endif
+
+#include "lpe-fillet-chamfer-properties.h"
+#include <boost/lexical_cast.hpp>
+#include <gtkmm/stock.h>
+#include <glibmm/main.h>
+#include <glibmm/i18n.h>
+#include "inkscape.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "layer-manager.h"
+#include "message-stack.h"
+#include "desktop-handles.h"
+#include "sp-object.h"
+#include "sp-item.h"
+#include "verbs.h"
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "ui/icon-names.h"
+#include "ui/widget/imagetoggler.h"
+#include <cmath>
+#include <gtkmm/radiobutton.h>
+#include "util/units.h"
+
+//#include "event-context.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+FilletChamferPropertiesDialog::FilletChamferPropertiesDialog()
+ : _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+{
+ Gtk::Box *mainVBox = this->get_vbox();
+ mainVBox->set_homogeneous(false);
+ _layout_table.set_spacings(4);
+ _layout_table.resize(2, 2);
+
+ // Layer name widgets
+ _fillet_chamfer_position_entry.set_activates_default(true);
+ _fillet_chamfer_position_label.set_label(_("Radius (pixels):"));
+ _fillet_chamfer_position_label.set_alignment(1.0, 0.5);
+
+ _layout_table.attach(_fillet_chamfer_position_label, 0, 1, 0, 1, Gtk::FILL,
+ Gtk::FILL);
+ _layout_table.attach(_fillet_chamfer_position_entry, 1, 2, 0, 1,
+ Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+ _fillet_chamfer_type_fillet.set_label(_("Fillet"));
+ _fillet_chamfer_type_fillet.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_inverse_fillet.set_label(_("Inverse fillet"));
+ _fillet_chamfer_type_inverse_fillet.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_chamfer.set_label(_("Chamfer"));
+ _fillet_chamfer_type_chamfer.set_group(_fillet_chamfer_type_group);
+ _fillet_chamfer_type_double_chamfer.set_label(_("Double chamfer"));
+ _fillet_chamfer_type_double_chamfer.set_group(_fillet_chamfer_type_group);
+
+ mainVBox->pack_start(_layout_table, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_fillet, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_inverse_fillet, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_chamfer, true, true, 4);
+ mainVBox->pack_start(_fillet_chamfer_type_double_chamfer, true, true, 4);
+
+ // Buttons
+ _close_button.set_use_stock(true);
+ _close_button.set_label(Gtk::Stock::CANCEL.id);
+ _close_button.set_can_default();
+
+ _apply_button.set_use_underline(true);
+ _apply_button.set_can_default();
+
+ _close_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close));
+ _apply_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_apply));
+
+ signal_delete_event().connect(sigc::bind_return(
+ sigc::hide(sigc::mem_fun(*this, &FilletChamferPropertiesDialog::_close)),
+ true));
+
+ add_action_widget(_close_button, Gtk::RESPONSE_CLOSE);
+ add_action_widget(_apply_button, Gtk::RESPONSE_APPLY);
+
+ _apply_button.grab_default();
+
+ show_all_children();
+
+ set_focus(_fillet_chamfer_position_entry);
+}
+
+FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog()
+{
+
+ _setDesktop(NULL);
+}
+
+void FilletChamferPropertiesDialog::showDialog(
+ SPDesktop *desktop, Geom::Point knotpoint,
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt,
+ const gchar *unit)
+{
+ FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog();
+
+ dialog->_setDesktop(desktop);
+ dialog->_setUnit(unit);
+ dialog->_setKnotPoint(knotpoint);
+ dialog->_setPt(pt);
+
+ dialog->set_title(_("Modify Fillet-Chamfer"));
+ dialog->_apply_button.set_label(_("_Modify"));
+
+ dialog->set_modal(true);
+ desktop->setWindowTransient(dialog->gobj());
+ dialog->property_destroy_with_parent() = true;
+
+ dialog->show();
+ dialog->present();
+}
+
+void FilletChamferPropertiesDialog::_apply()
+{
+ std::istringstream i_pos(_fillet_chamfer_position_entry.get_text());
+ double d_pos, d_width;
+ if (i_pos >> d_pos) {
+ if (_fillet_chamfer_type_fillet.get_active() == true) {
+ d_width = 1;
+ } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) {
+ d_width = 2;
+ } else if (_fillet_chamfer_type_chamfer.get_active() == true) {
+ d_width = 3;
+ } else {
+ d_width = 4;
+ }
+ if (_flexible) {
+ if (d_pos > 99.99999 || d_pos < 0) {
+ d_pos = 0;
+ }
+ d_pos = _index + (d_pos / 100);
+ } else {
+ d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, "px");
+ d_pos = d_pos * -1;
+ }
+ _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width));
+ }
+ _close();
+}
+
+void FilletChamferPropertiesDialog::_close()
+{
+ _setDesktop(NULL);
+ destroy_();
+ Glib::signal_idle().connect(
+ sigc::bind_return(
+ sigc::bind(sigc::ptr_fun(&::operator delete), this),
+ false
+ )
+ );
+}
+
+bool FilletChamferPropertiesDialog::_handleKeyEvent(GdkEventKey *event)
+{
+ return false;
+}
+
+void FilletChamferPropertiesDialog::_handleButtonEvent(GdkEventButton *event)
+{
+ if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) {
+ _apply();
+ }
+}
+
+void FilletChamferPropertiesDialog::_setKnotPoint(Geom::Point knotpoint)
+{
+ double position;
+ if (knotpoint.x() > 0) {
+ double intpart;
+ position = modf(knotpoint[Geom::X], &intpart) * 100;
+ _flexible = true;
+ _index = intpart;
+ _fillet_chamfer_position_label.set_label(_("Position (%):"));
+ } else {
+ _flexible = false;
+ std::string posConcat =
+ std::string(_("Position (")) + std::string(unit) + std::string(")");
+ _fillet_chamfer_position_label.set_label(_(posConcat.c_str()));
+ position = knotpoint[Geom::X] * -1;
+ position = Inkscape::Util::Quantity::convert(position, "px", unit);
+ }
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << position;
+ _fillet_chamfer_position_entry.set_text(s.str());
+ if (knotpoint.y() == 1) {
+ _fillet_chamfer_type_fillet.set_active(true);
+ } else if (knotpoint.y() == 2) {
+ _fillet_chamfer_type_inverse_fillet.set_active(true);
+ } else if (knotpoint.y() == 3) {
+ _fillet_chamfer_type_chamfer.set_active(true);
+ } else if (knotpoint.y() == 1) {
+ _fillet_chamfer_type_double_chamfer.set_active(true);
+ }
+}
+
+void FilletChamferPropertiesDialog::_setPt(
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt)
+{
+ _knotpoint = const_cast<
+ Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *>(
+ pt);
+}
+
+void FilletChamferPropertiesDialog::_setUnit(const gchar *abbr)
+{
+ unit = abbr;
+}
+
+void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop)
+{
+ if (desktop) {
+ Inkscape::GC::anchor(desktop);
+ }
+ if (_desktop) {
+ Inkscape::GC::release(_desktop);
+ }
+ _desktop = desktop;
+}
+
+} // namespace
+} // namespace
+} // namespace
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim:
+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
+// :
diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h
new file mode 100644
index 000000000..d3e859bff
--- /dev/null
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h
@@ -0,0 +1,104 @@
+/**
+ *
+ * From the code of Liam P.White from his Power Stroke Knot dialog
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H
+#define INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H
+
+#include <2geom/point.h>
+#include <gtkmm.h>
+#include "live_effects/parameter/filletchamferpointarray.h"
+
+class SPDesktop;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+class FilletChamferPropertiesDialog : public Gtk::Dialog {
+public:
+ FilletChamferPropertiesDialog();
+ virtual ~FilletChamferPropertiesDialog();
+
+ Glib::ustring getName() const {
+ return "LayerPropertiesDialog";
+ }
+
+ static void showDialog(SPDesktop *desktop, Geom::Point knotpoint,
+ const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt,
+ const gchar *unit);
+
+protected:
+
+ SPDesktop *_desktop;
+ Inkscape::LivePathEffect::FilletChamferPointArrayParamKnotHolderEntity *
+ _knotpoint;
+
+ Gtk::Label _fillet_chamfer_position_label;
+ Gtk::Entry _fillet_chamfer_position_entry;
+ Gtk::RadioButton::Group _fillet_chamfer_type_group;
+ Gtk::RadioButton _fillet_chamfer_type_fillet;
+ Gtk::RadioButton _fillet_chamfer_type_inverse_fillet;
+ Gtk::RadioButton _fillet_chamfer_type_chamfer;
+ Gtk::RadioButton _fillet_chamfer_type_double_chamfer;
+
+ Gtk::Table _layout_table;
+ bool _position_visible;
+ double _index;
+
+ Gtk::Button _close_button;
+ Gtk::Button _apply_button;
+
+ sigc::connection _destroy_connection;
+
+ static FilletChamferPropertiesDialog &_instance() {
+ static FilletChamferPropertiesDialog instance;
+ return instance;
+ }
+
+ void _setDesktop(SPDesktop *desktop);
+ void _setPt(const Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity *pt);
+ void _setUnit(const gchar *abbr);
+ void _apply();
+ void _close();
+ bool _flexible;
+ const gchar *unit;
+ void _setKnotPoint(Geom::Point knotpoint);
+ void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
+
+ bool _handleKeyEvent(GdkEventKey *event);
+ void _handleButtonEvent(GdkEventButton *event);
+
+ friend class Inkscape::LivePathEffect::
+ FilletChamferPointArrayParamKnotHolderEntity;
+
+private:
+ FilletChamferPropertiesDialog(
+ FilletChamferPropertiesDialog const &); // no copy
+ FilletChamferPropertiesDialog &operator=(
+ FilletChamferPropertiesDialog const &); // no assign
+};
+
+} // namespace
+} // namespace
+} // namespace
+
+#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim:
+// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
+// :
diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp
index 03ac9dc64..459e64041 100644
--- a/src/ui/dialog/print.cpp
+++ b/src/ui/dialog/print.cpp
@@ -13,10 +13,6 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#ifdef WIN32
-#include <io.h>
-#include <windows.h>
-#endif
#include "print.h"
#include <gtkmm/stock.h>
@@ -33,6 +29,11 @@
#include <glibmm/i18n.h>
+#ifdef WIN32
+#include <io.h>
+#include <windows.h>
+#endif
+
static void draw_page(
#ifdef WIN32
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index d3746b878..cdbf34e9d 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -53,6 +53,7 @@ public:
void insertNodesAtExtrema(ExtremumType extremum);
void insertNodes();
+ void alertLPE();
void duplicateNodes();
void joinNodes();
void breakNodes();
@@ -104,7 +105,7 @@ private:
}
void _commit(CommitEvent cps);
- void _done(gchar const *reason, bool alert_LPE = false);
+ void _done(gchar const *reason, bool alert_LPE = true);
void _doneWithCleanup(gchar const *reason, bool alert_LPE = false);
guint32 _getOutlineColor(ShapeRole role, SPItem *item);
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 3beeed049..01cff5ad7 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -11,6 +11,7 @@
*/
#include "live_effects/lpe-powerstroke.h"
+#include "live_effects/lpe-fillet-chamfer.h"
#include <string>
#include <sstream>
#include <deque>
@@ -1300,11 +1301,20 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE)
_spcurve->set_pathvector(pathv);
if (alert_LPE) {
/// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming?
- if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) {
- PathEffectList effect_list = _path->getEffectList();
- LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() );
- if (lpe_pwr) {
- lpe_pwr->adjustForNewPath(pathv);
+ if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
+ if(thisEffect){
+ LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_pwr) {
+ lpe_pwr->adjustForNewPath(pathv);
+ }
+ }
+ thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER);
+ if(thisEffect){
+ LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe());
+ if (lpe_fll) {
+ lpe_fll->adjustForNewPath(pathv);
+ }
}
}
}
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index 0d8a2668b..aead3ebc0 100644
--- a/src/ui/tools/pen-tool.cpp
+++ b/src/ui/tools/pen-tool.cpp
@@ -958,40 +958,42 @@ void PenTool::_lastpointToCurve() {
// avoid that if the "red_curve" contains only two points ( rect ), it doesn't stop here.
if (this->npoints != 5 && !this->spiro && !this->bspline)
return;
- Geom::CubicBezier const * cubic;
- this->p[1] = this->red_curve->last_segment()->initialPoint() + (1./3)* (Geom::Point)(this->red_curve->last_segment()->finalPoint() - this->red_curve->last_segment()->initialPoint());
+
+ this->p[1] = this->red_curve->last_segment()->initialPoint() + (1./3.)*(this->red_curve->last_segment()->finalPoint() - this->red_curve->last_segment()->initialPoint());
//modificate the last segment of the green curve so it creates the type of node we need
- if(this->spiro||this->bspline){
- if(!this->green_curve->is_empty()){
+ if (this->spiro||this->bspline) {
+ if (!this->green_curve->is_empty()) {
Geom::Point A(0,0);
Geom::Point B(0,0);
Geom::Point C(0,0);
Geom::Point D(0,0);
- SPCurve * previous = new SPCurve();
- cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() );
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>( this->green_curve->last_segment() );
//We obtain the last segment 4 points in the previous curve
if ( cubic ){
A = (*cubic)[0];
B = (*cubic)[1];
- if(this->spiro){
- C = this->p[0] + (Geom::Point)(this->p[0] - this->p[1]);
- }else
- C = this->green_curve->last_segment()->finalPoint() + (1./3)* (Geom::Point)(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ if (this->spiro) {
+ C = this->p[0] + (this->p[0] - this->p[1]);
+ } else {
+ C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ }
D = (*cubic)[3];
- }else{
+ } else {
A = this->green_curve->last_segment()->initialPoint();
B = this->green_curve->last_segment()->initialPoint();
- if(this->spiro)
- C = this->p[0] + (Geom::Point)(this->p[0] - this->p[1]);
- else
- C = this->green_curve->last_segment()->finalPoint() + (1./3)* (Geom::Point)(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ if (this->spiro) {
+ C = this->p[0] + (this->p[0] - this->p[1]);
+ } else {
+ C = this->green_curve->last_segment()->finalPoint() + (1./3.)*(this->green_curve->last_segment()->initialPoint() - this->green_curve->last_segment()->finalPoint());
+ }
D = this->green_curve->last_segment()->finalPoint();
}
+ SPCurve *previous = new SPCurve();
previous->moveto(A);
previous->curveto(B, C, D);
- if( this->green_curve->get_segment_count() == 1){
+ if ( this->green_curve->get_segment_count() == 1) {
this->green_curve = previous;
- }else{
+ } else {
//we eliminate the last segment
this->green_curve->backspace();
//and we add it again with the recreation
@@ -999,7 +1001,7 @@ void PenTool::_lastpointToCurve() {
}
}
//if the last node is an union with another curve
- if(this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()){
+ if (this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()) {
this->_bspline_spiro_start_anchor(false);
}
}
@@ -1242,12 +1244,12 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
}
} else {
// Reset red curve
- Geom::CubicBezier const * cubic = NULL;
this->red_curve->reset();
// Destroy topmost green bpath
if (this->green_bpaths) {
- if (this->green_bpaths->data)
+ if (this->green_bpaths->data) {
sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data));
+ }
this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data);
}
// Get last segment
@@ -1270,17 +1272,16 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]);
}
- Geom::Point const pt((this->npoints < 4
- ? (Geom::Point)(crv->finalPoint())
- : this->p[3]));
+ Geom::Point const pt( (this->npoints < 4) ? crv->finalPoint() : this->p[3] );
this->npoints = 2;
// delete the last segment of the green curve
if( this->green_curve->get_segment_count() == 1){
this->npoints = 5;
if (this->green_bpaths) {
- if (this->green_bpaths->data)
+ if (this->green_bpaths->data) {
sp_canvas_item_destroy(SP_CANVAS_ITEM(this->green_bpaths->data));
+ }
this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data);
}
this->green_curve->reset();
@@ -1289,14 +1290,16 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
}
// assign the value of this->p[1] to the oposite of the green line last segment
if(this->spiro){
- cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment());
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment());
if ( cubic ) {
- this->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2]);
+ this->p[1] = (*cubic)[3] + (*cubic)[3] - (*cubic)[2];
SP_CTRL(this->c1)->moveto(this->p[0]);
} else {
this->p[1] = this->p[0];
}
}
+ sp_canvas_item_hide(this->c0);
+ sp_canvas_item_hide(this->c1);
sp_canvas_item_hide(this->cl0);
sp_canvas_item_hide(this->cl1);
this->state = PenTool::POINT;
@@ -1607,7 +1610,7 @@ void PenTool::_bspline_spiro_motion(bool shift){
if(shift)
this->p[2] = this->p[3];
}else{
- this->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2] );
+ this->p[1] = (*cubic)[3] + ((*cubic)[3] - (*cubic)[2] );
this->p[1] = Geom::Point(this->p[1][X] + 0.005,this->p[1][Y] + 0.005);
}
}else{
@@ -1659,7 +1662,7 @@ void PenTool::_bspline_spiro_end_anchor_on()
C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint());
C = Geom::Point(C[X] + 0.005,C[Y] + 0.005);
}else{
- C = this->p[3] + (Geom::Point)(this->p[3] - this->p[2] );
+ C = this->p[3] + this->p[3] - this->p[2];
}
if(cubic){
lastSeg->moveto((*cubic)[0]);
@@ -2164,7 +2167,7 @@ void PenTool::_finishSegment(Geom::Point const p, guint const state) {
pen_last_paraxial_dir = this->nextParaxialDirection(p, this->p[0], state);
}
- ++this->num_clicks;
+ ++num_clicks;
if (!this->red_curve->is_empty()) {
diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp
index 3932bdfd4..4754b9c23 100644
--- a/src/ui/widget/filter-effect-chooser.cpp
+++ b/src/ui/widget/filter-effect-chooser.cpp
@@ -58,15 +58,12 @@ const Glib::ustring SimpleFilterModifier::get_blend_mode()
if (!(_flags & BLEND)) {
return "normal";
}
- if (_blend.get_active_row_number() == 5) {
+
+ const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data();
+ if (d) {
+ return _blend.get_active_data()->key;
+ } else
return "normal";
- } else {
- const Util::EnumData<Inkscape::Filters::FilterBlendMode> *d = _blend.get_active_data();
- if (d) {
- return _blend.get_active_data()->key;
- } else
- return "normal";
- }
}
void SimpleFilterModifier::set_blend_mode(const int val)
diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp
index 3ba00c083..7f3e6cd47 100644
--- a/src/ui/widget/preferences-widget.cpp
+++ b/src/ui/widget/preferences-widget.cpp
@@ -14,10 +14,6 @@
# include <config.h>
#endif
-#ifdef WIN32
-#include <windows.h>
-#endif
-
#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
#include <glibmm/threads.h>
#endif
@@ -49,6 +45,10 @@
#include <glibmm/convert.h>
#include <glibmm/i18n.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
+
using namespace Inkscape::UI::Widget;
namespace Inkscape {