#define __SP_LPE_ITEM_CPP__ /** \file * Base class for live path effect items */ /* * Authors: * Johan Engelen * Bastien Bouclet * * Copyright (C) 2008 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "live_effects/effect.h" #include "live_effects/lpe-path_length.h" #include "live_effects/lpeobject.h" #include "live_effects/lpeobject-reference.h" #include "sp-path.h" #include "sp-item-group.h" #include "streq.h" #include "macros.h" #include "attributes.h" #include "sp-lpe-item.h" #include "xml/repr.h" #include "uri.h" #include "message-stack.h" #include "inkscape.h" #include "desktop.h" #include "node-context.h" #include "shape-editor.h" #include /* LPEItem base class */ static void sp_lpe_item_class_init(SPLPEItemClass *klass); static void sp_lpe_item_init(SPLPEItem *lpe_item); static void sp_lpe_item_finalize(GObject *object); static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_lpe_item_release(SPObject *object); static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value); static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_lpe_item_modified (SPObject *object, unsigned int flags); static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags); static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref); static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child); static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable); static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem); static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem); static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem); static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem); typedef std::list HRefList; static std::string patheffectlist_write_svg(PathEffectList const & list); static std::string hreflist_write_svg(HRefList const & list); static SPItemClass *parent_class; GType sp_lpe_item_get_type() { static GType lpe_item_type = 0; if (!lpe_item_type) { GTypeInfo lpe_item_info = { sizeof(SPLPEItemClass), NULL, NULL, (GClassInitFunc) sp_lpe_item_class_init, NULL, NULL, sizeof(SPLPEItem), 16, (GInstanceInitFunc) sp_lpe_item_init, NULL, /* value_table */ }; lpe_item_type = g_type_register_static(SP_TYPE_ITEM, "SPLPEItem", &lpe_item_info, (GTypeFlags)0); } return lpe_item_type; } static void sp_lpe_item_class_init(SPLPEItemClass *klass) { GObjectClass *gobject_class; SPObjectClass *sp_object_class; gobject_class = (GObjectClass *) klass; sp_object_class = (SPObjectClass *) klass; parent_class = (SPItemClass *)g_type_class_peek_parent (klass); gobject_class->finalize = sp_lpe_item_finalize; sp_object_class->build = sp_lpe_item_build; sp_object_class->release = sp_lpe_item_release; sp_object_class->set = sp_lpe_item_set; sp_object_class->update = sp_lpe_item_update; sp_object_class->modified = sp_lpe_item_modified; sp_object_class->write = sp_lpe_item_write; sp_object_class->child_added = sp_lpe_item_child_added; sp_object_class->remove_child = sp_lpe_item_remove_child; klass->update_patheffect = NULL; } static void sp_lpe_item_init(SPLPEItem *lpeitem) { lpeitem->path_effects_enabled = 1; lpeitem->path_effect_list = new PathEffectList(); lpeitem->current_path_effect = NULL; new (&lpeitem->lpe_modified_connection) sigc::connection(); } static void sp_lpe_item_finalize(GObject *object) { if (((GObjectClass *) (parent_class))->finalize) { (* ((GObjectClass *) (parent_class))->finalize)(object); } } /** * Reads the Inkscape::XML::Node, and initializes SPLPEItem variables. For this to get called, * our name must be associated with a repr via "sp_object_type_register". Best done through * sp-object-repr.cpp's repr_name_entries array. */ static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { sp_object_read_attr(object, "inkscape:path-effect"); if (((SPObjectClass *) parent_class)->build) { ((SPObjectClass *) parent_class)->build(object, document, repr); } } /** * Drops any allocated memory. */ static void sp_lpe_item_release(SPObject *object) { SPLPEItem *lpeitem = (SPLPEItem *) object; lpeitem->lpe_modified_connection.disconnect(); lpeitem->lpe_modified_connection.~connection(); PathEffectList::iterator it = lpeitem->path_effect_list->begin(); while ( it != lpeitem->path_effect_list->end() ) { // unlink and delete all references in the list (*it)->unlink(); delete *it; it = lpeitem->path_effect_list->erase(it); } // delete the list itself delete SP_LPE_ITEM(object)->path_effect_list; if (((SPObjectClass *) parent_class)->release) ((SPObjectClass *) parent_class)->release(object); } /** * Sets a specific value in the SPLPEItem. */ static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value) { SPLPEItem *lpeitem = (SPLPEItem *) object; switch (key) { case SP_ATTR_INKSCAPE_PATH_EFFECT: { lpeitem->current_path_effect = NULL; // Disable the path effects while populating the LPE list sp_lpe_item_enable_path_effects(lpeitem, false); // Clear the path effect list PathEffectList::iterator it = lpeitem->path_effect_list->begin(); while ( it != lpeitem->path_effect_list->end() ) { (*it)->unlink(); delete *it; it = lpeitem->path_effect_list->erase(it); } // Parse the contents of "value" to rebuild the path effect reference list if ( value ) { std::istringstream iss(value); std::string href; while (std::getline(iss, href, ';')) { Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref; path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem)); path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object))); // Now do the attaching, which emits the changed signal. // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list try { path_effect_ref->link(href.c_str()); } catch (Inkscape::BadURIException &e) { g_warning("BadURIException: %s", e.what()); path_effect_ref->unlink(); delete path_effect_ref; path_effect_ref = NULL; } if (path_effect_ref) { lpeitem->path_effect_list->push_back(path_effect_ref); } } } sp_lpe_item_enable_path_effects(lpeitem, true); } break; default: if (((SPObjectClass *) parent_class)->set) { ((SPObjectClass *) parent_class)->set(object, key, value); } break; } } /** * Receives update notifications. */ static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags) { if (((SPObjectClass *) parent_class)->update) { ((SPObjectClass *) parent_class)->update(object, ctx, flags); } // update the helperpaths of all LPEs applied to the item // TODO: is there a more canonical place for this, since we don't have instant access to the item's nodepath? // FIXME: this is called multiple (at least 3) times; how can we avoid this? // FIXME: ditch inkscape_active_event_context() SPEventContext *ec = inkscape_active_event_context(); if (!SP_IS_NODE_CONTEXT(ec)) return; SPNodeContext *nc = SP_NODE_CONTEXT(ec); ShapeEditor *sh = nc->shape_editor; g_assert(sh); if (!sh->has_nodepath()) return; Inkscape::NodePath::Path *np = sh->get_nodepath(); sp_nodepath_update_helperpaths(np); } /** * Sets modified flag for all sub-item views. */ static void sp_lpe_item_modified (SPObject *object, unsigned int flags) { if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) { sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true); } if (((SPObjectClass *) (parent_class))->modified) { (* ((SPObjectClass *) (parent_class))->modified) (object, flags); } } /** * Writes its settings to an incoming repr object, if any. */ static Inkscape::XML::Node * sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { SPLPEItem *lpeitem = (SPLPEItem *) object; if ( sp_lpe_item_has_path_effect(lpeitem) ) { std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list); repr->setAttribute("inkscape:path-effect", href.c_str()); } else { repr->setAttribute("inkscape:path-effect", NULL); } if (((SPObjectClass *)(parent_class))->write) { ((SPObjectClass *)(parent_class))->write(object, xml_doc, repr, flags); } return repr; } void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) { if (!lpeitem) return; if (!curve) return; if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) { for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (!lpeobj) { g_warning("sp_lpe_item_perform_path_effect - NULL lpeobj in list!"); return; } if (!lpeobj->lpe) { g_warning("sp_lpe_item_perform_path_effect - lpeobj without lpe!"); return; } Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe; if (lpe->isVisible()) { if (lpe->acceptsNumClicks() > 0 && !lpe->isReady()) { // if the effect expects mouse input before being applied and the input is not finished // yet, we don't alter the path return; } // Groups have their doBeforeEffect called elsewhere if (!SP_IS_GROUP(lpeitem)) { lpe->doBeforeEffect(lpeitem); } try { lpe->doEffect(curve); } catch (std::exception & e) { g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what()); SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE, _("An exception occurred during execution of the Path Effect.") ); } } } } } /** * Calls any registered handlers for the update_patheffect action */ void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write) { #ifdef SHAPE_VERBOSE g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem); #endif g_return_if_fail (lpeitem != NULL); g_return_if_fail (SP_IS_LPE_ITEM (lpeitem)); if (!sp_lpe_item_path_effects_enabled(lpeitem)) return; // TODO: hack! this will be removed when path length measuring is reimplemented in a better way PathEffectList lpelist = sp_lpe_item_get_effect_list(lpeitem); std::list::iterator i; for (i = lpelist.begin(); i != lpelist.end(); ++i) { Inkscape::LivePathEffect::Effect *lpe = (*i)->lpeobject->lpe; if (dynamic_cast(lpe)) { if (!lpe->isVisible()) { // we manually disable text for LPEPathLength dynamic_cast(lpe)->hideCanvasText(); } } } SPLPEItem *top; if (wholetree) { SPObject *prev_parent = lpeitem; SPObject *parent = prev_parent->parent; while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) { prev_parent = parent; parent = prev_parent->parent; } top = SP_LPE_ITEM(prev_parent); } else { top = lpeitem; } if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) { SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write); } } /** * Gets called when (re)attached to another lpeobject. */ static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem) { if (old_ref) { sp_signal_disconnect_by_data(old_ref, lpeitem); } if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem ) { lpeitem->lpe_modified_connection.disconnect(); lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem)); lpeobject_ref_modified(ref, 0, lpeitem); } } /** * Gets called when lpeobject repr contents change: i.e. parameter change. */ static void lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem) { sp_lpe_item_update_patheffect (lpeitem, true, true); } static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) { if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast(iter->data); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); } } } else if (SP_IS_PATH(lpeitem)) { Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem); if ( !pathrepr->attribute("inkscape:original-d") ) { pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d")); } } } static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) { if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast(iter->data); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); } } } else if (SP_IS_PATH(lpeitem)) { Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem); if (!sp_lpe_item_has_path_effect_recursive(lpeitem) && repr->attribute("inkscape:original-d")) { repr->setAttribute("d", repr->attribute("inkscape:original-d")); repr->setAttribute("inkscape:original-d", NULL); } else { sp_lpe_item_update_patheffect(lpeitem, true, true); } } } void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset) { if (value) { // Apply the path effects here because in the casse of a group, lpe->resetDefaults // needs that all the subitems have their effects applied sp_lpe_item_update_patheffect(lpeitem, false, true); // Disable the path effects while preparing the new lpe sp_lpe_item_enable_path_effects(lpeitem, false); // Add the new reference to the list of LPE references HRefList hreflist; for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it) { hreflist.push_back( std::string((*it)->lpeobject_href) ); } hreflist.push_back( std::string(value) ); std::string hrefs = hreflist_write_svg(hreflist); SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str()); // make sure there is an original-d for paths!!! sp_lpe_item_create_original_path_recursive(lpeitem); LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject; if (lpeobj && lpeobj->lpe) { Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe; // Ask the path effect to reset itself if it doesn't have parameters yet if (reset) { // has to be called when all the subitems have their lpes applied lpe->resetDefaults(lpeitem); } // perform this once when the effect is applied lpe->doOnApply(SP_LPE_ITEM(lpeitem)); // indicate that all necessary preparations are done and the effect can be performed lpe->setReady(); } //Enable the path effects now that everything is ready to apply the new path effect sp_lpe_item_enable_path_effects(lpeitem, true); // Apply the path effect sp_lpe_item_update_patheffect(lpeitem, true, true); } } void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj) { const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id"); gchar *hrefstr = g_strdup_printf("#%s", repr_id); sp_lpe_item_add_path_effect(lpeitem, hrefstr, false); g_free(hrefstr); } void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths) { Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem); if (!lperef) return; PathEffectList new_list = *lpeitem->path_effect_list; new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list std::string r = patheffectlist_write_svg(new_list); SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); if (!keep_paths) { sp_lpe_item_cleanup_original_path_recursive(lpeitem); } } void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths) { SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL); if (!keep_paths) { sp_lpe_item_cleanup_original_path_recursive(lpeitem); } } void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem) { Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem); if (!lperef) return; PathEffectList new_list = *lpeitem->path_effect_list; PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef ); if (cur_it != new_list.end()) { PathEffectList::iterator down_it = cur_it; down_it++; if (down_it != new_list.end()) { // perhaps current effect is already last effect std::iter_swap(cur_it, down_it); } } std::string r = patheffectlist_write_svg(new_list); SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); sp_lpe_item_cleanup_original_path_recursive(lpeitem); } void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem) { Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem); if (!lperef) return; PathEffectList new_list = *lpeitem->path_effect_list; PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef ); if (cur_it != new_list.end() && cur_it != new_list.begin()) { PathEffectList::iterator up_it = cur_it; up_it--; std::iter_swap(cur_it, up_it); } std::string r = patheffectlist_write_svg(new_list); SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); sp_lpe_item_cleanup_original_path_recursive(lpeitem); } bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem) { return !lpeitem->path_effect_list->empty(); } bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem) { SPObject *parent = lpeitem->parent; if (parent && SP_IS_LPE_ITEM(parent)) { return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent)); } else { return sp_lpe_item_has_path_effect(lpeitem); } } Inkscape::LivePathEffect::Effect* sp_lpe_item_has_path_effect_of_type(SPLPEItem *lpeitem, int type) { std::list::iterator i; for (i = lpeitem->path_effect_list->begin(); i != lpeitem->path_effect_list->end(); ++i) { if ((*i)->lpeobject->lpe->effectType() == type) { return (*i)->lpeobject->lpe; } } return NULL; } /* Return false if the item is not a path or already has a shape applied */ bool sp_lpe_item_can_accept_freehand_shape(SPLPEItem *lpeitem) { if (!SP_IS_PATH(lpeitem)) return false; if (sp_lpe_item_has_path_effect_of_type(lpeitem, Inkscape::LivePathEffect::FREEHAND_SHAPE)) return false; return true; } void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt) { Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem); if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) { lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt); } } static void sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref) { if (((SPObjectClass *) (parent_class))->child_added) (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref); if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) { SPObject *ochild = sp_object_get_child_by_repr(object, child); if ( ochild && SP_IS_LPE_ITEM(ochild) ) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild)); } } } static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child) { if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) { SPObject *ochild = sp_object_get_child_by_repr(object, child); if ( ochild && SP_IS_LPE_ITEM(ochild) ) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild)); } } if (((SPObjectClass *) (parent_class))->remove_child) (* ((SPObjectClass *) (parent_class))->remove_child) (object, child); } static std::string patheffectlist_write_svg(PathEffectList const & list) { HRefList hreflist; for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it) { hreflist.push_back( std::string((*it)->lpeobject_href) ); } return hreflist_write_svg(hreflist); } /** * THE function that should be used to generate any patheffectlist string. * one of the methods to change the effect list: * - create temporary href list * - populate the templist with the effects from the old list that you want to have and their order * - call this function with temp list as param */ static std::string hreflist_write_svg(HRefList const & list) { std::string r; bool semicolon_first = false; for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it) { if (semicolon_first) { r += ';'; } semicolon_first = true; r += (*it); } return r; } // Return a copy of the effect list PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem) { return *lpeitem->path_effect_list; } Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem) { if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty()) sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back()); return lpeitem->current_path_effect; } Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem) { Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem); if (lperef && lperef->lpeobject) return lperef->lpeobject->lpe; else return NULL; } bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef) { for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) { if ((*it)->lpeobject_repr == lperef->lpeobject_repr) { lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here? lpeitem->current_path_effect = (*it); // current_path_effect should always be a pointer from the path_effect_list ! return true; } } return false; } void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj, LivePathEffectObject * new_lpeobj) { HRefList hreflist; for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it) { if ((*it)->lpeobject == old_lpeobj) { const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id"); gchar *hrefstr = g_strdup_printf("#%s", repr_id); hreflist.push_back( std::string(hrefstr) ); g_free(hrefstr); } else { hreflist.push_back( std::string((*it)->lpeobject_href) ); } } std::string r = hreflist_write_svg(hreflist); SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); } // Enable or disable the path effects of the item. // The counter allows nested calls static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable) { if (enable) { lpeitem->path_effects_enabled++; } else { lpeitem->path_effects_enabled--; } } // Are the path effects enabled on this item ? bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem) { return lpeitem->path_effects_enabled > 0; } /* 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:encoding=utf-8:textwidth=99 :