diff options
| author | Martin Owens <doctormo@gmail.com> | 2017-08-13 11:26:35 +0000 |
|---|---|---|
| committer | Martin Owens <doctormo@gmail.com> | 2017-08-13 11:26:35 +0000 |
| commit | 203bb5ccb8d526f3460e476693642c05bd6fab2f (patch) | |
| tree | 7b7e3142393909358d50019efc6fc5e1bc91fcca /src | |
| parent | Merge branch 'alvinpenner/inkscape-master' (diff) | |
| parent | update to trunk (diff) | |
| download | inkscape-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.txt | 4 | ||||
| -rw-r--r-- | src/live_effects/effect-enum.h | 2 | ||||
| -rw-r--r-- | src/live_effects/effect.cpp | 11 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerclip.cpp | 407 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerclip.h | 47 | ||||
| -rw-r--r-- | src/live_effects/lpe-powermask.cpp | 357 | ||||
| -rw-r--r-- | src/live_effects/lpe-powermask.h | 41 | ||||
| -rw-r--r-- | src/sp-clippath.cpp | 3 | ||||
| -rw-r--r-- | src/sp-clippath.h | 1 | ||||
| -rw-r--r-- | src/sp-item.cpp | 7 | ||||
| -rw-r--r-- | src/sp-mask.cpp | 3 | ||||
| -rw-r--r-- | src/sp-path.cpp | 3 | ||||
| -rw-r--r-- | src/ui/tools/node-tool.cpp | 5 |
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? |
