summaryrefslogtreecommitdiffstats
path: root/src/live_effects/parameter/nodesatellitesarray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects/parameter/nodesatellitesarray.cpp')
-rw-r--r--src/live_effects/parameter/nodesatellitesarray.cpp569
1 files changed, 569 insertions, 0 deletions
diff --git a/src/live_effects/parameter/nodesatellitesarray.cpp b/src/live_effects/parameter/nodesatellitesarray.cpp
new file mode 100644
index 0000000..5f12f4c
--- /dev/null
+++ b/src/live_effects/parameter/nodesatellitesarray.cpp
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ *
+ * Copyright (C) 2014 Author(s)
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "nodesatellitesarray.h"
+
+#include "helper/geom.h"
+#include "inkscape.h"
+#include "live_effects/effect.h"
+#include "live_effects/lpe-fillet-chamfer.h"
+#include "preferences.h"
+#include "ui/dialog/lpe-fillet-chamfer-properties.h"
+#include "ui/knot/knot-holder.h"
+#include "ui/shape-editor.h"
+#include "ui/tools/node-tool.h"
+
+// TODO due to internal breakage in glibmm headers,
+// this has to be included last.
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+NodeSatelliteArrayParam::NodeSatelliteArrayParam(const Glib::ustring &label, const Glib::ustring &tip,
+ const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
+ Effect *effect)
+ : ArrayParam<std::vector<NodeSatellite>>(label, tip, key, wr, effect, 0)
+ , _knoth(nullptr)
+{
+ param_widget_is_visible(false);
+}
+
+void NodeSatelliteArrayParam::set_oncanvas_looks(Inkscape::CanvasItemCtrlShape shape, Inkscape::CanvasItemCtrlMode mode,
+ guint32 color)
+{
+ _knot_shape = shape;
+ _knot_mode = mode;
+ _knot_color = color;
+}
+
+void NodeSatelliteArrayParam::setPathVectorNodeSatellites(PathVectorNodeSatellites *pathVectorNodeSatellites,
+ bool write)
+{
+ _last_pathvector_nodesatellites = pathVectorNodeSatellites;
+ if (write) {
+ param_set_and_write_new_value(_last_pathvector_nodesatellites->getNodeSatellites());
+ } else {
+ param_setValue(_last_pathvector_nodesatellites->getNodeSatellites());
+ }
+}
+
+void NodeSatelliteArrayParam::reloadKnots()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ Inkscape::UI::Tools::NodeTool *nt = dynamic_cast<Inkscape::UI::Tools::NodeTool *>(desktop->event_context);
+ if (nt) {
+ for (auto &_shape_editor : nt->_shape_editors) {
+ Inkscape::UI::ShapeEditor *shape_editor = _shape_editor.second.get();
+ if (shape_editor && shape_editor->lpeknotholder) {
+ SPItem *item = shape_editor->knotholder->item;
+ shape_editor->unset_item(true);
+ shape_editor->set_item(item);
+ }
+ }
+ }
+ }
+}
+void NodeSatelliteArrayParam::setUseDistance(bool use_knot_distance)
+{
+ _use_distance = use_knot_distance;
+}
+
+void NodeSatelliteArrayParam::setCurrentZoom(double current_zoom)
+{
+ _current_zoom = current_zoom;
+}
+
+void NodeSatelliteArrayParam::setGlobalKnotHide(bool global_knot_hide)
+{
+ _global_knot_hide = global_knot_hide;
+}
+
+void NodeSatelliteArrayParam::setEffectType(EffectType et)
+{
+ _effectType = et;
+}
+
+void NodeSatelliteArrayParam::updateCanvasIndicators(bool mirror)
+{
+ if (!_last_pathvector_nodesatellites) {
+ return;
+ }
+
+ if (!_hp.empty()) {
+ _hp.clear();
+ }
+ Geom::PathVector pathv = _last_pathvector_nodesatellites->getPathVector();
+ if (pathv.empty()) {
+ return;
+ }
+ if (mirror == true) {
+ _hp.clear();
+ }
+ if (_effectType == FILLET_CHAMFER) {
+ for (size_t i = 0; i < _vector.size(); ++i) {
+ for (size_t j = 0; j < _vector[i].size(); ++j) {
+ if (_vector[i][j].hidden || // Ignore if hidden
+ (!_vector[i][j].has_mirror && mirror == true) || // Ignore if not have mirror and we are in mirror
+ // loop
+ _vector[i][j].amount == 0 || // no helper in 0 value
+ j >= count_path_nodes(pathv[i]) || // ignore last nodesatellite in open paths with fillet chamfer
+ // effect
+ (!pathv[i].closed() && j == 0) || // ignore first nodesatellites on open paths
+ count_path_nodes(pathv[i]) == 2) {
+ continue;
+ }
+ Geom::Curve *curve_in = pathv[i][j].duplicate();
+ double pos = 0;
+ bool overflow = false;
+ double size_out = _vector[i][j].arcDistance(*curve_in);
+ double length_out = curve_in->length();
+ gint previous_index =
+ j - 1; // Always are previous index because we skip first nodesatellite on open paths
+ if (j == 0 && pathv[i].closed()) {
+ previous_index = count_path_nodes(pathv[i]) - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ double length_in = pathv.curveAt(previous_index).length();
+ if (mirror) {
+ curve_in = const_cast<Geom::Curve *>(&pathv.curveAt(previous_index));
+ pos = _vector[i][j].time(size_out, true, *curve_in);
+ if (length_out < size_out) {
+ overflow = true;
+ }
+ } else {
+ pos = _vector[i][j].time(*curve_in);
+ if (length_in < size_out) {
+ overflow = true;
+ }
+ }
+ if (pos <= 0 || pos >= 1) {
+ continue;
+ }
+ }
+ }
+ }
+ if (mirror) {
+ updateCanvasIndicators(false);
+ }
+}
+void NodeSatelliteArrayParam::updateCanvasIndicators()
+{
+ updateCanvasIndicators(true);
+}
+
+void NodeSatelliteArrayParam::addCanvasIndicators(SPLPEItem const * /*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(_hp);
+}
+
+void NodeSatelliteArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ if (prefs->getBool("/options/transform/rectcorners", true)) {
+ for (auto & i : _vector) {
+ for (auto & j : i) {
+ if (!j.is_time && j.amount > 0) {
+ j.amount = j.amount * ((postmul.expansionX() + postmul.expansionY()) / 2);
+ }
+ }
+ }
+ param_set_and_write_new_value(_vector);
+ }
+}
+
+void NodeSatelliteArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item, bool mirror)
+{
+ if (!_last_pathvector_nodesatellites) {
+ return;
+ }
+ size_t index = 0;
+ for (size_t i = 0; i < _vector.size(); ++i) {
+ for (size_t j = 0; j < _vector[i].size(); ++j) {
+ if (!_vector[i][j].has_mirror && mirror) {
+ continue;
+ }
+ NodeSatelliteType type = _vector[i][j].nodesatellite_type;
+ if (mirror && i == 0 && j == 0) {
+ index += _last_pathvector_nodesatellites->getTotalNodeSatellites();
+ }
+ using namespace Geom;
+ //If is for filletChamfer effect...
+ if (_effectType == FILLET_CHAMFER) {
+ const gchar *tip;
+ if (type == CHAMFER) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == INVERSE_CHAMFER) {
+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == INVERSE_FILLET) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ }
+ FilletChamferKnotHolderEntity *e = new FilletChamferKnotHolderEntity(this, index);
+ e->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:Chamfer",
+ _(tip), _knot_color);
+ knotholder->add(e);
+ }
+ index++;
+ }
+ }
+ if (mirror) {
+ addKnotHolderEntities(knotholder, item, false);
+ }
+}
+
+void NodeSatelliteArrayParam::updateAmmount(double amount)
+{
+ Geom::PathVector const pathv = _last_pathvector_nodesatellites->getPathVector();
+ NodeSatellites nodesatellites = _last_pathvector_nodesatellites->getNodeSatellites();
+ for (size_t i = 0; i < nodesatellites.size(); ++i) {
+ for (size_t j = 0; j < nodesatellites[i].size(); ++j) {
+ Geom::Curve const &curve_in = pathv[i][j];
+ if (param_effect->isNodePointSelected(curve_in.initialPoint()) ){
+ _vector[i][j].amount = amount;
+ _vector[i][j].setSelected(true);
+ } else {
+ _vector[i][j].setSelected(false);
+ }
+ }
+ }
+}
+
+void NodeSatelliteArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
+{
+ _knoth = knotholder;
+ addKnotHolderEntities(knotholder, item, true);
+}
+
+FilletChamferKnotHolderEntity::FilletChamferKnotHolderEntity(NodeSatelliteArrayParam *p, size_t index)
+ : _pparam(p)
+ , _index(index)
+{}
+
+void FilletChamferKnotHolderEntity::knot_set(Geom::Point const &p,
+ Geom::Point const &/*origin*/,
+ guint state)
+{
+ if (!_pparam->_last_pathvector_nodesatellites) {
+ return;
+ }
+ size_t total_nodesatellites = _pparam->_last_pathvector_nodesatellites->getTotalNodeSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_nodesatellites) {
+ index = _index - total_nodesatellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_nodesatellites->getIndexData(index);
+ size_t satelite_index = index_data.first;
+ size_t subsatelite_index = index_data.second;
+
+ Geom::Point s = snap_knot_position(p, state);
+ if (!valid_index(satelite_index, subsatelite_index)) {
+ return;
+ }
+ NodeSatellite nodesatellite = _pparam->_vector[satelite_index][subsatelite_index];
+ Geom::PathVector pathv = _pparam->_last_pathvector_nodesatellites->getPathVector();
+ if (nodesatellite.hidden ||
+ (!pathv[satelite_index].closed() &&
+ (subsatelite_index == 0 || // ignore first nodesatellites on open paths
+ count_path_nodes(pathv[satelite_index]) - 1 == subsatelite_index))) // ignore last nodesatellite in open paths
+ // with fillet chamfer effect
+ {
+ return;
+ }
+ gint previous_index = subsatelite_index - 1;
+ if (subsatelite_index == 0 && pathv[satelite_index].closed()) {
+ previous_index = count_path_nodes(pathv[satelite_index]) - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ Geom::Curve const &curve_in = pathv[satelite_index][previous_index];
+ double mirror_time = Geom::nearest_time(s, curve_in);
+ Geom::Point mirror = curve_in.pointAt(mirror_time);
+ double normal_time = Geom::nearest_time(s, pathv[satelite_index][subsatelite_index]);
+ Geom::Point normal = pathv[satelite_index][subsatelite_index].pointAt(normal_time);
+ double distance_mirror = Geom::distance(mirror,s);
+ double distance_normal = Geom::distance(normal,s);
+ if (Geom::are_near(s, pathv[satelite_index][subsatelite_index].initialPoint(), 1.5 / _pparam->_current_zoom)) {
+ nodesatellite.amount = 0;
+ } else if (distance_mirror < distance_normal) {
+ double time_start = 0;
+ NodeSatellites nodesatellites = _pparam->_last_pathvector_nodesatellites->getNodeSatellites();
+ time_start = nodesatellites[satelite_index][previous_index].time(curve_in);
+ if (time_start > mirror_time) {
+ mirror_time = time_start;
+ }
+ double size = arcLengthAt(mirror_time, curve_in);
+ double amount = curve_in.length() - size;
+ if (nodesatellite.is_time) {
+ amount = timeAtArcLength(amount, pathv[satelite_index][subsatelite_index]);
+ }
+ nodesatellite.amount = amount;
+ } else {
+ nodesatellite.setPosition(s, pathv[satelite_index][subsatelite_index]);
+ }
+ Inkscape::LivePathEffect::LPEFilletChamfer *filletchamfer = dynamic_cast<Inkscape::LivePathEffect::LPEFilletChamfer *>(_pparam->param_effect);
+ filletchamfer->helperpath = true;
+ _pparam->updateAmmount(nodesatellite.amount);
+ _pparam->_vector[satelite_index][subsatelite_index] = nodesatellite;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+}
+
+void
+FilletChamferKnotHolderEntity::knot_ungrabbed(Geom::Point const &p, Geom::Point const &origin, guint state)
+{
+ Inkscape::LivePathEffect::LPEFilletChamfer *filletchamfer = dynamic_cast<Inkscape::LivePathEffect::LPEFilletChamfer *>(_pparam->param_effect);
+ if (filletchamfer) {
+ filletchamfer->refresh_widgets = true;
+ filletchamfer->helperpath = false;
+ filletchamfer->writeParamsToSVG();
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ }
+}
+
+Geom::Point FilletChamferKnotHolderEntity::knot_get() const
+{
+ if (!_pparam->_last_pathvector_nodesatellites || _pparam->_global_knot_hide) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ Geom::Point tmp_point;
+ size_t total_nodesatellites = _pparam->_last_pathvector_nodesatellites->getTotalNodeSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_nodesatellites) {
+ index = _index - total_nodesatellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_nodesatellites->getIndexData(index);
+ size_t satelite_index = index_data.first;
+ size_t subsatelite_index = index_data.second;
+ if (!valid_index(satelite_index, subsatelite_index)) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ NodeSatellite nodesatellite = _pparam->_vector[satelite_index][subsatelite_index];
+ Geom::PathVector pathv = _pparam->_last_pathvector_nodesatellites->getPathVector();
+ if (nodesatellite.hidden ||
+ (!pathv[satelite_index].closed() &&
+ (subsatelite_index == 0 || subsatelite_index == count_path_nodes(pathv[satelite_index]) -
+ 1))) // ignore first and last nodesatellites on open paths
+ {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ this->knot->show();
+ if (is_mirror) {
+ gint previous_index = subsatelite_index - 1;
+ if (subsatelite_index == 0 && pathv[satelite_index].closed()) {
+ previous_index = count_path_nodes(pathv[satelite_index]) - 1;
+ }
+ if ( previous_index < 0 ) {
+ return Geom::Point(Geom::infinity(), Geom::infinity());
+ }
+ Geom::Curve const &curve_in = pathv[satelite_index][previous_index];
+ double s = nodesatellite.arcDistance(pathv[satelite_index][subsatelite_index]);
+ double t = nodesatellite.time(s, true, curve_in);
+ if (t > 1) {
+ t = 1;
+ }
+ if (t < 0) {
+ t = 0;
+ }
+ double time_start = 0;
+ time_start = _pparam->_last_pathvector_nodesatellites->getNodeSatellites()[satelite_index][previous_index].time(
+ curve_in);
+ if (time_start > t) {
+ t = time_start;
+ }
+ tmp_point = (curve_in).pointAt(t);
+ } else {
+ tmp_point = nodesatellite.getPosition(pathv[satelite_index][subsatelite_index]);
+ }
+ Geom::Point const canvas_point = tmp_point;
+ return canvas_point;
+}
+
+void FilletChamferKnotHolderEntity::knot_click(guint state)
+{
+ if (!_pparam->_last_pathvector_nodesatellites) {
+ return;
+ }
+ size_t total_nodesatellites = _pparam->_last_pathvector_nodesatellites->getTotalNodeSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_nodesatellites) {
+ index = _index - total_nodesatellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_nodesatellites->getIndexData(index);
+ size_t satelite_index = index_data.first;
+ size_t subsatelite_index = index_data.second;
+ if (!valid_index(satelite_index, subsatelite_index)) {
+ return;
+ }
+ Geom::PathVector pathv = _pparam->_last_pathvector_nodesatellites->getPathVector();
+ if (!pathv[satelite_index].closed() &&
+ (subsatelite_index == 0 ||
+ count_path_nodes(pathv[satelite_index]) - 1 == subsatelite_index)) // ignore last nodesatellite in open paths
+ // with fillet chamfer effect
+ {
+ return;
+ }
+ if (state & GDK_CONTROL_MASK) {
+ if (state & GDK_MOD1_MASK) {
+ _pparam->_vector[satelite_index][subsatelite_index].amount = 0.0;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ } else {
+ using namespace Geom;
+ NodeSatelliteType type = _pparam->_vector[satelite_index][subsatelite_index].nodesatellite_type;
+ switch (type) {
+ case FILLET:
+ type = INVERSE_FILLET;
+ break;
+ case INVERSE_FILLET:
+ type = CHAMFER;
+ break;
+ case CHAMFER:
+ type = INVERSE_CHAMFER;
+ break;
+ default:
+ type = FILLET;
+ break;
+ }
+ _pparam->_vector[satelite_index][subsatelite_index].nodesatellite_type = type;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ const gchar *tip;
+ if (type == CHAMFER) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else if (type == INVERSE_CHAMFER) {
+ tip = _("<b>Inverse Chamfer</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else if (type == INVERSE_FILLET) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ } else {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toggles type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> resets");
+ }
+ this->knot->tip = g_strdup(tip);
+ this->knot->show();
+ }
+ } else if (state & GDK_SHIFT_MASK) {
+ double amount = _pparam->_vector[satelite_index][subsatelite_index].amount;
+ gint previous_index = subsatelite_index - 1;
+ if (subsatelite_index == 0 && pathv[satelite_index].closed()) {
+ previous_index = count_path_nodes(pathv[satelite_index]) - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ if (!_pparam->_use_distance && !_pparam->_vector[satelite_index][subsatelite_index].is_time) {
+ amount = _pparam->_vector[satelite_index][subsatelite_index].lenToRad(
+ amount, pathv[satelite_index][previous_index], pathv[satelite_index][subsatelite_index],
+ _pparam->_vector[satelite_index][previous_index]);
+ }
+ bool aprox = false;
+ Geom::D2<Geom::SBasis> d2_out = pathv[satelite_index][subsatelite_index].toSBasis();
+ Geom::D2<Geom::SBasis> d2_in = pathv[satelite_index][previous_index].toSBasis();
+ aprox = ((d2_in)[0].degreesOfFreedom() != 2 ||
+ d2_out[0].degreesOfFreedom() != 2) &&
+ !_pparam->_use_distance
+ ? true
+ : false;
+ Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
+ this->desktop, amount, this, _pparam->_use_distance, aprox,
+ _pparam->_vector[satelite_index][subsatelite_index]);
+ }
+}
+
+void FilletChamferKnotHolderEntity::knot_set_offset(NodeSatellite nodesatellite)
+{
+ if (!_pparam->_last_pathvector_nodesatellites) {
+ return;
+ }
+ size_t total_nodesatellites = _pparam->_last_pathvector_nodesatellites->getTotalNodeSatellites();
+ bool is_mirror = false;
+ size_t index = _index;
+ if (_index >= total_nodesatellites) {
+ index = _index - total_nodesatellites;
+ is_mirror = true;
+ }
+ std::pair<size_t, size_t> index_data = _pparam->_last_pathvector_nodesatellites->getIndexData(index);
+ size_t satelite_index = index_data.first;
+ size_t subsatelite_index = index_data.second;
+ if (!valid_index(satelite_index, subsatelite_index)) {
+ return;
+ }
+ Geom::PathVector pathv = _pparam->_last_pathvector_nodesatellites->getPathVector();
+ if (nodesatellite.hidden ||
+ (!pathv[satelite_index].closed() &&
+ (subsatelite_index == 0 ||
+ count_path_nodes(pathv[satelite_index]) - 1 == subsatelite_index))) // ignore last nodesatellite in open paths
+ // with fillet chamfer effect
+ {
+ return;
+ }
+ double amount = nodesatellite.amount;
+ double max_amount = amount;
+ if (!_pparam->_use_distance && !nodesatellite.is_time) {
+ gint previous_index = subsatelite_index - 1;
+ if (subsatelite_index == 0 && pathv[satelite_index].closed()) {
+ previous_index = count_path_nodes(pathv[satelite_index]) - 1;
+ }
+ if ( previous_index < 0 ) {
+ return;
+ }
+ amount = _pparam->_vector[satelite_index][subsatelite_index].radToLen(
+ amount, pathv[satelite_index][previous_index], pathv[satelite_index][subsatelite_index]);
+ if (max_amount > 0 && amount == 0) {
+ amount = _pparam->_vector[satelite_index][subsatelite_index].amount;
+ }
+ }
+ nodesatellite.amount = amount;
+ _pparam->_vector[satelite_index][subsatelite_index] = nodesatellite;
+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
+ SPLPEItem *splpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (splpeitem) {
+ sp_lpe_item_update_patheffect(splpeitem, false, false);
+ }
+}
+
+} /* namespace LivePathEffect */
+
+} /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :