diff options
Diffstat (limited to 'src/live_effects/lpe-powerclip.cpp')
| -rw-r--r-- | src/live_effects/lpe-powerclip.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/live_effects/lpe-powerclip.cpp b/src/live_effects/lpe-powerclip.cpp new file mode 100644 index 000000000..a3a827ec4 --- /dev/null +++ b/src/live_effects/lpe-powerclip.cpp @@ -0,0 +1,297 @@ +/* + * 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), + hide_clip(_("Hide clip"), _("Hide clip"), "hide_clip", &wr, this, false), + inverse(_("Inverse clip"), _("Inverse clip"), "inverse", &wr, this, false), + flatten(_("Flatten clip"), _("Flatten clip"), "flatten", &wr, this, false), + fillrule(_("Set/unset evenodd fill rule"), _("Set/unset evenodd fill rule (this is overwriting your current value)."), "fillrule", &wr, this, false), + convert_shapes(_("Convert clip shapes to paths"), _("Convert clip shapes to paths (this is overwriting your current value)."), "convert_shapes", &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(&hide_clip); + registerParameter(&inverse); + registerParameter(&flatten); + registerParameter(&fillrule); + registerParameter(&convert_shapes); + registerParameter(&is_inverse); + is_clip = false; + previous_fillrule = fillrule; +} + +LPEPowerClip::~LPEPowerClip() {} + +void +LPEPowerClip::doBeforeEffect (SPLPEItem const* lpeitem){ + original_bbox(lpeitem); + const Glib::ustring uri = (Glib::ustring)sp_lpe_item->getRepr()->attribute("clip-path"); + SPClipPath *clip_path = SP_ITEM(lpeitem)->clip_ref->getObject(); + SPItem * item = SP_ITEM(lpeitem); + if(hide_clip) { + SPItemView *v; + for (v = item->display; v != NULL; v = v->next) { + clip_path->hide(v->arenaitem->key()); + } + Geom::OptRect bbox = item->geometricBounds(); + clip_path->setBBox(v->arenaitem->key(), bbox); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } else if (!hide_clip) { + 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); + } + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } + 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; + 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 (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(); + const char * id = clip_data->getId(); + Inkscape::XML::Node *clip_path_node = sp_selected_item_to_curved_repr(SP_ITEM(clip_data), 0); + clip_data->updateRepr(xml_doc, clip_path_node, SP_OBJECT_WRITE_ALL); + clip_data->getRepr()->setAttribute("id", id); + clip_path->emitModified(SP_OBJECT_MODIFIED_CASCADE); + std::cout << "toshapes\n"; + } + if( inverse && isVisible()) { + addInverse(SP_ITEM(clip_data)); + } else if(is_inverse.param_getSVGValue() == (Glib::ustring)"true") { + removeInverse(SP_ITEM(clip_data)); + } + } + } else { + is_clip = false; + } +} + +void +LPEPowerClip::addInverse (SPItem * clip_data){ + 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)) { + setFillRule(clip_data); + SPCurve * c = NULL; + c = SP_SHAPE(clip_data)->getCurve(); + if (c) { + Geom::PathVector c_pv = c->get_pathvector(); + if(is_inverse.param_getSVGValue() == (Glib::ustring)"true") { + c_pv.pop_back(); + } + //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)) { + setFillRule(clip_data); + SPCurve * c = NULL; + c = SP_SHAPE(clip_data)->getCurve(); + if (c) { + Geom::PathVector c_pv = c->get_pathvector(); + 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::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)); + is_inverse.param_setValue((Glib::ustring)"false"); + } + } + } + } 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::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)) { + if (!SP_IS_PATH(clip_data) && convert_shapes) { + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + const char * id = clip_data->getId(); + Inkscape::XML::Node *clip_path_node = sp_selected_item_to_curved_repr(clip_data, 0); + clip_data->updateRepr(xml_doc, clip_path_node, SP_OBJECT_WRITE_ALL); + clip_data->getRepr()->setAttribute("id", id); + } + 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(); + } + } +} + +void +LPEPowerClip::setFillRule(SPItem * clip_data) +{ + if (previous_fillrule != fillrule) { + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, clip_data->getRepr()->attribute("style")); + if (fillrule) { + sp_repr_css_set_property (css, "fill-rule", "evenodd"); + } else { + sp_repr_css_set_property (css, "fill-rule", "nonzero"); + } + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + clip_data->getRepr()->setAttribute("style", css_str.c_str()); + previous_fillrule = fillrule; + } +} + +}; //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 : |
