Code

LPE STACKING!
[inkscape.git] / src / sp-lpe-item.cpp
1 #define __SP_LPE_ITEM_CPP__
3 /** \file
4  * Base class for live path effect items
5  */
6 /*
7  * Authors:
8  *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
9  *   Bastien Bouclet <bgkweb@gmail.com>
10  *
11  * Copyright (C) 2008 authors
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #include "live_effects/effect.h"
21 #include "live_effects/lpeobject.h"
22 #include "live_effects/lpeobject-reference.h"
24 #include "sp-path.h"
25 #include "sp-item-group.h"
26 #include "streq.h"
27 #include "macros.h"
28 #include "attributes.h"
29 #include "sp-lpe-item.h"
30 #include "xml/repr.h"
31 #include "uri.h"
33 #include <algorithm>
35 /* LPEItem base class */
37 static void sp_lpe_item_class_init(SPLPEItemClass *klass);
38 static void sp_lpe_item_init(SPLPEItem *lpe_item);
39 static void sp_lpe_item_finalize(GObject *object);
41 static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
42 static void sp_lpe_item_release(SPObject *object);
43 static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value);
44 static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags);
45 static void sp_lpe_item_modified (SPObject *object, unsigned int flags);
46 static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
48 static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
49 static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child);
51 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
53 static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
54 static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
56 static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
57 static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem);
58 typedef std::list<std::string> HRefList;
59 static std::string patheffectlist_write_svg(PathEffectList const & list);
60 static std::string hreflist_write_svg(HRefList const & list);
62 static SPItemClass *parent_class;
64 GType
65 sp_lpe_item_get_type()
66 {
67     static GType lpe_item_type = 0;
69     if (!lpe_item_type) {
70         GTypeInfo lpe_item_info = {
71             sizeof(SPLPEItemClass),
72             NULL, NULL,
73             (GClassInitFunc) sp_lpe_item_class_init,
74             NULL, NULL,
75             sizeof(SPLPEItem),
76             16,
77             (GInstanceInitFunc) sp_lpe_item_init,
78             NULL,    /* value_table */
79         };
80         lpe_item_type = g_type_register_static(SP_TYPE_ITEM, "SPLPEItem", &lpe_item_info, (GTypeFlags)0);
81     }
82     return lpe_item_type;
83 }
85 static void
86 sp_lpe_item_class_init(SPLPEItemClass *klass)
87 {
88     GObjectClass *gobject_class;
89     SPObjectClass *sp_object_class;
91     gobject_class = (GObjectClass *) klass;
92     sp_object_class = (SPObjectClass *) klass;
93     parent_class = (SPItemClass *)g_type_class_peek_parent (klass);
95     gobject_class->finalize = sp_lpe_item_finalize;
97     sp_object_class->build = sp_lpe_item_build;
98     sp_object_class->release = sp_lpe_item_release;
99     sp_object_class->set = sp_lpe_item_set;
100     sp_object_class->update = sp_lpe_item_update;
101     sp_object_class->modified = sp_lpe_item_modified;
102     sp_object_class->write = sp_lpe_item_write;
103     sp_object_class->child_added = sp_lpe_item_child_added;
104     sp_object_class->remove_child = sp_lpe_item_remove_child;
106     klass->update_patheffect = NULL;
109 static void
110 sp_lpe_item_init(SPLPEItem *lpeitem)
112     lpeitem->path_effects_enabled = 1;
114     lpeitem->path_effect_list = new PathEffectList();
115     lpeitem->current_path_effect = NULL;
117     new (&lpeitem->lpe_modified_connection) sigc::connection();
120 static void
121 sp_lpe_item_finalize(GObject *object)
123     if (((GObjectClass *) (parent_class))->finalize) {
124         (* ((GObjectClass *) (parent_class))->finalize)(object);
125     }
127     delete SP_LPE_ITEM(object)->path_effect_list;
130 /**
131  * Reads the Inkscape::XML::Node, and initializes SPLPEItem variables.  For this to get called,
132  * our name must be associated with a repr via "sp_object_type_register".  Best done through
133  * sp-object-repr.cpp's repr_name_entries array.
134  */
135 static void
136 sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
138     sp_object_read_attr(object, "inkscape:path-effect");
140     if (((SPObjectClass *) parent_class)->build) {
141         ((SPObjectClass *) parent_class)->build(object, document, repr);
142     }
145 /**
146  * Drops any allocated memory.
147  */
148 static void
149 sp_lpe_item_release(SPObject *object)
151     SPLPEItem *lpeitem;
152     lpeitem = (SPLPEItem *) object;
154     lpeitem->lpe_modified_connection.disconnect();
155     lpeitem->lpe_modified_connection.~connection();
157     if (((SPObjectClass *) parent_class)->release)
158         ((SPObjectClass *) parent_class)->release(object);
161 /**
162  * Sets a specific value in the SPLPEItem.
163  */
164 static void
165 sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value)
167     SPLPEItem *lpeitem = (SPLPEItem *) object;
169     switch (key) {
170         case SP_ATTR_INKSCAPE_PATH_EFFECT:
171             {
172                 lpeitem->current_path_effect = NULL;
174                 // Disable the path effects while populating the LPE list
175                  sp_lpe_item_enable_path_effects(lpeitem, false);
177                 // Clear the path effect list
178                 PathEffectList::iterator it = lpeitem->path_effect_list->begin();
179                 while ( it != lpeitem->path_effect_list->end() )
180                 {
181                     (*it)->unlink();
182                     delete *it;
183                     it = lpeitem->path_effect_list->erase(it);
184                 }
186                 // Parse the contents of "value" to rebuild the path effect reference list
187                 if ( value ) {
188                     std::istringstream iss(value);
189                     std::string href;
190                     while (std::getline(iss, href, ';'))
191                     {
192                         Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref;
193                         path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
194                         path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
195                         // Now do the attaching, which emits the changed signal.
196                         // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list
197                         try {
198                             path_effect_ref->link(href.c_str());
199                         } catch (Inkscape::BadURIException &e) {
200                             g_warning("BadURIException: %s", e.what());
201                             path_effect_ref->unlink();
202                             delete path_effect_ref;
203                             path_effect_ref = NULL;
204                         }
206                         if (path_effect_ref) {
207                             lpeitem->path_effect_list->push_back(path_effect_ref);
208                         }
209                     }
210                 }
212                 sp_lpe_item_enable_path_effects(lpeitem, true);
213             }
214             break;
215         default:
216             if (((SPObjectClass *) parent_class)->set) {
217                 ((SPObjectClass *) parent_class)->set(object, key, value);
218             }
219             break;
220     }
223 /**
224  * Receives update notifications.
225  */
226 static void
227 sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
229     if (((SPObjectClass *) parent_class)->update) {
230         ((SPObjectClass *) parent_class)->update(object, ctx, flags);
231     }
234 /**
235  * Sets modified flag for all sub-item views.
236  */
237 static void
238 sp_lpe_item_modified (SPObject *object, unsigned int flags)
241     if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) {
242         sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true);
243     }
245     if (((SPObjectClass *) (parent_class))->modified) {
246         (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
247     }
250 /**
251  * Writes its settings to an incoming repr object, if any.
252  */
253 static Inkscape::XML::Node *
254 sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
256     SPLPEItem *lpeitem = (SPLPEItem *) object;
258     if ( sp_lpe_item_has_path_effect(lpeitem) ) {
259         std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
260         repr->setAttribute("inkscape:path-effect", href.c_str());
261     } else {
262         repr->setAttribute("inkscape:path-effect", NULL);
263     }
265     if (((SPObjectClass *)(parent_class))->write) {
266         ((SPObjectClass *)(parent_class))->write(object, repr, flags);
267     }
269     return repr;
272 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) {
273     if (!lpeitem) return;
274     if (!curve) return;
276     if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) {
277         for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
278         {
279             LivePathEffectObject *lpeobj = (*it)->lpeobject;
281             if (lpeobj->lpe->isVisible()) {
282                 // Groups have their doBeforeEffect called elsewhere
283                 if (!SP_IS_GROUP(lpeitem)) {
284                     lpeobj->lpe->doBeforeEffect(lpeitem);
285                 }
287                 lpeobj->lpe->doEffect(curve);
288             }
289         }
290     }
293 /**
294  * Calls any registered handlers for the update_patheffect action
295  */
296 void
297 sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
299 #ifdef SHAPE_VERBOSE
300     g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
301 #endif
302     g_return_if_fail (lpeitem != NULL);
303     g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
305     SPLPEItem *top;
307     if (wholetree) {
308         SPObject *prev_parent = lpeitem;
309         SPObject *parent = prev_parent->parent;
310         while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) {
311             prev_parent = parent;
312             parent = prev_parent->parent;
313         }
314         top = SP_LPE_ITEM(prev_parent);
315     }
316     else {
317         top = lpeitem;
318     }
320     if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) {
321         SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write);
322     }
325 /**
326  * Gets called when (re)attached to another lpeobject.
327  */
328 static void
329 lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
331     if (old_ref) {
332         sp_signal_disconnect_by_data(old_ref, lpeitem);
333     }
334     if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
335     {
336         lpeitem->lpe_modified_connection.disconnect();
337         lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
338         lpeobject_ref_modified(ref, 0, lpeitem);
339     }
342 /**
343  * Gets called when lpeobject repr contents change: i.e. parameter change.
344  */
345 static void
346 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
348     sp_lpe_item_update_patheffect (lpeitem, true, true);
351 static void
352 sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
354     if (SP_IS_GROUP(lpeitem)) {
355         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
356         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
357             SPObject *subitem = static_cast<SPObject *>(iter->data);
358             if (SP_IS_LPE_ITEM(subitem)) {
359                 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
360             }
361         }
362     }
363     else if (SP_IS_PATH(lpeitem)) {
364         Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem);
365         if ( !pathrepr->attribute("inkscape:original-d") ) {
366             pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));
367         }
368     }
371 static void
372 sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
374     if (SP_IS_GROUP(lpeitem)) {
375         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
376         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
377             SPObject *subitem = static_cast<SPObject *>(iter->data);
378             if (SP_IS_LPE_ITEM(subitem)) {
379                 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
380             }
381         }
382     }
383     else if (SP_IS_PATH(lpeitem)) {
384         Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
385         if (!sp_lpe_item_has_path_effect_recursive(lpeitem)
386                 && repr->attribute("inkscape:original-d")) {
387             repr->setAttribute("d", repr->attribute("inkscape:original-d"));
388             repr->setAttribute("inkscape:original-d", NULL);
389         }
390         else {
391             sp_lpe_item_update_patheffect(lpeitem, true, true);
392         }
393     }
396 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
398     if (value) {
399         // Apply the path effects here because in the casse of a group, lpe->resetDefaults
400         // needs that all the subitems have their effects applied
401         sp_lpe_item_update_patheffect(lpeitem, false, true);
403         // Disable the path effects while preparing the new lpe
404         sp_lpe_item_enable_path_effects(lpeitem, false);
406         // Add the new reference to the list of LPE references
407         HRefList hreflist;
408         for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
409         {
410             hreflist.push_back( std::string((*it)->lpeobject_href) );
411         }
412         hreflist.push_back( std::string(value) );
413         std::string hrefs = hreflist_write_svg(hreflist);
415         SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str());
417         // make sure there is an original-d for paths!!!
418         sp_lpe_item_create_original_path_recursive(lpeitem);
420         LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject;
421         if (lpeobj && lpeobj->lpe) {
422             // Ask the path effect to reset itself if it doesn't have parameters yet
423             if (reset) {
424                 // has to be called when all the subitems have their lpes applied
425                 lpeobj->lpe->resetDefaults(lpeitem);
426             }
427         }
429         //Enable the path effects now that everything is ready to apply the new path effect
430         sp_lpe_item_enable_path_effects(lpeitem, true);
432         // Apply the path effect
433         sp_lpe_item_update_patheffect(lpeitem, true, true);
434     }
437 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
439     const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
440     gchar *hrefstr = g_strdup_printf("#%s", repr_id);
441     sp_lpe_item_add_path_effect(lpeitem, hrefstr, false);
442     g_free(hrefstr);
445 void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
447     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
448     if (!lperef)
449         return;
451     PathEffectList new_list = *lpeitem->path_effect_list;
452     new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
453     std::string r = patheffectlist_write_svg(new_list);
455     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
457     if (!keep_paths) {
458         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
459     }
462 void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths)
464     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
466     if (!keep_paths) {
467         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
468     }
471 void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem)
473     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
474     if (!lperef)
475         return;
477     PathEffectList new_list = *lpeitem->path_effect_list;
478     PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
479     if (cur_it != new_list.end()) {
480         PathEffectList::iterator down_it = cur_it;
481         down_it++;
482         if (down_it != new_list.end()) { // perhaps current effect is already last effect
483             std::iter_swap(cur_it, down_it);
484         }
485     }
486     std::string r = patheffectlist_write_svg(new_list);
487     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
489     sp_lpe_item_cleanup_original_path_recursive(lpeitem);
492 void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem)
494     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
495     if (!lperef)
496         return;
498     PathEffectList new_list = *lpeitem->path_effect_list;
499     PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
500     if (cur_it != new_list.end() && cur_it != new_list.begin()) {
501         PathEffectList::iterator up_it = cur_it;
502         up_it--;
503         std::iter_swap(cur_it, up_it);
504     }
505     std::string r = patheffectlist_write_svg(new_list);
507     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
509     sp_lpe_item_cleanup_original_path_recursive(lpeitem);
513 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
515     return !lpeitem->path_effect_list->empty();
518 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
520     SPObject *parent = lpeitem->parent;
521     if (parent && SP_IS_LPE_ITEM(parent)) {
522         return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent));
523     }
524     else {
525         return sp_lpe_item_has_path_effect(lpeitem);
526     }
529 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
531     Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem);
532     if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) {
533         lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
534     }
537 static void
538 sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
540     if (((SPObjectClass *) (parent_class))->child_added)
541         (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
543     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
544         SPObject *ochild = sp_object_get_child_by_repr(object, child);
545         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
546             sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
547         }
548     }
551 static void
552 sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
554     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
555         SPObject *ochild = sp_object_get_child_by_repr(object, child);
556         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
557             sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
558         }
559     }
561     if (((SPObjectClass *) (parent_class))->remove_child)
562         (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
565 static std::string patheffectlist_write_svg(PathEffectList const & list)
567     HRefList hreflist;
568     for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it)
569     {
570         hreflist.push_back( std::string((*it)->lpeobject_href) );
571     }
572     return hreflist_write_svg(hreflist);
575 /**
576  *  THE function that should be used to generate any patheffectlist string.
577  * one of the methods to change the effect list:
578  *  - create temporary href list
579  *  - populate the templist with the effects from the old list that you want to have and their order
580  *  - call this function with temp list as param
581  */
582 static std::string hreflist_write_svg(HRefList const & list)
584     std::string r;
585     bool semicolon_first = false;
586     for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it)
587     {
588         if (semicolon_first) {
589             r += ';';
590         }
591         semicolon_first = true;
593         r += (*it);
594     }
595     return r;
598 // Return a copy of the effect list
599 PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem)
601     return *lpeitem->path_effect_list;
604 Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
606     if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
607         sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
609     return lpeitem->current_path_effect;
612 Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem)
614     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
616     if (lperef && lperef->lpeobject)
617         return lperef->lpeobject->lpe;
618     else
619         return NULL;
622 bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef)
624     for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
625         if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
626             lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
627             lpeitem->current_path_effect = (*it);  // current_path_effect should always be a pointer from the path_effect_list !
628             return true;
629         }
630     }
632     return false;
635 void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
636                                         LivePathEffectObject * new_lpeobj)
638     HRefList hreflist;
639     for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
640     {
641         if ((*it)->lpeobject == old_lpeobj) {
642             const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
643             gchar *hrefstr = g_strdup_printf("#%s", repr_id);
644             hreflist.push_back( std::string(hrefstr) );
645             g_free(hrefstr);
646         }
647         else {
648             hreflist.push_back( std::string((*it)->lpeobject_href) );
649         }
650     }
651     std::string r = hreflist_write_svg(hreflist);
652     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
655 // Enable or disable the path effects of the item.
656 // The counter allows nested calls
657 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
659     if (enable) {
660         lpeitem->path_effects_enabled++;
661     }
662     else {
663         lpeitem->path_effects_enabled--;
664     }
667 // Are the path effects enabled on this item ?
668 bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
670     return lpeitem->path_effects_enabled > 0;
673 /*
674   Local Variables:
675   mode:c++
676   c-file-style:"stroustrup"
677   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
678   indent-tabs-mode:nil
679   fill-column:99
680   End:
681 */
682 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :