summaryrefslogtreecommitdiffstats
path: root/src/live_effects/parameter
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-10-29 22:40:05 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-10-29 22:40:05 +0000
commite9943b70c7bf507b9639ecb0a421bcee7ce93e33 (patch)
tree2d2fe7ee7a566e1ef1a5dcde18296d9f21188f35 /src/live_effects/parameter
parenti18n. Fixing untranslated strings. (diff)
parentMerge with trunk r13640 (diff)
downloadinkscape-e9943b70c7bf507b9639ecb0a421bcee7ce93e33.tar.gz
inkscape-e9943b70c7bf507b9639ecb0a421bcee7ce93e33.zip
Merge experimental
(bzr r13641)
Diffstat (limited to 'src/live_effects/parameter')
-rw-r--r--src/live_effects/parameter/Makefile_insert10
-rw-r--r--src/live_effects/parameter/bool.h2
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp882
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h123
-rw-r--r--src/live_effects/parameter/originalpatharray.cpp487
-rw-r--r--src/live_effects/parameter/originalpatharray.h122
-rw-r--r--src/live_effects/parameter/parameter.cpp29
-rw-r--r--src/live_effects/parameter/path.cpp4
-rw-r--r--src/live_effects/parameter/pointreseteable.cpp210
-rw-r--r--src/live_effects/parameter/pointreseteable.h74
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp45
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.h25
-rw-r--r--src/live_effects/parameter/togglebutton.cpp172
-rw-r--r--src/live_effects/parameter/togglebutton.h77
-rw-r--r--src/live_effects/parameter/transformedpoint.cpp182
-rw-r--r--src/live_effects/parameter/transformedpoint.h82
16 files changed, 2507 insertions, 19 deletions
diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert
index efdda686a..f990f41c7 100644
--- a/src/live_effects/parameter/Makefile_insert
+++ b/src/live_effects/parameter/Makefile_insert
@@ -11,6 +11,8 @@ ink_common_sources += \
live_effects/parameter/random.h \
live_effects/parameter/point.cpp \
live_effects/parameter/point.h \
+ live_effects/parameter/pointreseteable.cpp \
+ live_effects/parameter/pointreseteable.h \
live_effects/parameter/enum.h \
live_effects/parameter/path-reference.cpp \
live_effects/parameter/path-reference.h \
@@ -18,10 +20,18 @@ ink_common_sources += \
live_effects/parameter/path.h \
live_effects/parameter/originalpath.cpp \
live_effects/parameter/originalpath.h \
+ live_effects/parameter/originalpatharray.cpp \
+ live_effects/parameter/originalpatharray.h \
live_effects/parameter/powerstrokepointarray.cpp \
live_effects/parameter/powerstrokepointarray.h \
+ live_effects/parameter/filletchamferpointarray.cpp \
+ live_effects/parameter/filletchamferpointarray.h \
live_effects/parameter/text.cpp \
live_effects/parameter/text.h \
+ live_effects/parameter/transformedpoint.cpp \
+ live_effects/parameter/transformedpoint.h \
+ live_effects/parameter/togglebutton.cpp \
+ live_effects/parameter/togglebutton.h \
live_effects/parameter/unit.cpp \
live_effects/parameter/unit.h \
live_effects/parameter/vector.cpp \
diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h
index fafb1beca..b45eeb0b3 100644
--- a/src/live_effects/parameter/bool.h
+++ b/src/live_effects/parameter/bool.h
@@ -4,7 +4,7 @@
/*
* Inkscape::LivePathEffectParameters
*
-* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
new file mode 100644
index 000000000..e2b1aba61
--- /dev/null
+++ b/src/live_effects/parameter/filletchamferpointarray.cpp
@@ -0,0 +1,882 @@
+/*
+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * Special thanks to Johan Engelen for the base of the effect -powerstroke-
+ * Also to ScislaC for point me to the idea
+ * Also su_v for his construvtive feedback and time
+ * and finaly to Liam P. White for his big help on coding, that save me a lot of
+ * hours
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <2geom/piecewise.h>
+#include <2geom/sbasis-to-bezier.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/svg-elliptical-arc.h>
+#include <2geom/line.h>
+#include <2geom/path-intersection.h>
+
+#include "ui/dialog/lpe-fillet-chamfer-properties.h"
+#include "live_effects/parameter/filletchamferpointarray.h"
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "knotholder.h"
+#include "sp-lpe-item.h"
+#include "selection.h"
+
+// needed for on-canvas editting:
+#include "desktop.h"
+#include "live_effects/lpeobject.h"
+#include "helper/geom-nodetype.h"
+#include "helper/geom-curves.h"
+#include "ui/tools/node-tool.h"
+
+// TODO due to internal breakage in glibmm headers,
+// this has to be included last.
+#include <glibmm/i18n.h>
+
+
+using namespace Geom;
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+FilletChamferPointArrayParam::FilletChamferPointArrayParam(
+ const Glib::ustring &label, const Glib::ustring &tip,
+ const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr,
+ Effect *effect)
+ : ArrayParam<Point>(label, tip, key, wr, effect, 0)
+{
+ knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ knot_mode = SP_KNOT_MODE_XOR;
+ knot_color = 0x00ff0000;
+}
+
+FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {}
+
+Gtk::Widget *FilletChamferPointArrayParam::param_newWidget()
+{
+ return NULL;
+ /*
+ Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg =
+ Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredTransformedPoint(
+ param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ param_effect->getRepr(),
+ param_effect->getSPDoc()
+ ) );
+ // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Affine transf = desktop->doc2dt();
+ pointwdg->setTransform(transf);
+ pointwdg->setValue( *this );
+ pointwdg->clearProgrammatically();
+ pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Change point parameter"));
+
+ Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() );
+ static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
+ static_cast<Gtk::HBox*>(hbox)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (hbox);
+ */
+}
+
+void
+FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul,
+ bool /*set*/)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ if (prefs->getBool("/options/transform/rectcorners", true) &&
+ _vector[1][X] <= 0) {
+ std::vector<Geom::Point> result;
+ for (std::vector<Point>::const_iterator point_it = _vector.begin();
+ point_it != _vector.end(); ++point_it) {
+ Coord A =
+ (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2);
+ result.push_back(Point(A, (*point_it)[Y]));
+ }
+ param_set_and_write_new_value(result);
+ }
+
+ // param_set_and_write_new_value( (*this) * postmul );
+}
+
+/** call this method to recalculate the controlpoints such that they stay at the
+ * same location relative to the new path. Useful after adding/deleting nodes to
+ * the path.*/
+void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
+ Piecewise<D2<SBasis> > const &pwd2_in)
+{
+ if (!last_pwd2.empty()) {
+ PathVector const pathv =
+ path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001);
+ PathVector last_pathv =
+ path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001);
+ std::vector<Point> result;
+ unsigned long counter = 0;
+ unsigned long counterPaths = 0;
+ unsigned long counterCurves = 0;
+ long offset = 0;
+ long offsetPaths = 0;
+ Geom::NodeType nodetype;
+ for (PathVector::const_iterator path_it = pathv.begin();
+ path_it != pathv.end(); ++path_it) {
+ if (path_it->empty()) {
+ counterPaths++;
+ counter++;
+ continue;
+ }
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed() && path_it->back_closed().isDegenerate()) {
+ const Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ counterCurves = 0;
+ while (curve_it1 != curve_endit) {
+ //if start a path get node type
+ if (counterCurves == 0) {
+ if (path_it->closed()) {
+ if (path_it->back_closed().isDegenerate()) {
+ nodetype = get_nodetype(path_it->back_open(), *curve_it1);
+ } else {
+ nodetype = get_nodetype(path_it->back_closed(), *curve_it1);
+ }
+ } else {
+ nodetype = NODE_NONE;
+ }
+ } else {
+ //check node type also whith straight lines because get_nodetype
+ //return non cusp node in a node inserted inside a straight line
+ //todo: if the path remove some nodes whith the result of a straight
+ //line but with handles, the node inserted into dont fire the knot
+ // because is not handle as cusp node by get_nodetype function
+ bool 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.size() > counterPaths &&
+ last_pathv[counterPaths].size() > counter - offset &&
+ !are_near(curve_it1->initialPoint(),
+ last_pathv[counterPaths][counter - offset].initialPoint(),
+ 0.1))) {
+ if ( curve_it2 == curve_endit) {
+ if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) {
+ offset = 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;
+ counter++;
+ if (curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
+ counterCurves++;
+ }
+ }
+ if (change) {
+ _vector = result;
+ write_to_SVG();
+ }
+ }
+}
+
+void FilletChamferPointArrayParam::set_pwd2(
+ Piecewise<D2<SBasis> > const &pwd2_in,
+ Piecewise<D2<SBasis> > const &pwd2_normal_in)
+{
+ last_pwd2 = pwd2_in;
+ last_pwd2_normal = pwd2_normal_in;
+}
+
+void FilletChamferPointArrayParam::set_helper_size(int hs)
+{
+ helper_size = hs;
+}
+
+void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance )
+{
+ use_distance = use_knot_distance;
+}
+
+void FilletChamferPointArrayParam::set_unit(const gchar *abbr)
+{
+ unit = abbr;
+}
+
+void FilletChamferPointArrayParam::updateCanvasIndicators()
+{
+ std::vector<Point> ts = data();
+ hp.clear();
+ unsigned int i = 0;
+ for (std::vector<Point>::const_iterator point_it = ts.begin();
+ point_it != ts.end(); ++point_it) {
+ double Xvalue = to_time(i, (*point_it)[X]) -i;
+ if (Xvalue == 0) {
+ i++;
+ continue;
+ }
+ Geom::Point ptA = last_pwd2[i].valueAt(Xvalue);
+ Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue));
+ Geom::Rotate rot(Geom::Rotate::from_degrees(-90));
+ derivA = derivA * rot;
+ Geom::Point C = ptA - derivA * helper_size;
+ Geom::Point D = ptA + derivA * helper_size;
+ Geom::Ray ray1(C, D);
+ char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ Geom::Affine aff = Geom::Affine();
+ aff *= Geom::Scale(helper_size);
+ aff *= Geom::Rotate(ray1.angle() - deg_to_rad(270));
+ pathv *= aff;
+ pathv += last_pwd2[i].valueAt(Xvalue);
+ hp.push_back(pathv[0]);
+ hp.push_back(pathv[1]);
+ i++;
+ }
+}
+
+void FilletChamferPointArrayParam::addCanvasIndicators(
+ SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(hp);
+}
+
+double FilletChamferPointArrayParam::rad_to_len(int index, double rad)
+{
+ double len = 0;
+ std::vector<Geom::Path> subpaths = path_from_piecewise(last_pwd2, 0.1);
+ std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
+ D2<SBasis> A = last_pwd2[last_index(index, subpaths)];
+ if(positions.second != 0){
+ A = last_pwd2[index-1];
+ }else{
+ if(!subpaths[positions.first].closed()){
+ return len;
+ }
+ }
+ D2<SBasis> B = last_pwd2[index];
+ Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad);
+ Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad);
+ Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0];
+ Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0];
+ Geom::Crossings cs = Geom::crossings(p0, p1);
+ if(cs.size() > 0){
+ Point cp =p0(cs[0].ta);
+ double p0pt = nearest_point(cp, B);
+ len = time_to_len(index,p0pt);
+ } else {
+ if(rad < 0){
+ len = rad_to_len(index, rad * -1);
+ }
+ }
+ return len;
+}
+
+double FilletChamferPointArrayParam::len_to_rad(int index, double len)
+{
+ double rad = 0;
+ double tmp_len = _vector[index][X];
+ _vector[index] = Geom::Point(len,_vector[index][Y]);
+ std::vector<Geom::Path> subpaths = path_from_piecewise(last_pwd2, 0.1);
+ std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
+ Piecewise<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[last_index(index, subpaths)], 1);
+ Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate();
+ Geom::Curve * B = subpaths[positions.first][positions.second].duplicate();
+ std::vector<double> times;
+ if(positions.second != 0){
+ A = subpaths[positions.first][positions.second-1].duplicate();
+ times = get_times(index-1, subpaths, false);
+ }else{
+ if(!subpaths[positions.first].closed()){
+ return rad;
+ }
+ times = get_times(last_index(index, subpaths), subpaths, true);
+ }
+ _vector[index] = Geom::Point(tmp_len,_vector[index][Y]);
+ Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]);
+ Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]);
+ Curve *knotCurve1 = A->portion(times[0], times[1]);
+ Curve *knotCurve2 = B->portion(times[2], 1);
+ Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
+ Ray ray1(startArcPoint, A->finalPoint());
+ if (cubic1) {
+ ray1.setPoints((*cubic1)[2], startArcPoint);
+ }
+ Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
+ Ray ray2(B->initialPoint(), endArcPoint);
+ if (cubic2) {
+ ray2.setPoints(endArcPoint, (*cubic2)[1]);
+ }
+ bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0;
+ double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint));
+ double angleBetween = angle_between(ray1, ray2, ccwToggle);
+ rad = distanceArc/sin(angleBetween/2.0);
+ return rad * -1;
+}
+
+std::vector<double> FilletChamferPointArrayParam::get_times(int index, std::vector<Geom::Path> subpaths, bool last)
+{
+ const double tolerance = 0.001;
+ const double gapHelper = 0.00001;
+ std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths);
+ Curve *curve_it1;
+ curve_it1 = subpaths[positions.first][positions.second].duplicate();
+ Coord it1_length = (*curve_it1).length(tolerance);
+ double time_it1, time_it2, time_it1_B, intpart;
+ time_it1 = modf(to_time(index, _vector[index][X]), &intpart);
+ if (_vector[index][Y] == 0) {
+ time_it1 = 0;
+ }
+ double resultLenght = 0;
+ time_it1_B = 1;
+ if (subpaths[positions.first].closed() && last) {
+ time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart);
+ resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]);
+ } else if (!subpaths[positions.first].closed() && last){
+ time_it2 = 0;
+ resultLenght = 0;
+ } else {
+ time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart);
+ resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]);
+ }
+ if (resultLenght > 0 && time_it2 != 0) {
+ time_it1_B = modf(to_time(index, -resultLenght), &intpart);
+ } else {
+ if (time_it2 == 0) {
+ time_it1_B = 1;
+ } else {
+ time_it1_B = gapHelper;
+ }
+ }
+
+ if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) {
+ time_it1_B = 1;
+ time_it2 = 0;
+ }
+ if (time_it1_B < time_it1) {
+ time_it1_B = time_it1 + gapHelper;
+ }
+ std::vector<double> out;
+ out.push_back(time_it1);
+ out.push_back(time_it1_B);
+ out.push_back(time_it2);
+ return out;
+}
+
+std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, std::vector<Geom::Path> subpaths)
+{
+ int counter = -1;
+ std::size_t first = 0;
+ std::size_t second = 0;
+ for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
+ if (path_it->empty())
+ continue;
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed()) {
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
+ }
+ first++;
+ second = 0;
+ while (curve_it1 != curve_endit) {
+ counter++;
+ second++;
+ if(counter == index){
+ break;
+ }
+ ++curve_it1;
+ }
+ if(counter == index){
+ break;
+ }
+ }
+ first--;
+ second--;
+ std::pair<std::size_t, std::size_t> out(first, second);
+ return out;
+}
+
+int FilletChamferPointArrayParam::last_index(int index, std::vector<Geom::Path> subpaths)
+{
+ int counter = -1;
+ bool inSubpath = false;
+ for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) {
+ if (path_it->empty())
+ continue;
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
+ if (path_it->closed()) {
+ const Geom::Curve &closingline = path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
+ }
+ while (curve_it1 != curve_endit) {
+ counter++;
+ if(counter == index){
+ inSubpath = true;
+ }
+ ++curve_it1;
+ }
+ if(inSubpath){
+ break;
+ }
+ }
+ if(!inSubpath){
+ counter = -1;
+ }
+ return counter;
+}
+
+
+double FilletChamferPointArrayParam::len_to_time(int index, double len)
+{
+ double t = 0;
+ if (last_pwd2.size() > (unsigned) index) {
+ if (len != 0) {
+ if (last_pwd2[index][0].degreesOfFreedom() != 2) {
+ Piecewise<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[index], 1);
+ std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len));
+ if (t_roots.size() > 0) {
+ t = t_roots[0];
+ }
+ } else {
+ double lenghtPart = 0;
+ if (last_pwd2.size() > (unsigned) index) {
+ lenghtPart = length(last_pwd2[index], EPSILON);
+ }
+ if (std::abs(len) < lenghtPart && lenghtPart != 0) {
+ t = std::abs(len) / lenghtPart;
+ }
+ }
+ }
+ t = double(index) + t;
+ } else {
+ t = double(last_pwd2.size() - 1);
+ }
+
+ return t;
+}
+
+double FilletChamferPointArrayParam::time_to_len(int index, double time)
+{
+ double intpart;
+ double len = 0;
+ time = modf(time, &intpart);
+ double lenghtPart = 0;
+ if (last_pwd2.size() <= (unsigned) index || time == 0) {
+ return len;
+ }
+ if (last_pwd2[index][0].degreesOfFreedom() != 2) {
+ Piecewise<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[index], 1);
+ u = portion(u, 0, time);
+ return length(u, 0.001) * -1;
+ }
+ lenghtPart = length(last_pwd2[index], EPSILON);
+ return (time * lenghtPart) * -1;
+}
+
+double FilletChamferPointArrayParam::to_time(int index, double A)
+{
+ if (A > 0) {
+ return A;
+ } else {
+ return len_to_time(index, A);
+ }
+}
+
+double FilletChamferPointArrayParam::to_len(int index, double A)
+{
+ if (A > 0) {
+ return time_to_len(index, A);
+ } else {
+ return A;
+ }
+}
+
+void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape,
+ SPKnotModeType mode,
+ guint32 color)
+{
+ knot_shape = shape;
+ knot_mode = mode;
+ knot_color = color;
+}
+/*
+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) {
+ if (state & GDK_MOD1_MASK) {
+ _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]);
+ _pparam->param_set_and_write_new_value(_pparam->_vector);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ }else{
+ using namespace Geom;
+ 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, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (type == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ }
+ this->knot->tip = g_strdup(tip);
+ this->knot->show();
+ }
+ } else if (state & GDK_SHIFT_MASK) {
+ double xModified = _pparam->_vector.at(_index).x();
+ if(xModified < 0 && !_pparam->use_distance){
+ xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x());
+ }
+ std::vector<Geom::Path> subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1);
+ std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths);
+ D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)];
+ if(positions.second != 0){
+ A = _pparam->last_pwd2[_index-1];
+ }
+ D2<SBasis> B = _pparam->last_pwd2[_index];
+ bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false;
+ Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y());
+ Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog(
+ this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox);
+ }
+
+}
+
+void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
+ Geom::Point offset)
+{
+ double xModified = offset.x();
+ if(xModified < 0 && !_pparam->use_distance){
+ xModified = _pparam->rad_to_len(_index, offset.x());
+ }
+ _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y());
+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
+}
+
+void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
+ SPDesktop *desktop,
+ SPItem *item)
+{
+ recalculate_knots(get_pwd2());
+ for (unsigned int i = 0; i < _vector.size(); ++i) {
+ if (_vector[i][Y] <= 0) {
+ continue;
+ }
+ const gchar *tip;
+ if (_vector[i][Y] == 3) {
+ tip = _("<b>Chamfer</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (_vector[i][Y] == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else if (_vector[i][Y] == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+Click</b> toogle type, "
+ "<b>Shift+Click</b> open dialog, "
+ "<b>Ctrl+Alt+Click</b> reset");
+ }
+ FilletChamferPointArrayParamKnotHolderEntity *e =
+ new FilletChamferPointArrayParamKnotHolderEntity(this, i);
+ e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
+ knot_shape, knot_mode, knot_color);
+ knotholder->add(e);
+ }
+ updateCanvasIndicators();
+}
+
+} /* namespace LivePathEffect */
+
+} /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h
new file mode 100644
index 000000000..a1fa698ae
--- /dev/null
+++ b/src/live_effects/parameter/filletchamferpointarray.h
@@ -0,0 +1,123 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
+#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * Special thanks to Johan Engelen for the base of the effect -powerstroke-
+ * Also to ScislaC for point me to the idea
+ * Also su_v for his construvtive feedback and time
+ * and finaly to Liam P. White for his big help on coding, that save me a lot of
+ * hours
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <2geom/point.h>
+
+#include "live_effects/parameter/array.h"
+
+#include "knot-holder-entity.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class FilletChamferPointArrayParamKnotHolderEntity;
+
+class FilletChamferPointArrayParam : public ArrayParam<Geom::Point> {
+public:
+ FilletChamferPointArrayParam(const Glib::ustring &label,
+ const Glib::ustring &tip,
+ const Glib::ustring &key,
+ Inkscape::UI::Widget::Registry *wr,
+ Effect *effect);
+ virtual ~FilletChamferPointArrayParam();
+
+ virtual Gtk::Widget *param_newWidget();
+
+ virtual void param_transform_multiply(Geom::Affine const &postmul,
+ bool /*set*/);
+
+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode,
+ guint32 color);
+ virtual double to_time(int index, double A);
+ virtual double to_len(int index, double A);
+ virtual double rad_to_len(int index, double rad);
+ virtual double len_to_rad(int index, double len);
+ virtual double len_to_time(int index, double len);
+ virtual double time_to_len(int index, double time);
+ virtual std::pair<std::size_t, std::size_t> get_positions(int index, std::vector<Geom::Path> subpaths);
+ virtual int last_index(int index, std::vector<Geom::Path> subpaths);
+ std::vector<double> get_times(int index, std::vector<Geom::Path> subpaths, bool last);
+ virtual void set_helper_size(int hs);
+ virtual void set_use_distance(bool use_knot_distance);
+ 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;
+ bool use_distance;
+ 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_set_offset(Geom::Point offset);
+
+ /*Checks whether the index falls within the size of the parameter's vector*/
+ bool valid_index(unsigned int index) const {
+ return (_pparam->_vector.size() > index);
+ }
+ ;
+
+private:
+ FilletChamferPointArrayParam *_pparam;
+ unsigned int _index;
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp
new file mode 100644
index 000000000..7706dbdf8
--- /dev/null
+++ b/src/live_effects/parameter/originalpatharray.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * 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 "live_effects/parameter/originalpatharray.h"
+
+#include <gtkmm/widget.h>
+#include <gtkmm/icontheme.h>
+#include <gtkmm/imagemenuitem.h>
+#include <gtkmm/separatormenuitem.h>
+#include <gtkmm/scrolledwindow.h>
+
+#include <glibmm/i18n.h>
+
+#include "inkscape.h"
+#include "icon-size.h"
+#include "widgets/icon.h"
+#include "ui/clipboard.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "originalpath.h"
+#include "uri.h"
+#include "display/curve.h"
+
+#include <2geom/coord.h>
+#include <2geom/point.h>
+#include "sp-shape.h"
+#include "sp-text.h"
+#include "live_effects/effect.h"
+
+#include "verbs.h"
+#include "document-undo.h"
+#include "document.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class OriginalPathArrayParam::ModelColumns : public Gtk::TreeModel::ColumnRecord
+{
+public:
+
+ ModelColumns()
+ {
+ add(_colObject);
+ add(_colLabel);
+ add(_colReverse);
+ }
+ virtual ~ModelColumns() {}
+
+ Gtk::TreeModelColumn<PathAndDirection*> _colObject;
+ Gtk::TreeModelColumn<Glib::ustring> _colLabel;
+ Gtk::TreeModelColumn<bool> _colReverse;
+};
+
+OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect )
+: Parameter(label, tip, key, wr, effect),
+ _vector(),
+ _tree(),
+ _text_renderer(),
+ _toggle_renderer(),
+ _scroller()
+{
+ _model = new ModelColumns();
+ _store = Gtk::TreeStore::create(*_model);
+ _tree.set_model(_store);
+
+ _tree.set_reorderable(true);
+ _tree.enable_model_drag_dest (Gdk::ACTION_MOVE);
+
+ _text_renderer = manage(new Gtk::CellRendererText());
+ int nameColNum = _tree.append_column(_("Name"), *_text_renderer) - 1;
+ _name_column = _tree.get_column(nameColNum);
+ _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel);
+
+ _tree.set_expander_column( *_tree.get_column(nameColNum) );
+ _tree.set_search_column(_model->_colLabel);
+
+ Gtk::CellRendererToggle * _toggle_renderer = manage(new Gtk::CellRendererToggle());
+ int toggleColNum = _tree.append_column(_("Reverse"), *_toggle_renderer) - 1;
+ Gtk::TreeViewColumn* col = _tree.get_column(toggleColNum);
+ _toggle_renderer->set_activatable(true);
+ _toggle_renderer->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled));
+ col->add_attribute(_toggle_renderer->property_active(), _model->_colReverse);
+
+ //quick little hack -- newer versions of gtk gave the item zero space allotment
+ _scroller.set_size_request(-1, 120);
+
+ _scroller.add(_tree);
+ _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
+ //_scroller.set_shadow_type(Gtk::SHADOW_IN);
+
+ oncanvas_editable = true;
+
+}
+
+OriginalPathArrayParam::~OriginalPathArrayParam()
+{
+ while (!_vector.empty()) {
+ PathAndDirection *w = _vector.back();
+ _vector.pop_back();
+ unlink(w);
+ delete w;
+ }
+ delete _model;
+}
+
+void OriginalPathArrayParam::on_reverse_toggled(const Glib::ustring& path)
+{
+ Gtk::TreeModel::iterator iter = _store->get_iter(path);
+ Gtk::TreeModel::Row row = *iter;
+ PathAndDirection *w = row[_model->_colObject];
+ row[_model->_colReverse] = !row[_model->_colReverse];
+ w->reversed = row[_model->_colReverse];
+
+ gchar * full = param_getSVGValue();
+ param_write_to_repr(full);
+ g_free(full);
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Link path parameter to path"));
+}
+
+void OriginalPathArrayParam::param_set_default()
+{
+
+}
+
+Gtk::Widget* OriginalPathArrayParam::param_newWidget()
+{
+ Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox());
+ Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
+
+ vbox->pack_start(_scroller, Gtk::PACK_EXPAND_WIDGET);
+
+
+ { // Paste path to link button
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_link_button_click));
+ hbox->pack_start(*pButton, Gtk::PACK_SHRINK);
+ pButton->set_tooltip_text(_("Link to path"));
+ }
+
+ { // Remove linked path
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_REMOVE, Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_remove_button_click));
+ hbox->pack_start(*pButton, Gtk::PACK_SHRINK);
+ pButton->set_tooltip_text(_("Remove Path"));
+ }
+
+ { // Move Down
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_DOWN, Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_down_button_click));
+ hbox->pack_end(*pButton, Gtk::PACK_SHRINK);
+ pButton->set_tooltip_text(_("Move Down"));
+ }
+
+ { // Move Down
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_UP, Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
+ pButton->set_relief(Gtk::RELIEF_NONE);
+ pIcon->show();
+ pButton->add(*pIcon);
+ pButton->show();
+ pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_up_button_click));
+ hbox->pack_end(*pButton, Gtk::PACK_SHRINK);
+ pButton->set_tooltip_text(_("Move Up"));
+ }
+
+ vbox->pack_end(*hbox, Gtk::PACK_SHRINK);
+
+ vbox->show_all_children(true);
+
+ return vbox;
+}
+
+bool OriginalPathArrayParam::_selectIndex(const Gtk::TreeIter& iter, int* i)
+{
+ if ((*i)-- <= 0) {
+ _tree.get_selection()->select(iter);
+ return true;
+ }
+ return false;
+}
+
+void OriginalPathArrayParam::on_up_button_click()
+{
+ Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+
+ int i = -1;
+ std::vector<PathAndDirection*>::iterator piter = _vector.begin();
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, iter++) {
+ if (*iter == row[_model->_colObject]) {
+ _vector.erase(iter);
+ _vector.insert(piter, row[_model->_colObject]);
+ break;
+ }
+ }
+
+ gchar * full = param_getSVGValue();
+ param_write_to_repr(full);
+ g_free(full);
+
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Move path up"));
+
+ _store->foreach_iter(sigc::bind<int*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i));
+ }
+}
+
+void OriginalPathArrayParam::on_down_button_click()
+{
+ Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+
+ int i = 0;
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, iter++) {
+ if (*iter == row[_model->_colObject]) {
+ std::vector<PathAndDirection*>::iterator niter = _vector.erase(iter);
+ if (niter != _vector.end()) {
+ niter++;
+ i++;
+ }
+ _vector.insert(niter, row[_model->_colObject]);
+ break;
+ }
+ }
+
+ gchar * full = param_getSVGValue();
+ param_write_to_repr(full);
+ g_free(full);
+
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Move path down"));
+
+ _store->foreach_iter(sigc::bind<int*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i));
+ }
+}
+
+void OriginalPathArrayParam::on_remove_button_click()
+{
+ Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
+ if (iter) {
+ Gtk::TreeModel::Row row = *iter;
+ remove_link(row[_model->_colObject]);
+
+ gchar * full = param_getSVGValue();
+ param_write_to_repr(full);
+ g_free(full);
+
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Remove path"));
+ }
+
+}
+
+void
+OriginalPathArrayParam::on_link_button_click()
+{
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ Glib::ustring pathid = cm->getShapeOrTextObjectId(SP_ACTIVE_DESKTOP);
+
+ if (pathid == "") {
+ return;
+ }
+ // add '#' at start to make it an uri.
+ pathid.insert(pathid.begin(), '#');
+
+ Inkscape::SVGOStringStream os;
+ bool foundOne = false;
+ for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ if (foundOne) {
+ os << "|";
+ } else {
+ foundOne = true;
+ }
+ os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0");
+ }
+
+ if (foundOne) {
+ os << "|";
+ }
+
+ os << pathid.c_str() << ",0";
+
+ param_write_to_repr(os.str().c_str());
+ DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
+ _("Link path parameter to path"));
+}
+
+void OriginalPathArrayParam::unlink(PathAndDirection* to)
+{
+ to->linked_modified_connection.disconnect();
+ to->linked_delete_connection.disconnect();
+ to->ref.detach();
+ to->_pathvector = Geom::PathVector();
+ if (to->href) {
+ g_free(to->href);
+ to->href = NULL;
+ }
+}
+
+void OriginalPathArrayParam::remove_link(PathAndDirection* to)
+{
+ unlink(to);
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ if (*iter == to) {
+ PathAndDirection *w = *iter;
+ _vector.erase(iter);
+ delete w;
+ return;
+ }
+ }
+}
+
+void OriginalPathArrayParam::linked_delete(SPObject */*deleted*/, PathAndDirection* /*to*/)
+{
+ //remove_link(to);
+
+ gchar * full = param_getSVGValue();
+ param_write_to_repr(full);
+ g_free(full);
+}
+
+bool OriginalPathArrayParam::_updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd)
+{
+ Gtk::TreeModel::Row row = *iter;
+ if (row[_model->_colObject] == pd) {
+ SPObject *obj = pd->ref.getObject();
+ row[_model->_colLabel] = obj && obj->getId() ? ( obj->label() ? obj->label() : obj->getId() ) : pd->href;
+ return true;
+ }
+ return false;
+}
+
+void OriginalPathArrayParam::linked_changed(SPObject */*old_obj*/, SPObject *new_obj, PathAndDirection* to)
+{
+ to->linked_delete_connection.disconnect();
+ to->linked_modified_connection.disconnect();
+ to->linked_transformed_connection.disconnect();
+
+ if (new_obj && SP_IS_ITEM(new_obj)) {
+ to->linked_delete_connection = new_obj->connectDelete(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_delete), to));
+ to->linked_modified_connection = new_obj->connectModified(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_modified), to));
+ to->linked_transformed_connection = SP_ITEM(new_obj)->connectTransformed(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_transformed), to));
+
+ linked_modified(new_obj, SP_OBJECT_MODIFIED_FLAG, to);
+ } else {
+ to->_pathvector = Geom::PathVector();
+ SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ _store->foreach_iter(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to));
+ }
+}
+
+void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint /*flags*/, PathAndDirection* to)
+{
+ if (!to) {
+ return;
+ }
+ SPCurve *curve = NULL;
+ if (SP_IS_SHAPE(linked_obj)) {
+ curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE();
+ }
+ if (SP_IS_TEXT(linked_obj)) {
+ curve = SP_TEXT(linked_obj)->getNormalizedBpath();
+ }
+
+ if (curve == NULL) {
+ // curve invalid, set empty pathvector
+ to->_pathvector = Geom::PathVector();
+ } else {
+ to->_pathvector = curve->get_pathvector();
+ curve->unref();
+ }
+}
+
+void OriginalPathArrayParam::linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to)
+{
+ if (!to) {
+ return;
+ }
+ setPathVector(linked_obj, flags, to);
+ SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ _store->foreach_iter(sigc::bind<PathAndDirection*>(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to));
+}
+
+bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue)
+{
+ if (strvalue) {
+ while (!_vector.empty()) {
+ PathAndDirection *w = _vector.back();
+ unlink(w);
+ _vector.pop_back();
+ delete w;
+ }
+ _store->clear();
+
+ gchar ** strarray = g_strsplit(strvalue, "|", 0);
+ for (gchar ** iter = strarray; *iter != NULL; iter++) {
+ if ((*iter)[0] == '#') {
+ gchar ** substrarray = g_strsplit(*iter, ",", 0);
+ PathAndDirection* w = new PathAndDirection((SPObject *)param_effect->getLPEObj());
+ w->href = g_strdup(*substrarray);
+ w->reversed = *(substrarray+1) != NULL && (*(substrarray+1))[0] == '1';
+
+ w->linked_changed_connection = w->ref.changedSignal().connect(sigc::bind<PathAndDirection *>(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_changed), w));
+ w->ref.attach(URI(w->href));
+
+ _vector.push_back(w);
+
+ Gtk::TreeModel::iterator iter = _store->append();
+ Gtk::TreeModel::Row row = *iter;
+ SPObject *obj = w->ref.getObject();
+
+ row[_model->_colObject] = w;
+ row[_model->_colLabel] = obj ? ( obj->label() ? obj->label() : obj->getId() ) : w->href;
+ row[_model->_colReverse] = w->reversed;
+ g_strfreev (substrarray);
+ }
+ }
+ g_strfreev (strarray);
+ return true;
+ }
+ return false;
+}
+
+gchar * OriginalPathArrayParam::param_getSVGValue() const
+{
+ Inkscape::SVGOStringStream os;
+ bool foundOne = false;
+ for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ if (foundOne) {
+ os << "|";
+ } else {
+ foundOne = true;
+ }
+ os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0");
+ }
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
+}
+
+} /* namespace LivePathEffect */
+
+} /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h
new file mode 100644
index 000000000..6c792613f
--- /dev/null
+++ b/src/live_effects/parameter/originalpatharray.h
@@ -0,0 +1,122 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <vector>
+
+#include <gtkmm/box.h>
+#include <gtkmm/treeview.h>
+#include <gtkmm/treestore.h>
+#include <gtkmm/scrolledwindow.h>
+
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/path-reference.h"
+
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "path-reference.h"
+#include "sp-object.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class PathAndDirection {
+public:
+ PathAndDirection(SPObject *owner)
+ : href(NULL),
+ ref(owner),
+ _pathvector(Geom::PathVector()),
+ reversed(false)
+ {
+
+ }
+ gchar *href;
+ URIReference ref;
+ std::vector<Geom::Path> _pathvector;
+ bool reversed;
+
+ sigc::connection linked_changed_connection;
+ sigc::connection linked_delete_connection;
+ sigc::connection linked_modified_connection;
+ sigc::connection linked_transformed_connection;
+};
+
+class OriginalPathArrayParam : public Parameter {
+public:
+ class ModelColumns;
+
+ OriginalPathArrayParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect);
+
+ virtual ~OriginalPathArrayParam();
+
+ virtual Gtk::Widget * param_newWidget();
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ virtual gchar * param_getSVGValue() const;
+ virtual void param_set_default();
+
+ /** Disable the canvas indicators of parent class by overriding this method */
+ virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {};
+ /** Disable the canvas indicators of parent class by overriding this method */
+ virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector<Geom::PathVector> & /*hp_vec*/) {};
+
+ std::vector<PathAndDirection*> _vector;
+
+protected:
+ bool _updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd);
+ bool _selectIndex(const Gtk::TreeIter& iter, int* i);
+ void unlink(PathAndDirection* to);
+ void remove_link(PathAndDirection* to);
+ void setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to);
+
+ void linked_changed(SPObject *old_obj, SPObject *new_obj, PathAndDirection* to);
+ void linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to);
+ void linked_transformed(Geom::Affine const *, SPItem *, PathAndDirection*) {}
+ void linked_delete(SPObject *deleted, PathAndDirection* to);
+
+ ModelColumns *_model;
+ Glib::RefPtr<Gtk::TreeStore> _store;
+ Gtk::TreeView _tree;
+ Gtk::CellRendererText *_text_renderer;
+ Gtk::CellRendererToggle *_toggle_renderer;
+ Gtk::TreeView::Column *_name_column;
+ Gtk::ScrolledWindow _scroller;
+
+ void on_link_button_click();
+ void on_remove_button_click();
+ void on_up_button_click();
+ void on_down_button_click();
+ void on_reverse_toggled(const Glib::ustring& path);
+
+private:
+ OriginalPathArrayParam(const OriginalPathArrayParam&);
+ OriginalPathArrayParam& operator=(const OriginalPathArrayParam&);
+};
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp
index ad2960cd9..7a2fd9769 100644
--- a/src/live_effects/parameter/parameter.cpp
+++ b/src/live_effects/parameter/parameter.cpp
@@ -42,6 +42,13 @@ Parameter::param_write_to_repr(const char * svgd)
param_effect->getRepr()->setAttribute(param_key.c_str(), svgd);
}
+// In gtk2, this wasn't an issue; we could toss around
+// G_MAXDOUBLE and not worry about size allocations. But
+// in gtk3, it is an issue: it allocates widget size for the maxmium
+// value you pass to it, leading to some insane lengths.
+// If you need this to be more, please be conservative about it.
+const double SCALARPARAM_G_MAXDOUBLE = 10000000000;
+
void Parameter::write_to_SVG(void)
{
gchar * str = param_getSVGValue();
@@ -57,8 +64,8 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip,
Effect* effect, gdouble default_value)
: Parameter(label, tip, key, wr, effect),
value(default_value),
- min(-G_MAXDOUBLE),
- max(G_MAXDOUBLE),
+ min(-SCALARPARAM_G_MAXDOUBLE),
+ max(SCALARPARAM_G_MAXDOUBLE),
integer(false),
defvalue(default_value),
digits(2),
@@ -114,8 +121,22 @@ ScalarParam::param_set_value(gdouble val)
void
ScalarParam::param_set_range(gdouble min, gdouble max)
{
- this->min = min;
- this->max = max;
+ // if you look at client code, you'll see that many effects
+ // has a tendency to set an upper range of Geom::infinity().
+ // Once again, in gtk2, this is not a problem. But in gtk3,
+ // widgets get allocated the amount of size they ask for,
+ // leading to excessively long widgets.
+
+ if (min >= -SCALARPARAM_G_MAXDOUBLE) {
+ this->min = min;
+ } else {
+ this->min = -SCALARPARAM_G_MAXDOUBLE;
+ }
+ if (max <= SCALARPARAM_G_MAXDOUBLE) {
+ this->max = max;
+ } else {
+ this->max = SCALARPARAM_G_MAXDOUBLE;
+ }
param_set_value(value); // reset value to see whether it is in ranges
}
diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp
index 89947034d..2a14d4208 100644
--- a/src/live_effects/parameter/path.cpp
+++ b/src/live_effects/parameter/path.cpp
@@ -28,8 +28,8 @@
#include "document-undo.h"
// needed for on-canvas editting:
-#include "tools-switch.h"
-#include "shape-editor.h"
+#include "ui/tools-switch.h"
+#include "ui/shape-editor.h"
#include "desktop-handles.h"
#include "selection.h"
// clipboard support
diff --git a/src/live_effects/parameter/pointreseteable.cpp b/src/live_effects/parameter/pointreseteable.cpp
new file mode 100644
index 000000000..c0f8858b8
--- /dev/null
+++ b/src/live_effects/parameter/pointreseteable.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "ui/widget/registered-widget.h"
+#include "live_effects/parameter/pointreseteable.h"
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "ui/widget/point.h"
+#include "widgets/icon.h"
+#include "inkscape.h"
+#include "verbs.h"
+#include "knotholder.h"
+#include <glibmm/i18n.h>
+#include "ui/tools-switch.h"
+#include "ui/tools/node-tool.h"
+
+// needed for on-canvas editting:
+#include "desktop.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+PointReseteableParam::PointReseteableParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, const gchar *htip, Geom::Point default_value)
+ : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value)
+{
+ knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ knot_mode = SP_KNOT_MODE_XOR;
+ knot_color = 0xffffff00;
+ handle_tip = g_strdup(htip);
+}
+
+PointReseteableParam::~PointReseteableParam()
+{
+ if (handle_tip)
+ g_free(handle_tip);
+}
+
+void
+PointReseteableParam::param_set_default()
+{
+ param_setValue(defvalue);
+}
+
+void
+PointReseteableParam::param_set_and_write_default()
+{
+ param_set_and_write_new_value(defvalue);
+}
+
+void
+PointReseteableParam::param_update_default(Geom::Point newpoint)
+{
+ this->defvalue = newpoint;
+}
+
+bool
+PointReseteableParam::param_readSVGValue(const gchar * strvalue)
+{
+ gchar ** strarray = g_strsplit(strvalue, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ param_setValue( Geom::Point(newx, newy) );
+ return true;
+ }
+ return false;
+}
+
+gchar *
+PointReseteableParam::param_getSVGValue() const
+{
+ Inkscape::SVGOStringStream os;
+ os << *dynamic_cast<Geom::Point const *>( this );
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
+}
+
+Gtk::Widget *
+PointReseteableParam::param_newWidget()
+{
+ 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;
+ Geom::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
+PointReseteableParam::param_setValue(Geom::Point newpoint)
+{
+ *dynamic_cast<Geom::Point *>( this ) = newpoint;
+ if(SP_ACTIVE_DESKTOP){
+ SPDesktop* desktop = SP_ACTIVE_DESKTOP;
+ if (tools_isactive( desktop, TOOLS_NODES)) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>( desktop->event_context);
+ nt->update_helperpath();
+ }
+ }
+}
+
+void
+PointReseteableParam::param_set_and_write_new_value (Geom::Point newpoint)
+{
+ Inkscape::SVGOStringStream os;
+ os << newpoint;
+ gchar * str = g_strdup(os.str().c_str());
+ param_write_to_repr(str);
+ g_free(str);
+}
+
+void
+PointReseteableParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/)
+{
+ param_set_and_write_new_value( (*this) * postmul );
+}
+
+
+void
+PointReseteableParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color)
+{
+ knot_shape = shape;
+ knot_mode = mode;
+ knot_color = color;
+}
+
+class PointReseteableParamKnotHolderEntity : public KnotHolderEntity {
+public:
+ PointReseteableParamKnotHolderEntity(PointReseteableParam *p) { this->pparam = p; }
+ virtual ~PointReseteableParamKnotHolderEntity() {}
+
+ 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);
+
+private:
+ PointReseteableParam *pparam;
+};
+
+void
+PointReseteableParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
+{
+ Geom::Point const s = snap_knot_position(p, state);
+ pparam->param_setValue(s);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+}
+
+Geom::Point
+PointReseteableParamKnotHolderEntity::knot_get() const
+{
+ return *pparam;
+}
+
+void
+PointReseteableParamKnotHolderEntity::knot_click(guint state)
+{
+ if (state & GDK_CONTROL_MASK) {
+ if (state & GDK_MOD1_MASK) {
+ this->pparam->param_set_default();
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ }
+ }
+}
+
+void
+PointReseteableParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+{
+ PointReseteableParamKnotHolderEntity *e = new PointReseteableParamKnotHolderEntity(this);
+ // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself???
+ e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color);
+ knotholder->add(e);
+}
+
+} /* 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/pointreseteable.h b/src/live_effects/parameter/pointreseteable.h
new file mode 100644
index 000000000..5ae1fdf02
--- /dev/null
+++ b/src/live_effects/parameter/pointreseteable.h
@@ -0,0 +1,74 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <2geom/point.h>
+
+#include "live_effects/parameter/parameter.h"
+
+#include "knot-holder-entity.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+class PointReseteableParamKnotHolderEntity;
+
+class PointReseteableParam : public Geom::Point, public Parameter {
+public:
+ PointReseteableParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const gchar *handle_tip = NULL,
+ Geom::Point default_value = Geom::Point(0,0) ); // tip for automatically associated on-canvas handle
+ virtual ~PointReseteableParam();
+
+ virtual Gtk::Widget * param_newWidget();
+
+ bool param_readSVGValue(const gchar * strvalue);
+ gchar * param_getSVGValue() const;
+ inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); }
+
+ void param_setValue(Geom::Point newpoint);
+ void param_set_default();
+ void param_set_and_write_default();
+ void param_update_default(Geom::Point newpoint);
+
+ void param_set_and_write_new_value(Geom::Point newpoint);
+
+ virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/);
+
+ void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
+
+ virtual bool providesKnotHolderEntities() const { return true; }
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+
+ friend class PointReseteableParamKnotHolderEntity;
+private:
+ PointReseteableParam(const PointReseteableParam&);
+ PointReseteableParam& operator=(const PointReseteableParam&);
+
+ Geom::Point defvalue;
+
+ SPKnotShapeType knot_shape;
+ SPKnotModeType knot_mode;
+ guint32 knot_color;
+ gchar *handle_tip;
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp
index 964ab13b0..e0c2f4c68 100644
--- a/src/live_effects/parameter/powerstrokepointarray.cpp
+++ b/src/live_effects/parameter/powerstrokepointarray.cpp
@@ -4,8 +4,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
+#include "ui/dialog/lpe-powerstroke-properties.h"
#include "live_effects/parameter/powerstrokepointarray.h"
#include "live_effects/effect.h"
@@ -17,6 +16,8 @@
#include "preferences.h" // for proportional stroke/path scaling behavior
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -41,7 +42,6 @@ PowerStrokePointArrayParam::param_newWidget()
return NULL;
}
-
void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/)
{
// Check if proportional stroke-width scaling is on
@@ -61,7 +61,6 @@ void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const &po
}
}
-
/** 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
PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
@@ -90,6 +89,23 @@ PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewi
}
}
+float PowerStrokePointArrayParam::median_width()
+{
+ size_t size = _vector.size();
+ if (size > 0)
+ {
+ if (size % 2 == 0)
+ {
+ return (_vector[size / 2 - 1].y() + _vector[size / 2].y()) / 2;
+ }
+ else
+ {
+ return _vector[size / 2].y();
+ }
+ }
+ return 1;
+}
+
void
PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in)
{
@@ -105,7 +121,7 @@ PowerStrokePointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotMode
knot_mode = mode;
knot_color = color;
}
-
+/*
class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity {
public:
PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index);
@@ -115,7 +131,7 @@ public:
virtual Geom::Point knot_get() const;
virtual void knot_click(guint state);
- /** Checks whether the index falls within the size of the parameter's vector */
+ // 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);
};
@@ -123,7 +139,7 @@ public:
private:
PowerStrokePointArrayParam *_pparam;
unsigned int _index;
-};
+};*/
PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index)
: _pparam(p),
@@ -172,6 +188,12 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const
return canvas_point;
}
+void PowerStrokePointArrayParamKnotHolderEntity::knot_set_offset(Geom::Point offset)
+{
+ _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y() / 2);
+ this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
+}
+
void
PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state)
{
@@ -214,10 +236,15 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state)
// add knot to knotholder
PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(_pparam, _index+1);
e->create( this->desktop, this->item, parent_holder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it."),
+ _("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it, <b>Shift+click</b> launches width dialog."),
_pparam->knot_shape, _pparam->knot_mode, _pparam->knot_color);
parent_holder->add(e);
}
+ }
+ 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() * 2);
+ Inkscape::UI::Dialogs::PowerstrokePropertiesDialog::showDialog(this->desktop, offset, this);
}
}
@@ -226,7 +253,7 @@ void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, S
for (unsigned int i = 0; i < _vector.size(); ++i) {
PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i);
e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it."),
+ _("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it, <b>Shift+click</b> launches width dialog."),
knot_shape, knot_mode, knot_color);
knotholder->add(e);
}
diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h
index e1fa440f2..70b22e27e 100644
--- a/src/live_effects/parameter/powerstrokepointarray.h
+++ b/src/live_effects/parameter/powerstrokepointarray.h
@@ -20,8 +20,6 @@ namespace Inkscape {
namespace LivePathEffect {
-class PowerStrokePointArrayParamKnotHolderEntity;
-
class PowerStrokePointArrayParam : public ArrayParam<Geom::Point> {
public:
PowerStrokePointArrayParam( const Glib::ustring& label,
@@ -33,10 +31,12 @@ public:
virtual Gtk::Widget * param_newWidget();
- virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/);
+ virtual void param_transform_multiply(Geom::Affine const& postmul, bool /*set*/);
void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
+ float median_width();
+
virtual bool providesKnotHolderEntities() const { return true; }
virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
@@ -60,6 +60,25 @@ private:
Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal;
};
+class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity {
+public:
+ PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index);
+ virtual ~PowerStrokePointArrayParamKnotHolderEntity() {}
+
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+ virtual Geom::Point knot_get() const;
+ virtual void knot_set_offset(Geom::Point offset);
+ virtual void knot_click(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:
+ PowerStrokePointArrayParam *_pparam;
+ unsigned int _index;
+};
} //namespace LivePathEffect
diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp
new file mode 100644
index 000000000..c5da8b858
--- /dev/null
+++ b/src/live_effects/parameter/togglebutton.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Jabiertxo Arraiza Cenoz 2014 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "ui/widget/registered-widget.h"
+#include <glibmm/i18n.h>
+
+#include "live_effects/parameter/togglebutton.h"
+#include "live_effects/effect.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+#include "widgets/icon.h"
+#include "inkscape.h"
+#include "verbs.h"
+#include "helper-fns.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, bool default_value, const Glib::ustring& inactive_label,
+ char const * icon_active, char const * icon_inactive,
+ Inkscape::IconSize icon_size)
+ : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value),
+ inactiveLabel(inactive_label), iconActive(icon_active), iconInactive(icon_inactive), iconSize(icon_size)
+{
+ checkwdg = NULL;
+}
+
+ToggleButtonParam::~ToggleButtonParam()
+{
+ if (_toggled_connection.connected()) {
+ _toggled_connection.disconnect();
+ }
+}
+
+void
+ToggleButtonParam::param_set_default()
+{
+ param_setValue(defvalue);
+}
+
+bool
+ToggleButtonParam::param_readSVGValue(const gchar * strvalue)
+{
+ param_setValue(helperfns_read_bool(strvalue, defvalue));
+ return true; // not correct: if value is unacceptable, should return false!
+}
+
+gchar *
+ToggleButtonParam::param_getSVGValue() const
+{
+ gchar * str = g_strdup(value ? "true" : "false");
+ return str;
+}
+
+Gtk::Widget *
+ToggleButtonParam::param_newWidget()
+{
+ if (_toggled_connection.connected()) {
+ _toggled_connection.disconnect();
+ }
+
+ checkwdg = Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredToggleButton( param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ false,
+ param_effect->getRepr(),
+ param_effect->getSPDoc()) );
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget * boxButton = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(boxButton), false);
+#else
+ GtkWidget * boxButton = gtk_hbox_new (false, 0);
+#endif
+ GtkWidget * labelButton = gtk_label_new ("");
+ if (!param_label.empty()) {
+ if(value || inactiveLabel.empty()){
+ gtk_label_set_text(GTK_LABEL(labelButton), param_label.c_str());
+ }else{
+ gtk_label_set_text(GTK_LABEL(labelButton), inactiveLabel.c_str());
+ }
+ }
+ gtk_widget_show(labelButton);
+ if ( iconActive ) {
+ if(!iconInactive){
+ iconInactive = iconActive;
+ }
+ gtk_widget_show(boxButton);
+ GtkWidget *iconButton = sp_icon_new(iconSize, iconActive);
+ if(!value){
+ iconButton = sp_icon_new(iconSize, iconInactive);
+ }
+ gtk_widget_show(iconButton);
+ gtk_box_pack_start (GTK_BOX(boxButton), iconButton, false, false, 1);
+ if (!param_label.empty()) {
+ gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ }
+ }else{
+ gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ }
+ checkwdg->add(*Gtk::manage(Glib::wrap(boxButton)));
+ checkwdg->setActive(value);
+ checkwdg->setProgrammatically = false;
+ checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter"));
+
+ _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled));
+
+ return checkwdg;
+}
+
+void
+ToggleButtonParam::refresh_button()
+{
+ if(!checkwdg){
+ return;
+ }
+ Gtk::Widget * boxButton = checkwdg->get_child();
+ if(!boxButton){
+ return;
+ }
+ GList * childs = gtk_container_get_children(GTK_CONTAINER(boxButton->gobj()));
+ guint totalWidgets = g_list_length (childs);
+ if (!param_label.empty()) {
+ if(value || inactiveLabel.empty()){
+ gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), param_label.c_str());
+ }else{
+ gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), inactiveLabel.c_str());
+ }
+ }
+ if ( iconActive ) {
+ GdkPixbuf * iconPixbuf = sp_pixbuf_new( iconSize, iconActive );
+ if(!value){
+ iconPixbuf = sp_pixbuf_new( iconSize, iconInactive);
+ }
+ gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), iconPixbuf);
+ }
+}
+
+void
+ToggleButtonParam::param_setValue(bool newvalue)
+{
+ value = newvalue;
+ refresh_button();
+}
+
+void
+ToggleButtonParam::toggled() {
+ _signal_toggled.emit();
+}
+
+} /* namespace LivePathEffect */
+
+} /* 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/togglebutton.h b/src/live_effects/parameter/togglebutton.h
new file mode 100644
index 000000000..4e545bcfd
--- /dev/null
+++ b/src/live_effects/parameter/togglebutton.h
@@ -0,0 +1,77 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H
+
+/*
+ * Copyright (C) Jabiertxo Arraiza Cenoz 2014
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <sigc++/connection.h>
+#include <sigc++/signal.h>
+
+#include "live_effects/parameter/parameter.h"
+#include "icon-size.h"
+#include "ui/widget/registered-widget.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+/**
+ * class ToggleButtonParam:
+ * represents a Gtk::ToggleButton as a Live Path Effect parameter
+ */
+class ToggleButtonParam : public Parameter {
+public:
+ ToggleButtonParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ bool default_value = false,
+ const Glib::ustring& inactive_label = "",
+ char const * icon_active = NULL,
+ char const * icon_inactive = NULL,
+ Inkscape::IconSize icon_size = Inkscape::ICON_SIZE_SMALL_TOOLBAR);
+ virtual ~ToggleButtonParam();
+
+ virtual Gtk::Widget * param_newWidget();
+
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ virtual gchar * param_getSVGValue() const;
+
+ void param_setValue(bool newvalue);
+ virtual void param_set_default();
+
+ bool get_value() const { return value; };
+
+ inline operator bool() const { return value; };
+
+ sigc::signal<void>& signal_toggled() { return _signal_toggled; }
+ virtual void toggled();
+
+private:
+ ToggleButtonParam(const ToggleButtonParam&);
+ ToggleButtonParam& operator=(const ToggleButtonParam&);
+
+ void refresh_button();
+ bool value;
+ bool defvalue;
+ const Glib::ustring inactiveLabel;
+ const char * iconActive;
+ const char * iconInactive;
+ Inkscape::IconSize iconSize;
+ Inkscape::UI::Widget::RegisteredToggleButton * checkwdg;
+
+ sigc::signal<void> _signal_toggled;
+ sigc::connection _toggled_connection;
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif
diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp
new file mode 100644
index 000000000..0d03432c3
--- /dev/null
+++ b/src/live_effects/parameter/transformedpoint.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "ui/widget/registered-widget.h"
+#include "live_effects/parameter/transformedpoint.h"
+#include "sp-lpe-item.h"
+#include "knotholder.h"
+#include "svg/svg.h"
+#include "svg/stringstream.h"
+
+#include "live_effects/effect.h"
+#include "desktop.h"
+#include "verbs.h"
+
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+TransformedPointParam::TransformedPointParam( const Glib::ustring& label, const Glib::ustring& tip,
+ const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
+ Effect* effect, Geom::Point default_vector,
+ bool dontTransform)
+ : Parameter(label, tip, key, wr, effect),
+ defvalue(default_vector),
+ origin(0.,0.),
+ vector(default_vector),
+ noTransform(dontTransform)
+{
+ vec_knot_shape = SP_KNOT_SHAPE_DIAMOND;
+ vec_knot_mode = SP_KNOT_MODE_XOR;
+ vec_knot_color = 0xffffb500;
+}
+
+TransformedPointParam::~TransformedPointParam()
+{
+
+}
+
+void
+TransformedPointParam::param_set_default()
+{
+ setOrigin(Geom::Point(0.,0.));
+ setVector(defvalue);
+}
+
+bool
+TransformedPointParam::param_readSVGValue(const gchar * strvalue)
+{
+ gchar ** strarray = g_strsplit(strvalue, ",", 4);
+ if (!strarray) {
+ return false;
+ }
+ double val[4];
+ unsigned int i = 0;
+ while (i < 4 && strarray[i]) {
+ if (sp_svg_number_read_d(strarray[i], &val[i]) != 0) {
+ i++;
+ } else {
+ break;
+ }
+ }
+ g_strfreev (strarray);
+ if (i == 4) {
+ setOrigin( Geom::Point(val[0], val[1]) );
+ setVector( Geom::Point(val[2], val[3]) );
+ return true;
+ }
+ return false;
+}
+
+gchar *
+TransformedPointParam::param_getSVGValue() const
+{
+ Inkscape::SVGOStringStream os;
+ os << origin << " , " << vector;
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
+}
+
+Gtk::Widget *
+TransformedPointParam::param_newWidget()
+{
+ Inkscape::UI::Widget::RegisteredVector * pointwdg = Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredVector( param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ param_effect->getRepr(),
+ param_effect->getSPDoc() ) );
+ pointwdg->setPolarCoords();
+ pointwdg->setValue( vector, origin );
+ pointwdg->clearProgrammatically();
+ pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change vector 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
+TransformedPointParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector)
+{
+ setValues(new_origin, new_vector);
+ gchar * str = param_getSVGValue();
+ param_write_to_repr(str);
+ g_free(str);
+}
+
+void
+TransformedPointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/)
+{
+ if (!noTransform) {
+ set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() );
+ }
+}
+
+
+void
+TransformedPointParam::set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color)
+{
+ vec_knot_shape = shape;
+ vec_knot_mode = mode;
+ vec_knot_color = color;
+}
+
+void
+TransformedPointParam::set_oncanvas_color(guint32 color)
+{
+ vec_knot_color = color;
+}
+
+class TransformedPointParamKnotHolderEntity_Vector : public KnotHolderEntity {
+public:
+ TransformedPointParamKnotHolderEntity_Vector(TransformedPointParam *p) : param(p) { }
+ virtual ~TransformedPointParamKnotHolderEntity_Vector() {}
+
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/) {
+ Geom::Point const s = p - param->origin;
+ /// @todo implement angle snapping when holding CTRL
+ param->setVector(s);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ };
+ virtual Geom::Point knot_get() const{
+ return param->origin + param->vector;
+ };
+ virtual void knot_click(guint /*state*/){
+ g_print ("This is the vector handle associated to parameter '%s'\n", param->param_key.c_str());
+ };
+
+private:
+ TransformedPointParam *param;
+};
+
+void
+TransformedPointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+{
+ TransformedPointParamKnotHolderEntity_Vector *vector_e = new TransformedPointParamKnotHolderEntity_Vector(this);
+ vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color);
+ knotholder->add(vector_e);
+}
+
+} /* 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/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h
new file mode 100644
index 000000000..c96bedb53
--- /dev/null
+++ b/src/live_effects/parameter/transformedpoint.h
@@ -0,0 +1,82 @@
+#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H
+#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H
+
+/*
+ * Inkscape::LivePathEffectParameters
+ *
+ * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+#include <2geom/point.h>
+
+#include "live_effects/parameter/parameter.h"
+
+#include "knot-holder-entity.h"
+
+namespace Inkscape {
+
+namespace LivePathEffect {
+
+
+class TransformedPointParam : public Parameter {
+public:
+ TransformedPointParam( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ Geom::Point default_vector = Geom::Point(1,0),
+ bool dontTransform = false);
+ virtual ~TransformedPointParam();
+
+ virtual Gtk::Widget * param_newWidget();
+ inline const gchar *handleTip() const { return param_tooltip.c_str(); }
+
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ virtual gchar * param_getSVGValue() const;
+
+ Geom::Point getVector() const { return vector; };
+ Geom::Point getOrigin() const { return origin; };
+ void setValues(Geom::Point const &new_origin, Geom::Point const &new_vector) { setVector(new_vector); setOrigin(new_origin); };
+ void setVector(Geom::Point const &new_vector) { vector = new_vector; };
+ void setOrigin(Geom::Point const &new_origin) { origin = new_origin; };
+ virtual void param_set_default();
+
+ void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector);
+
+ virtual void param_transform_multiply(Geom::Affine const &postmul, bool set);
+
+ void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
+ void set_oncanvas_color(guint32 color);
+
+ virtual bool providesKnotHolderEntities() const { return true; }
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+
+private:
+ TransformedPointParam(const TransformedPointParam&);
+ TransformedPointParam& operator=(const TransformedPointParam&);
+
+ Geom::Point defvalue;
+
+ Geom::Point origin;
+ Geom::Point vector;
+
+ bool noTransform;
+
+ /// The looks of the vector and origin knots oncanvas
+ SPKnotShapeType vec_knot_shape;
+ SPKnotModeType vec_knot_mode;
+ guint32 vec_knot_color;
+
+ friend class TransformedPointParamKnotHolderEntity_Vector;
+};
+
+
+} //namespace LivePathEffect
+
+} //namespace Inkscape
+
+#endif