summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2017-08-13 11:26:35 +0000
committerMartin Owens <doctormo@gmail.com>2017-08-13 11:26:35 +0000
commit203bb5ccb8d526f3460e476693642c05bd6fab2f (patch)
tree7b7e3142393909358d50019efc6fc5e1bc91fcca /src
parentMerge branch 'alvinpenner/inkscape-master' (diff)
parentupdate to trunk (diff)
downloadinkscape-203bb5ccb8d526f3460e476693642c05bd6fab2f.tar.gz
inkscape-203bb5ccb8d526f3460e476693642c05bd6fab2f.zip
Merge branch 'jabiertxof/inkscape-inkscape.dev_power_clip_and_mask'
Diffstat (limited to 'src')
-rw-r--r--src/live_effects/CMakeLists.txt4
-rw-r--r--src/live_effects/effect-enum.h2
-rw-r--r--src/live_effects/effect.cpp11
-rw-r--r--src/live_effects/lpe-powerclip.cpp407
-rw-r--r--src/live_effects/lpe-powerclip.h47
-rw-r--r--src/live_effects/lpe-powermask.cpp357
-rw-r--r--src/live_effects/lpe-powermask.h41
-rw-r--r--src/sp-clippath.cpp3
-rw-r--r--src/sp-clippath.h1
-rw-r--r--src/sp-item.cpp7
-rw-r--r--src/sp-mask.cpp3
-rw-r--r--src/sp-path.cpp3
-rw-r--r--src/ui/tools/node-tool.cpp5
13 files changed, 881 insertions, 10 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index 5b192f40e..2a137d6bb 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -36,6 +36,8 @@ set(live_effects_SRC
lpe-perp_bisector.cpp
lpe-perspective-envelope.cpp
lpe-perspective_path.cpp
+ lpe-powerclip.cpp
+ lpe-powermask.cpp
lpe-powerstroke.cpp
lpe-recursiveskeleton.cpp
lpe-rough-hatches.cpp
@@ -124,6 +126,8 @@ set(live_effects_SRC
lpe-perspective-envelope.h
lpe-perspective_path.h
lpe-powerstroke-interpolators.h
+ lpe-powerclip.h
+ lpe-powermask.h
lpe-powerstroke.h
lpe-recursiveskeleton.h
lpe-rough-hatches.h
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 5cc4d58e5..6a3aebcd6 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -51,6 +51,8 @@ enum EffectType {
FILLET_CHAMFER,
BOOL_OP,
EMBRODERY_STITCH,
+ POWERCLIP,
+ POWERMASK,
DOEFFECTSTACK_TEST,
ANGLE_BISECTOR,
CIRCLE_WITH_RADIUS,
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index e5a879241..c817f5caa 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -47,6 +47,8 @@
#include "live_effects/lpe-perp_bisector.h"
#include "live_effects/lpe-perspective-envelope.h"
#include "live_effects/lpe-perspective_path.h"
+#include "live_effects/lpe-powerclip.h"
+#include "live_effects/lpe-powermask.h"
#include "live_effects/lpe-powerstroke.h"
#include "live_effects/lpe-recursiveskeleton.h"
#include "live_effects/lpe-roughen.h"
@@ -128,6 +130,8 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"},
{BOOL_OP, N_("Boolean operation"), "bool_op"},
{EMBRODERY_STITCH, N_("Embrodery stitch"), "embrodery_stitch"},
+ {POWERCLIP, N_("Power clip"), "powerclip"},
+ {POWERMASK, N_("Power mask"), "powermask"},
#ifdef LPE_ENABLE_TEST_EFFECTS
{DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"},
{ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"},
@@ -312,6 +316,12 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case FILLET_CHAMFER:
neweffect = static_cast<Effect*> ( new LPEFilletChamfer(lpeobj) );
break;
+ case POWERCLIP:
+ neweffect = static_cast<Effect*> ( new LPEPowerClip(lpeobj) );
+ break;
+ case POWERMASK:
+ neweffect = static_cast<Effect*> ( new LPEPowerMask(lpeobj) );
+ break;
case ROUGHEN:
neweffect = static_cast<Effect*> ( new LPERoughen(lpeobj) );
break;
@@ -971,6 +981,7 @@ Effect::resetDefaults(SPItem const* /*item*/)
}
}
+//Activate handle your transform filling your effect on SPPath.cpp
void
Effect::transform_multiply(Geom::Affine const& postmul, bool set)
{
diff --git a/src/live_effects/lpe-powerclip.cpp b/src/live_effects/lpe-powerclip.cpp
new file mode 100644
index 000000000..2d0d4bb12
--- /dev/null
+++ b/src/live_effects/lpe-powerclip.cpp
@@ -0,0 +1,407 @@
+/*
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#include "live_effects/lpe-powerclip.h"
+#include <2geom/path-intersection.h>
+#include <2geom/intersection-graph.h>
+#include "display/drawing-item.h"
+#include "display/curve.h"
+#include "helper/geom.h"
+#include "sp-clippath.h"
+#include "sp-path.h"
+#include "sp-shape.h"
+#include "sp-item-group.h"
+#include "ui/tools-switch.h"
+#include "path-chemistry.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPEPowerClip::LPEPowerClip(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ inverse(_("Inverse clip"), _("Inverse clip"), "inverse", &wr, this, false),
+ flatten(_("Flatten clip"), _("Flatten clip, see fill rule once convert to paths"), "flatten", &wr, this, false),
+ //loock(_("Lock clip"), _("Lock clip"), "lock", &wr, this, false),
+ //tooltip empty to no show in default param set
+ is_inverse("Store the last inverse apply", "", "is_inverse", &wr, this, "false", false)
+{
+ registerParameter(&inverse);
+ registerParameter(&flatten);
+ registerParameter(&is_inverse);
+ //registerParameter(&lock);
+ //lock.param_setValue(false);
+ is_clip = false;
+ hide_clip = false;
+ convert_shapes = false;
+}
+
+LPEPowerClip::~LPEPowerClip() {}
+
+void
+LPEPowerClip::doBeforeEffect (SPLPEItem const* lpeitem){
+ original_bbox(lpeitem);
+ SPClipPath *clip_path = SP_ITEM(lpeitem)->clip_ref->getObject();
+ Geom::Point topleft = Geom::Point(boundingbox_X.min() - 5,boundingbox_Y.max() + 5);
+ Geom::Point topright = Geom::Point(boundingbox_X.max() + 5,boundingbox_Y.max() + 5);
+ Geom::Point bottomright = Geom::Point(boundingbox_X.max() + 5,boundingbox_Y.min() - 5);
+ Geom::Point bottomleft = Geom::Point(boundingbox_X.min() - 5,boundingbox_Y.min() - 5);
+ clip_box.clear();
+ clip_box.start(topleft);
+ clip_box.appendNew<Geom::LineSegment>(topright);
+ clip_box.appendNew<Geom::LineSegment>(bottomright);
+ clip_box.appendNew<Geom::LineSegment>(bottomleft);
+ clip_box.close();
+ //clip_path *= sp_lpe_item->i2dt_affine();
+ if (clip_path) {
+ is_clip = true;
+ const Glib::ustring uri = (Glib::ustring)sp_lpe_item->getRepr()->attribute("clip-path");
+ std::vector<SPObject*> clip_path_list = clip_path->childList(true);
+ for ( std::vector<SPObject*>::const_iterator iter=clip_path_list.begin();iter!=clip_path_list.end();++iter) {
+ SPObject * clip_data = *iter;
+ SPObject * clip_to_path = NULL;
+ if (SP_IS_SHAPE(clip_data) && !SP_IS_PATH(clip_data) && convert_shapes) {
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Inkscape::XML::Node *clip_path_node = sp_selected_item_to_curved_repr(SP_ITEM(clip_data), 0);
+ // remember the position of the item
+ gint pos = clip_data->getRepr()->position();
+ // remember parent
+ Inkscape::XML::Node *parent = clip_data->getRepr()->parent();
+ // remember id
+ char const *id = clip_data->getRepr()->attribute("id");
+ // remember title
+ gchar *title = clip_data->title();
+ // remember description
+ gchar *desc = clip_data->desc();
+
+ // It's going to resurrect, so we delete without notifying listeners.
+ clip_data->deleteObject(false);
+
+ // restore id
+ clip_path_node->setAttribute("id", id);
+ // add the new repr to the parent
+ parent->appendChild(clip_path_node);
+ clip_to_path = document->getObjectByRepr(clip_path_node);
+ if (title && clip_to_path) {
+ clip_to_path->setTitle(title);
+ g_free(title);
+ }
+ if (desc && clip_to_path) {
+ clip_to_path->setDesc(desc);
+ g_free(desc);
+ }
+ // move to the saved position
+ clip_path_node->setPosition(pos > 0 ? pos : 0);
+ Inkscape::GC::release(clip_path_node);
+ clip_to_path->emitModified(SP_OBJECT_MODIFIED_CASCADE);
+ }
+ if( is_inverse.param_getSVGValue() == (Glib::ustring)"false" && inverse && isVisible()) {
+ if (clip_to_path) {
+ addInverse(SP_ITEM(clip_to_path));
+ } else {
+ addInverse(SP_ITEM(clip_data));
+ }
+ } else if(is_inverse.param_getSVGValue() == (Glib::ustring)"true" && !inverse && isVisible()) {
+ if (clip_to_path) {
+ removeInverse(SP_ITEM(clip_to_path));
+ } else {
+ removeInverse(SP_ITEM(clip_data));
+ }
+ } else if (inverse && !is_visible && is_inverse.param_getSVGValue() == (Glib::ustring)"true"){
+ removeInverse(SP_ITEM(clip_data));
+ }
+ }
+ } else {
+ is_clip = false;
+ }
+}
+
+void
+LPEPowerClip::addInverse (SPItem * clip_data){
+ if(is_inverse.param_getSVGValue() == (Glib::ustring)"false") {
+ if (SP_IS_GROUP(clip_data)) {
+ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(clip_data));
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
+ SPItem *subitem = *iter;
+ addInverse(subitem);
+ }
+ } else if (SP_IS_PATH(clip_data)) {
+ SPCurve * c = NULL;
+ c = SP_SHAPE(clip_data)->getCurve();
+ if (c) {
+ Geom::PathVector c_pv = c->get_pathvector();
+ //TODO: this can be not correct but no better way
+ bool dir_a = Geom::path_direction(c_pv[0]);
+ bool dir_b = Geom::path_direction(clip_box);
+ if (dir_a == dir_b) {
+ clip_box = clip_box.reversed();
+ }
+ c_pv.push_back(clip_box);
+ c->set_pathvector(c_pv);
+ SP_SHAPE(clip_data)->setCurve(c, TRUE);
+ c->unref();
+ is_inverse.param_setValue((Glib::ustring)"true", true);
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ if (tools_isactive(desktop, TOOLS_NODES)) {
+ Inkscape::Selection * sel = SP_ACTIVE_DESKTOP->getSelection();
+ SPItem * item = sel->singleItem();
+ if (item != NULL) {
+ sel->remove(item);
+ sel->add(item);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+LPEPowerClip::removeInverse (SPItem * clip_data){
+ if(is_inverse.param_getSVGValue() == (Glib::ustring)"true") {
+ if (SP_IS_GROUP(clip_data)) {
+ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(clip_data));
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
+ SPItem *subitem = *iter;
+ removeInverse(subitem);
+ }
+ } else if (SP_IS_PATH(clip_data)) {
+ SPCurve * c = NULL;
+ c = SP_SHAPE(clip_data)->getCurve();
+ if (c) {
+ Geom::PathVector c_pv = c->get_pathvector();
+ if(c_pv.size() > 1) {
+ c_pv.pop_back();
+ }
+ c->set_pathvector(c_pv);
+ SP_SHAPE(clip_data)->setCurve(c, TRUE);
+ c->unref();
+ is_inverse.param_setValue((Glib::ustring)"false", true);
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop) {
+ if (tools_isactive(desktop, TOOLS_NODES)) {
+ Inkscape::Selection * sel = SP_ACTIVE_DESKTOP->getSelection();
+ SPItem * item = sel->singleItem();
+ if (item != NULL) {
+ sel->remove(item);
+ sel->add(item);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+LPEPowerClip::toggleClip() {
+ SPItem * item = SP_ITEM(sp_lpe_item);
+ if (item) {
+ SPClipPath *clip_path = item->clip_ref->getObject();
+ if (clip_path) {
+ hide_clip = !hide_clip;
+ if(hide_clip) {
+ SPItemView *v;
+ for (v = item->display; v != NULL; v = v->next) {
+ clip_path->hide(v->arenaitem->key());
+ }
+ } else {
+ Geom::OptRect bbox = item->geometricBounds();
+ for (SPItemView *v = item->display; v != NULL; v = v->next) {
+ if (!v->arenaitem->key()) {
+ v->arenaitem->setKey(SPItem::display_key_new(3));
+ }
+ Inkscape::DrawingItem *ai = clip_path->show(
+ v->arenaitem->drawing(),
+ v->arenaitem->key());
+ v->arenaitem->setClip(ai);
+ clip_path->setBBox(v->arenaitem->key(), bbox);
+ }
+ }
+ clip_path->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+}
+
+void
+LPEPowerClip::convertShapes() {
+ convert_shapes = true;
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(sp_lpe_item), false, false);
+}
+
+Gtk::Widget *
+LPEPowerClip::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
+ Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(6);
+
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter * param = *it;
+ Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+ ++it;
+ }
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::Button * toggle_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Toggle clip visibiliy"))));
+ toggle_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPowerClip::toggleClip));
+ toggle_button->set_size_request(180,30);
+ vbox->pack_start(*hbox, true,true,2);
+ hbox->pack_start(*toggle_button, false, false,2);
+ Gtk::HBox * hbox2 = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::Button * topaths_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Convert clips to paths, undoable"))));
+ topaths_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPowerClip::convertShapes));
+ topaths_button->set_size_request(220,30);
+ vbox->pack_start(*hbox2, true,true,2);
+ hbox2->pack_start(*topaths_button, false, false,2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPEPowerClip::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ SPClipPath *clip_path = SP_ITEM(sp_lpe_item)->clip_ref->getObject();
+ if(!keep_paths) {
+ if(clip_path) {
+ is_clip = true;
+ std::vector<SPObject*> clip_path_list = clip_path->childList(true);
+ for ( std::vector<SPObject*>::const_iterator iter=clip_path_list.begin();iter!=clip_path_list.end();++iter) {
+ SPObject * clip_data = *iter;
+ if(is_inverse.param_getSVGValue() == (Glib::ustring)"true") {
+ removeInverse(SP_ITEM(clip_data));
+ }
+ }
+ }
+ } else {
+ if (flatten && clip_path) {
+ clip_path->deleteObject();
+ sp_lpe_item->getRepr()->setAttribute("clip-path", NULL);
+ }
+ }
+}
+
+Geom::PathVector
+LPEPowerClip::doEffect_path(Geom::PathVector const & path_in){
+ Geom::PathVector path_out = pathv_to_linear_and_cubic_beziers(path_in);
+ if (flatten && is_clip && isVisible()) {
+ SPClipPath *clip_path = SP_ITEM(sp_lpe_item)->clip_ref->getObject();
+ if(clip_path) {
+ std::vector<SPObject*> clip_path_list = clip_path->childList(true);
+ for ( std::vector<SPObject*>::const_iterator iter=clip_path_list.begin();iter!=clip_path_list.end();++iter) {
+ SPObject * clip_data = *iter;
+ flattenClip(SP_ITEM(clip_data), path_out);
+ }
+ }
+ }
+ return path_out;
+}
+
+void
+LPEPowerClip::doOnVisibilityToggled(SPLPEItem const* lpeitem)
+{
+ doBeforeEffect(lpeitem);
+}
+
+
+//void
+//LPEPowerClip::transform_multiply(Geom::Affine const& postmul, bool set)
+//{
+// SPDocument * doc = SP_ACTIVE_DOCUMENT;
+// SPClipPath *clip_path = SP_ITEM(sp_lpe_item)->clip_ref->getObject();
+// if (is_clip && lock) {
+// std::vector<SPObject*> clip_path_list = clip_path->childList(true);
+// Glib::ustring clip_id = (Glib::ustring)clip_path->getId();
+// Glib::ustring box_id = clip_id + (Glib::ustring)"_box";
+// for ( std::vector<SPObject*>::const_iterator iter=clip_path_list.begin();iter!=clip_path_list.end();++iter) {
+// SPItem * clip_data = SP_ITEM(*iter);
+// if(inverse && is_clip && lock) {
+// removeInverse(clip_data);
+// }
+// if (lock) {
+// clip_data->transform *= postmul;
+//// if (!inverse) {
+//// SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+//// if (desktop) {
+//// if (tools_isactive(desktop, TOOLS_NODES)) {
+//// Inkscape::Selection * sel = SP_ACTIVE_DESKTOP->getSelection();
+//// SPItem * item = sel->singleItem();
+//// if (item != NULL) {
+//// sel->remove(item);
+//// sel->add(item);
+//// }
+//// }
+//// }
+//// }
+// }
+// if(inverse && is_clip && lock) {
+// doBeforeEffect(sp_lpe_item);
+// }
+// }
+// }
+// //cycle through all parameters. Most parameters will not need transformation, but path and point params
+// for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
+// Parameter * param = *it;
+// param->param_transform_multiply(postmul, set);
+// }
+// toggleClip();
+// toggleClip();
+//}
+
+void
+LPEPowerClip::flattenClip(SPItem * clip_data, Geom::PathVector &path_in)
+{
+ if (SP_IS_GROUP(clip_data)) {
+ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(clip_data));
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
+ SPItem *subitem = *iter;
+ flattenClip(subitem, path_in);
+ }
+ } else if (SP_IS_PATH(clip_data)) {
+ SPCurve * c = NULL;
+ c = SP_SHAPE(clip_data)->getCurve();
+ if (c) {
+ Geom::PathVector c_pv = c->get_pathvector();
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(c_pv, path_in);
+ if (pig && !c_pv.empty() && !path_in.empty()) {
+ path_in = pig->getIntersection();
+ }
+ c->unref();
+ }
+ }
+}
+
+}; //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/lpe-powerclip.h b/src/live_effects/lpe-powerclip.h
new file mode 100644
index 000000000..ce46b560a
--- /dev/null
+++ b/src/live_effects/lpe-powerclip.h
@@ -0,0 +1,47 @@
+#ifndef INKSCAPE_LPE_POWERCLIP_H
+#define INKSCAPE_LPE_POWERCLIP_H
+
+/*
+ * Inkscape::LPEPowerClip
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+#include "live_effects/parameter/hidden.h"
+#include "live_effects/lpegroupbbox.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEPowerClip : public Effect, GroupBBoxEffect {
+public:
+ LPEPowerClip(LivePathEffectObject *lpeobject);
+ virtual ~LPEPowerClip();
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual Gtk::Widget * newWidget();
+ //virtual void transform_multiply(Geom::Affine const& postmul, bool set);
+ virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem);
+ void toggleClip();
+ void addInverse (SPItem * clip_data);
+ void removeInverse (SPItem * clip_data);
+ void flattenClip(SPItem * clip_data, Geom::PathVector &path_in);
+ void convertShapes();
+private:
+ BoolParam inverse;
+ BoolParam flatten;
+ // BoolParam lock;
+ HiddenParam is_inverse;
+ Geom::Path clip_box;
+ Geom::Affine base;
+ bool is_clip;
+ bool convert_shapes;
+ bool hide_clip;
+ bool previous_hide_clip;
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+#endif
diff --git a/src/live_effects/lpe-powermask.cpp b/src/live_effects/lpe-powermask.cpp
new file mode 100644
index 000000000..434ad6dd4
--- /dev/null
+++ b/src/live_effects/lpe-powermask.cpp
@@ -0,0 +1,357 @@
+/*
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#include "live_effects/lpe-powermask.h"
+#include <2geom/path-intersection.h>
+#include <2geom/intersection-graph.h>
+#include "display/drawing-item.h"
+#include "display/curve.h"
+#include "helper/geom.h"
+#include "sp-mask.h"
+#include "sp-path.h"
+#include "sp-shape.h"
+#include "sp-defs.h"
+#include "style.h"
+#include "sp-item-group.h"
+#include "svg/svg.h"
+#include "ui/tools-switch.h"
+#include "path-chemistry.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPEPowerMask::LPEPowerMask(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ invert(_("Invert mask"), _("Invert mask"), "invert", &wr, this, false),
+ wrap(_("Wrap mask data"), _("Wrap mask data allowing previous filters"), "wrap", &wr, this, false),
+ background(_("Add background to mask"), _("Add background to mask"), "background", &wr, this, false),
+ //lock(_("Lock mask"), _("Lock mask"), "lock", &wr, this, false),
+ background_style(_("Background Style"), _("CSS to background"), "background_style", &wr, this,"fill:#ffffff;opacity:1;")
+
+{
+ registerParameter(&invert);
+ registerParameter(&wrap);
+ //registerParameter(&lock);
+ registerParameter(&background);
+ registerParameter(&background_style);
+ //lock.param_setValue(false);
+ background_style.param_hide_canvas_text();
+ hide_mask = false;
+}
+
+LPEPowerMask::~LPEPowerMask() {}
+
+void
+LPEPowerMask::doBeforeEffect (SPLPEItem const* lpeitem){
+ original_bbox(lpeitem);
+ SPMask *mask = SP_ITEM(lpeitem)->mask_ref->getObject();
+ Geom::Point topleft = Geom::Point(boundingbox_X.min() - 5,boundingbox_Y.max() + 5);
+ Geom::Point topright = Geom::Point(boundingbox_X.max() + 5,boundingbox_Y.max() + 5);
+ Geom::Point bottomright = Geom::Point(boundingbox_X.max() + 5,boundingbox_Y.min() - 5);
+ Geom::Point bottomleft = Geom::Point(boundingbox_X.min() - 5,boundingbox_Y.min() - 5);
+ mask_box.clear();
+ mask_box.start(topleft);
+ mask_box.appendNew<Geom::LineSegment>(topright);
+ mask_box.appendNew<Geom::LineSegment>(bottomright);
+ mask_box.appendNew<Geom::LineSegment>(bottomleft);
+ mask_box.close();
+ if(mask) {
+ setMask();
+ }
+}
+
+void
+LPEPowerMask::setMask(){
+ SPMask *mask = SP_ITEM(sp_lpe_item)->mask_ref->getObject();
+ SPObject *elemref = NULL;
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ if (!document || !mask) {
+ return;
+ }
+ Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = document->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Inkscape::XML::Node *box = NULL;
+ Inkscape::XML::Node *filter = NULL;
+ SPDefs * defs = document->getDefs();
+ Glib::ustring mask_id = (Glib::ustring)mask->getId();
+ Glib::ustring box_id = mask_id + (Glib::ustring)"_box";
+ Glib::ustring filter_id = mask_id + (Glib::ustring)"_inverse";
+ Glib::ustring filter_label = (Glib::ustring)"filter" + mask_id;
+ Glib::ustring filter_uri = (Glib::ustring)"url(#" + filter_id + (Glib::ustring)")";
+ if (!(elemref = document->getObjectById(filter_id))) {
+ filter = xml_doc->createElement("svg:filter");
+ filter->setAttribute("id", filter_id.c_str());
+ filter->setAttribute("inkscape:label", filter_label.c_str());
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css, "color-interpolation-filters", "sRGB");
+ sp_repr_css_change(filter, css, "style");
+ sp_repr_css_attr_unref(css);
+ filter->setAttribute("height", "100");
+ filter->setAttribute("width", "100");
+ filter->setAttribute("x", "-50");
+ filter->setAttribute("y", "-50");
+ Inkscape::XML::Node *primitive1 = xml_doc->createElement("svg:feColorMatrix");
+ Glib::ustring primitive1_id = (mask_id + (Glib::ustring)"_primitive1").c_str();
+ primitive1->setAttribute("id", primitive1_id.c_str());
+ primitive1->setAttribute("values", "1");
+ primitive1->setAttribute("type", "saturate");
+ primitive1->setAttribute("result", "fbSourceGraphic");
+ Inkscape::XML::Node *primitive2 = xml_doc->createElement("svg:feColorMatrix");
+ Glib::ustring primitive2_id = (mask_id + (Glib::ustring)"_primitive2").c_str();
+ primitive2->setAttribute("id", primitive2_id.c_str());
+ primitive2->setAttribute("values", "-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 ");
+ primitive2->setAttribute("in", "fbSourceGraphic");
+ elemref = defs->appendChildRepr(filter);
+ Inkscape::GC::release(filter);
+ filter->appendChild(primitive1);
+ Inkscape::GC::release(primitive1);
+ filter->appendChild(primitive2);
+ Inkscape::GC::release(primitive2);
+ }
+ if(wrap && is_visible){
+ Glib::ustring g_data_id = mask_id + (Glib::ustring)"_container";
+ if((elemref = document->getObjectById(g_data_id))){
+ elemref->getRepr()->setPosition(-1);
+ } else {
+ Inkscape::XML::Node * container = xml_doc->createElement("svg:g");
+ container->setAttribute("id", g_data_id.c_str());
+ mask->appendChildRepr(container);
+ std::vector<SPObject*> mask_list = mask->childList(true);
+ container->setPosition(-1);
+ Inkscape::GC::release(container);
+ for ( std::vector<SPObject*>::const_iterator iter=mask_list.begin();iter!=mask_list.end();++iter) {
+ SPItem * mask_data = SP_ITEM(*iter);
+ Inkscape::XML::Node *mask_node = mask_data->getRepr();
+ if (! strcmp(mask_data->getId(), box_id.c_str()) ||
+ ! strcmp(mask_data->getId(), g_data_id.c_str()))
+ {
+ continue;
+ }
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ if(mask_node->attribute("style")) {
+ sp_repr_css_attr_add_from_string(css, mask_node->attribute("style"));
+ }
+ char const* filter = sp_repr_css_property (css, "filter", NULL);
+ if(!filter || !strcmp(filter, filter_uri.c_str())) {
+ sp_repr_css_set_property (css, "filter", NULL);
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css, css_str);
+ mask_node->setAttribute("style", css_str.c_str());
+ mask->getRepr()->removeChild(mask_node);
+ container->appendChild(mask_node);
+ Inkscape::GC::release(mask_node);
+ }
+ }
+ } else {
+ Glib::ustring g_data_id = mask_id + (Glib::ustring)"_container";
+ if((elemref = document->getObjectById(g_data_id))){
+ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(elemref));
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
+ Inkscape::XML::Node *mask_node = (*iter)->getRepr();
+ elemref->getRepr()->removeChild(mask_node);
+ mask->getRepr()->appendChild(mask_node);
+ Inkscape::GC::release(mask_node);
+ }
+ sp_object_ref(elemref, 0 );
+ elemref->deleteObject(true);
+ sp_object_unref(elemref);
+ }
+ }
+ std::vector<SPObject*> mask_list = mask->childList(true);
+ for ( std::vector<SPObject*>::const_iterator iter=mask_list.begin();iter!=mask_list.end();++iter) {
+ SPItem * mask_data = SP_ITEM(*iter);
+ Inkscape::XML::Node *mask_node = mask_data->getRepr();
+ if (! strcmp(mask_data->getId(), box_id.c_str())){
+ continue;
+ }
+ Glib::ustring mask_data_id = (Glib::ustring)mask_data->getId();
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ if(mask_node->attribute("style")) {
+ sp_repr_css_attr_add_from_string(css, mask_node->attribute("style"));
+ }
+ char const* filter = sp_repr_css_property (css, "filter", NULL);
+ if(!filter || !strcmp(filter, filter_uri.c_str())) {
+ if (invert && is_visible) {
+ sp_repr_css_set_property (css, "filter", filter_uri.c_str());
+ } else {
+ sp_repr_css_set_property (css, "filter", NULL);
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css, css_str);
+ mask_node->setAttribute("style", css_str.c_str());
+ }
+ }
+ if ((elemref = document->getObjectById(box_id))) {
+ elemref->deleteObject(true);
+ }
+ if (background && is_visible) {
+ bool exist = true;
+ if (!(elemref = document->getObjectById(box_id))) {
+ box = xml_doc->createElement("svg:path");
+ box->setAttribute("id", box_id.c_str());
+ exist = false;
+ }
+ box->setAttribute("style", background_style.param_getSVGValue());
+ gchar * box_str = sp_svg_write_path( mask_box );
+ box->setAttribute("d" , box_str);
+ g_free(box_str);
+ if (!exist) {
+ elemref = mask->appendChildRepr(box);
+ Inkscape::GC::release(box);
+ }
+ box->setPosition(1);
+ } else if ((elemref = document->getObjectById(box_id))) {
+ elemref->deleteObject(true);
+ }
+ mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void
+LPEPowerMask::doOnVisibilityToggled(SPLPEItem const* lpeitem)
+{
+ doBeforeEffect(lpeitem);
+}
+
+void
+LPEPowerMask::doEffect (SPCurve * curve)
+{
+}
+
+void
+LPEPowerMask::toggleMask() {
+ SPItem * item = SP_ITEM(sp_lpe_item);
+ if (item) {
+ SPMask *mask = item->mask_ref->getObject();
+ if (mask) {
+ hide_mask = !hide_mask;
+ if(hide_mask) {
+ SPItemView *v;
+ for (v = item->display; v != NULL; v = v->next) {
+ mask->sp_mask_hide(v->arenaitem->key());
+ }
+ } else {
+ Geom::OptRect bbox = item->geometricBounds();
+ for (SPItemView *v = item->display; v != NULL; v = v->next) {
+ if (!v->arenaitem->key()) {
+ v->arenaitem->setKey(SPItem::display_key_new(3));
+ }
+ Inkscape::DrawingItem *ai = mask->sp_mask_show(
+ v->arenaitem->drawing(),
+ v->arenaitem->key());
+ bbox.unionWith(ai->geometricBounds());
+ v->arenaitem->setMask(ai);
+ mask->sp_mask_set_bbox(v->arenaitem->key(), bbox);
+ }
+ }
+ mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+}
+
+//void
+//LPEPowerMask::transform_multiply(Geom::Affine const& postmul, bool set)
+//{
+// SPMask *mask_path = SP_ITEM(sp_lpe_item)->mask_ref->getObject();
+// if (mask_path && lock) {
+// SPMask *mask_path = SP_ITEM(sp_lpe_item)->mask_ref->getObject();
+// std::vector<SPObject*> mask_path_list = mask_path->childList(true);
+// Glib::ustring mask_id = (Glib::ustring)mask_path->getId();
+// Glib::ustring box_id = mask_id + (Glib::ustring)"_box";
+// for ( std::vector<SPObject*>::const_iterator iter=mask_path_list.begin();iter!=mask_path_list.end();++iter) {
+// SPObject * mask_data = *iter;
+// if (! strcmp(mask_data->getId(), box_id.c_str())){
+// continue;
+// }
+// SP_ITEM(mask_data)->transform *= postmul.inverse();
+// }
+// }
+// //cycle through all parameters. Most parameters will not need transformation, but path and point params
+// for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
+// Parameter * param = *it;
+// param->param_transform_multiply(postmul, set);
+// }
+// sp_lpe_item_update_patheffect(SP_LPE_ITEM(sp_lpe_item), false, false);
+//}
+
+
+
+Gtk::Widget *
+LPEPowerMask::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
+ Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(6);
+
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter * param = *it;
+ Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::Button * toggle_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Toggle mask visibiliy"))));
+ toggle_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPowerMask::toggleMask));
+ toggle_button->set_size_request(140,30);
+ vbox->pack_start(*hbox, true,true,2);
+ hbox->pack_start(*toggle_button, false, false,2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPEPowerMask::doOnRemove (SPLPEItem const* lpeitem)
+{
+ if(!keep_paths) {
+ SPMask *mask = lpeitem->mask_ref->getObject();
+ if (mask) {
+ invert.param_setValue(false);
+ wrap.param_setValue(false);
+ background.param_setValue(false);
+ setMask();
+ SPObject *elemref = NULL;
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Glib::ustring mask_id = (Glib::ustring)mask->getId();
+ Glib::ustring filter_id = mask_id + (Glib::ustring)"_inverse";
+ if ((elemref = document->getObjectById(filter_id))) {
+ elemref->deleteObject(true);
+ }
+ }
+ }
+}
+
+}; //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/lpe-powermask.h b/src/live_effects/lpe-powermask.h
new file mode 100644
index 000000000..cd36b3b37
--- /dev/null
+++ b/src/live_effects/lpe-powermask.h
@@ -0,0 +1,41 @@
+#ifndef INKSCAPE_LPE_POWERMASK_H
+#define INKSCAPE_LPE_POWERMASK_H
+
+/*
+ * Inkscape::LPEPowerMask
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+#include "live_effects/parameter/text.h"
+#include "live_effects/lpegroupbbox.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEPowerMask : public Effect, GroupBBoxEffect {
+public:
+ LPEPowerMask(LivePathEffectObject *lpeobject);
+ virtual ~LPEPowerMask();
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void doEffect (SPCurve * curve);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual Gtk::Widget * newWidget();
+ virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem);
+ //virtual void transform_multiply(Geom::Affine const& postmul, bool set);
+ void toggleMask();
+ void setMask();
+private:
+ BoolParam invert;
+ BoolParam wrap;
+ BoolParam background;
+ //BoolParam lock;
+ TextParam background_style;
+ Geom::Path mask_box;
+ bool hide_mask;
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+#endif
diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp
index b371e15b2..1829837d8 100644
--- a/src/sp-clippath.cpp
+++ b/src/sp-clippath.cpp
@@ -227,7 +227,6 @@ void SPClipPath::hide(unsigned int key) {
SP_ITEM(&child)->invoke_hide(key);
}
}
-
for (SPClipPathView *v = display; v != NULL; v = v->next) {
if (v->key == key) {
/* We simply unref and let item to manage this in handler */
@@ -235,8 +234,6 @@ void SPClipPath::hide(unsigned int key) {
return;
}
}
-
- g_assert_not_reached();
}
void SPClipPath::setBBox(unsigned int key, Geom::OptRect const &bbox) {
diff --git a/src/sp-clippath.h b/src/sp-clippath.h
index 7b1c83356..129f3b7f3 100644
--- a/src/sp-clippath.h
+++ b/src/sp-clippath.h
@@ -21,7 +21,6 @@
struct SPClipPathView;
#include <cstdio>
-
#include "sp-object-group.h"
#include "uri-references.h"
#include "xml/node.h"
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 368f8896c..4f3c7d283 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -1373,7 +1373,7 @@ void SPItem::adjust_paint_recursive (Geom::Affine advertized_transform, Geom::Af
// Within text, we do not fork gradients, and so must not recurse to avoid double compensation;
// also we do not recurse into clones, because a clone's child is the ghost of its original -
// we must not touch it
- if (!(this && (dynamic_cast<SPText *>(this) || dynamic_cast<SPUse *>(this)))) {
+ if (!(dynamic_cast<SPText *>(this) || dynamic_cast<SPUse *>(this))) {
for (auto& o: children) {
SPItem *item = dynamic_cast<SPItem *>(&o);
if (item) {
@@ -1401,7 +1401,6 @@ void SPItem::adjust_livepatheffect (Geom::Affine const &postmul, bool set)
SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(this);
if ( lpeitem && lpeitem->hasPathEffect() ) {
lpeitem->forkPathEffectsIfNecessary();
-
// now that all LPEs are forked_if_necessary, we can apply the transform
PathEffectList effect_list = lpeitem->getEffectList();
for (PathEffectList::iterator it = effect_list.begin(); it != effect_list.end(); ++it)
@@ -1496,6 +1495,10 @@ void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &tra
freeze_stroke_width_recursive(false);
}
} else {
+ SPLPEItem * lpeitem = SP_LPE_ITEM(this);
+ if (lpeitem && lpeitem->hasPathEffectRecursive()) {
+ lpeitem->adjust_livepatheffect(transform_attr);
+ }
if (freeze_stroke_width) {
freeze_stroke_width_recursive(false);
if (compensate) {
diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp
index 4690ffda2..a47fab35e 100644
--- a/src/sp-mask.cpp
+++ b/src/sp-mask.cpp
@@ -23,7 +23,8 @@
#include "attributes.h"
#include "document.h"
#include "document-private.h"
-
+#include "style.h"
+#include "attributes.h"
#include "sp-mask.h"
struct SPMaskView {
diff --git a/src/sp-path.cpp b/src/sp-path.cpp
index c6ec5559e..bb76eb73f 100644
--- a/src/sp-path.cpp
+++ b/src/sp-path.cpp
@@ -289,7 +289,6 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
if (!_curve) { // 0 nodes, nothing to transform
return Geom::identity();
}
-
// Transform the original-d path if this is a valid LPE this, other else the (ordinary) path
if (_curve_before_lpe && hasPathEffectRecursive()) {
if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL) ||
@@ -297,7 +296,7 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
this->hasPathEffectOfType(Inkscape::LivePathEffect::FILL_BETWEEN_MANY) ||
this->hasPathEffectOfType(Inkscape::LivePathEffect::FILL_BETWEEN_STROKES) )
{
- // if path has the CLONE_ORIGINAL LPE applied, don't write the transform to the pathdata, but write it 'unoptimized'
+ // if path has this LPE applied, don't write the transform to the pathdata, but write it 'unoptimized'
// also if the effect is type BEND PATH to fix bug #179842
this->adjust_livepatheffect(transform);
return transform;
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index 08aacf805..d508a16f2 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -368,7 +368,10 @@ void gather_items(NodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Shape
}
//XML Tree being used directly here while it shouldn't be.
- if (SP_IS_PATH(obj) && obj->getRepr()->attribute("inkscape:original-d") != NULL) {
+ if (SP_IS_PATH(obj) &&
+ obj->getRepr()->attribute("inkscape:original-d") != NULL &&
+ !SP_LPE_ITEM(obj)->hasPathEffectOfType(Inkscape::LivePathEffect::POWERCLIP))
+ {
ShapeRecord r;
r.item = static_cast<SPItem*>(obj);
r.edit_transform = Geom::identity(); // TODO wrong?