/* * 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 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(topright); mask_box.appendNew(bottomright); mask_box.appendNew(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 mask_list = mask->childList(true); container->setPosition(-1); Inkscape::GC::release(container); for ( std::vector::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 item_list = sp_item_group_item_list(SP_GROUP(elemref)); for ( std::vector::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 mask_list = mask->childList(true); for ( std::vector::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 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::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::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::iterator it = param_vector.begin(); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter * param = *it; Gtk::Widget * widg = dynamic_cast(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(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 :