Code

Remove now obsolete functions
[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"
32 #include "message-stack.h"
33 #include "inkscape.h"
34 #include "desktop.h"
35 #include "node-context.h"
36 #include "shape-editor.h"
38 #include <algorithm>
40 /* LPEItem base class */
42 static void sp_lpe_item_class_init(SPLPEItemClass *klass);
43 static void sp_lpe_item_init(SPLPEItem *lpe_item);
44 static void sp_lpe_item_finalize(GObject *object);
46 static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
47 static void sp_lpe_item_release(SPObject *object);
48 static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value);
49 static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags);
50 static void sp_lpe_item_modified (SPObject *object, unsigned int flags);
51 static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags);
53 static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
54 static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child);
56 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
58 static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
59 static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
61 static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
62 static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem);
63 typedef std::list<std::string> HRefList;
64 static std::string patheffectlist_write_svg(PathEffectList const & list);
65 static std::string hreflist_write_svg(HRefList const & list);
67 static SPItemClass *parent_class;
69 GType
70 sp_lpe_item_get_type()
71 {
72     static GType lpe_item_type = 0;
74     if (!lpe_item_type) {
75         GTypeInfo lpe_item_info = {
76             sizeof(SPLPEItemClass),
77             NULL, NULL,
78             (GClassInitFunc) sp_lpe_item_class_init,
79             NULL, NULL,
80             sizeof(SPLPEItem),
81             16,
82             (GInstanceInitFunc) sp_lpe_item_init,
83             NULL,    /* value_table */
84         };
85         lpe_item_type = g_type_register_static(SP_TYPE_ITEM, "SPLPEItem", &lpe_item_info, (GTypeFlags)0);
86     }
87     return lpe_item_type;
88 }
90 static void
91 sp_lpe_item_class_init(SPLPEItemClass *klass)
92 {
93     GObjectClass *gobject_class;
94     SPObjectClass *sp_object_class;
96     gobject_class = (GObjectClass *) klass;
97     sp_object_class = (SPObjectClass *) klass;
98     parent_class = (SPItemClass *)g_type_class_peek_parent (klass);
100     gobject_class->finalize = sp_lpe_item_finalize;
102     sp_object_class->build = sp_lpe_item_build;
103     sp_object_class->release = sp_lpe_item_release;
104     sp_object_class->set = sp_lpe_item_set;
105     sp_object_class->update = sp_lpe_item_update;
106     sp_object_class->modified = sp_lpe_item_modified;
107     sp_object_class->write = sp_lpe_item_write;
108     sp_object_class->child_added = sp_lpe_item_child_added;
109     sp_object_class->remove_child = sp_lpe_item_remove_child;
111     klass->update_patheffect = NULL;
114 static void
115 sp_lpe_item_init(SPLPEItem *lpeitem)
117     lpeitem->path_effects_enabled = 1;
119     lpeitem->path_effect_list = new PathEffectList();
120     lpeitem->current_path_effect = NULL;
122     new (&lpeitem->lpe_modified_connection) sigc::connection();
125 static void
126 sp_lpe_item_finalize(GObject *object)
128     if (((GObjectClass *) (parent_class))->finalize) {
129         (* ((GObjectClass *) (parent_class))->finalize)(object);
130     }
133 /**
134  * Reads the Inkscape::XML::Node, and initializes SPLPEItem variables.  For this to get called,
135  * our name must be associated with a repr via "sp_object_type_register".  Best done through
136  * sp-object-repr.cpp's repr_name_entries array.
137  */
138 static void
139 sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
141     sp_object_read_attr(object, "inkscape:path-effect");
143     if (((SPObjectClass *) parent_class)->build) {
144         ((SPObjectClass *) parent_class)->build(object, document, repr);
145     }
148 /**
149  * Drops any allocated memory.
150  */
151 static void
152 sp_lpe_item_release(SPObject *object)
154     SPLPEItem *lpeitem = (SPLPEItem *) object;
156     lpeitem->lpe_modified_connection.disconnect();
157     lpeitem->lpe_modified_connection.~connection();
159     PathEffectList::iterator it = lpeitem->path_effect_list->begin();
160     while ( it != lpeitem->path_effect_list->end() ) {
161         // unlink and delete all references in the list
162         (*it)->unlink();
163         delete *it;
164         it = lpeitem->path_effect_list->erase(it);
165     }
166     // delete the list itself
167     delete SP_LPE_ITEM(object)->path_effect_list;
169     if (((SPObjectClass *) parent_class)->release)
170         ((SPObjectClass *) parent_class)->release(object);
173 /**
174  * Sets a specific value in the SPLPEItem.
175  */
176 static void
177 sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value)
179     SPLPEItem *lpeitem = (SPLPEItem *) object;
181     switch (key) {
182         case SP_ATTR_INKSCAPE_PATH_EFFECT:
183             {
184                 lpeitem->current_path_effect = NULL;
186                 // Disable the path effects while populating the LPE list
187                  sp_lpe_item_enable_path_effects(lpeitem, false);
189                 // Clear the path effect list
190                 PathEffectList::iterator it = lpeitem->path_effect_list->begin();
191                 while ( it != lpeitem->path_effect_list->end() )
192                 {
193                     (*it)->unlink();
194                     delete *it;
195                     it = lpeitem->path_effect_list->erase(it);
196                 }
198                 // Parse the contents of "value" to rebuild the path effect reference list
199                 if ( value ) {
200                     std::istringstream iss(value);
201                     std::string href;
202                     while (std::getline(iss, href, ';'))
203                     {
204                         Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref;
205                         path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
206                         path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
207                         // Now do the attaching, which emits the changed signal.
208                         // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list
209                         try {
210                             path_effect_ref->link(href.c_str());
211                         } catch (Inkscape::BadURIException &e) {
212                             g_warning("BadURIException: %s", e.what());
213                             path_effect_ref->unlink();
214                             delete path_effect_ref;
215                             path_effect_ref = NULL;
216                         }
218                         if (path_effect_ref) {
219                             lpeitem->path_effect_list->push_back(path_effect_ref);
220                         }
221                     }
222                 }
224                 sp_lpe_item_enable_path_effects(lpeitem, true);
225             }
226             break;
227         default:
228             if (((SPObjectClass *) parent_class)->set) {
229                 ((SPObjectClass *) parent_class)->set(object, key, value);
230             }
231             break;
232     }
235 /**
236  * Receives update notifications.
237  */
238 static void
239 sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
241     if (((SPObjectClass *) parent_class)->update) {
242         ((SPObjectClass *) parent_class)->update(object, ctx, flags);
243     }
245     g_print ("sp_lpe_item_update()\n");
247     // update the helperpaths of all LPEs applied to the item
248     // TODO: is there a more canonical place for this, since we don't have instant access to the item's nodepath?
249     // FIXME: this is called multiple (at least 3) times; how can we avoid this?
251     // FIXME: ditch inkscape_active_event_context()
252     SPEventContext *ec = inkscape_active_event_context();
253     if (!SP_IS_NODE_CONTEXT(ec)) return;
254     SPNodeContext *nc = SP_NODE_CONTEXT(ec);
255     ShapeEditor *sh = nc->shape_editor;
256     g_assert(sh);
257     if (!sh->has_nodepath()) return;
259     Inkscape::NodePath::Path *np = sh->get_nodepath();
260     sp_nodepath_update_helperpaths(np);
263 /**
264  * Sets modified flag for all sub-item views.
265  */
266 static void
267 sp_lpe_item_modified (SPObject *object, unsigned int flags)
269     g_print ("sp_lpe_item_modified()\n");
271     if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) {
272         sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true);
273     }
275     if (((SPObjectClass *) (parent_class))->modified) {
276         (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
277     }
280 /**
281  * Writes its settings to an incoming repr object, if any.
282  */
283 static Inkscape::XML::Node *
284 sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
286     SPLPEItem *lpeitem = (SPLPEItem *) object;
288     if ( sp_lpe_item_has_path_effect(lpeitem) ) {
289         std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
290         repr->setAttribute("inkscape:path-effect", href.c_str());
291     } else {
292         repr->setAttribute("inkscape:path-effect", NULL);
293     }
295     if (((SPObjectClass *)(parent_class))->write) {
296         ((SPObjectClass *)(parent_class))->write(object, xml_doc, repr, flags);
297     }
299     return repr;
302 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) {
303     if (!lpeitem) return;
304     if (!curve) return;
306     if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) {
307         for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
308         {
309             LivePathEffectObject *lpeobj = (*it)->lpeobject;
310             if (!lpeobj) {
311                 g_warning("sp_lpe_item_perform_path_effect - NULL lpeobj in list!");
312                 return;
313             }
314             if (!lpeobj->lpe) {
315                 g_warning("sp_lpe_item_perform_path_effect - lpeobj without lpe!");
316                 return;
317             }
319             Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe;
320             if (lpe->isVisible()) {
321                 if (lpe->acceptsNumParams() > 0 && !lpe->pathParamAccepted()) {
322                     // if the effect expects mouse input before being applied and the input is not finished
323                     // yet, we don't alter the path
324                     return;
325                 }
327                 // Groups have their doBeforeEffect called elsewhere
328                 if (!SP_IS_GROUP(lpeitem)) {
329                     lpe->doBeforeEffect(lpeitem);
330                 }
332                 try {
333                     lpe->doEffect(curve);
334                 }
335                 catch (std::exception & e) {
336                     g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what());
337                     SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
338                         _("An exception occurred during execution of the Path Effect.") );
339                 }
340             }
341         }
342     }
345 /**
346  * Calls any registered handlers for the update_patheffect action
347  */
348 void
349 sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
351 #ifdef SHAPE_VERBOSE
352     g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
353 #endif
354     g_return_if_fail (lpeitem != NULL);
355     g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
357     if (!sp_lpe_item_path_effects_enabled(lpeitem))
358         return;
360     SPLPEItem *top;
362     if (wholetree) {
363         SPObject *prev_parent = lpeitem;
364         SPObject *parent = prev_parent->parent;
365         while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) {
366             prev_parent = parent;
367             parent = prev_parent->parent;
368         }
369         top = SP_LPE_ITEM(prev_parent);
370     }
371     else {
372         top = lpeitem;
373     }
375     if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) {
376         SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write);
377     }
380 /**
381  * Gets called when (re)attached to another lpeobject.
382  */
383 static void
384 lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
386     if (old_ref) {
387         sp_signal_disconnect_by_data(old_ref, lpeitem);
388     }
389     if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
390     {
391         lpeitem->lpe_modified_connection.disconnect();
392         lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
393         lpeobject_ref_modified(ref, 0, lpeitem);
394     }
397 /**
398  * Gets called when lpeobject repr contents change: i.e. parameter change.
399  */
400 static void
401 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
403     sp_lpe_item_update_patheffect (lpeitem, true, true);
406 static void
407 sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
409     if (SP_IS_GROUP(lpeitem)) {
410         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
411         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
412             SPObject *subitem = static_cast<SPObject *>(iter->data);
413             if (SP_IS_LPE_ITEM(subitem)) {
414                 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
415             }
416         }
417     }
418     else if (SP_IS_PATH(lpeitem)) {
419         Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem);
420         if ( !pathrepr->attribute("inkscape:original-d") ) {
421             pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));
422         }
423     }
426 static void
427 sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
429     if (SP_IS_GROUP(lpeitem)) {
430         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
431         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
432             SPObject *subitem = static_cast<SPObject *>(iter->data);
433             if (SP_IS_LPE_ITEM(subitem)) {
434                 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
435             }
436         }
437     }
438     else if (SP_IS_PATH(lpeitem)) {
439         Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
440         if (!sp_lpe_item_has_path_effect_recursive(lpeitem)
441                 && repr->attribute("inkscape:original-d")) {
442             repr->setAttribute("d", repr->attribute("inkscape:original-d"));
443             repr->setAttribute("inkscape:original-d", NULL);
444         }
445         else {
446             sp_lpe_item_update_patheffect(lpeitem, true, true);
447         }
448     }
451 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
453     if (value) {
454         // Apply the path effects here because in the casse of a group, lpe->resetDefaults
455         // needs that all the subitems have their effects applied
456         sp_lpe_item_update_patheffect(lpeitem, false, true);
458         // Disable the path effects while preparing the new lpe
459         sp_lpe_item_enable_path_effects(lpeitem, false);
461         // Add the new reference to the list of LPE references
462         HRefList hreflist;
463         for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
464         {
465             hreflist.push_back( std::string((*it)->lpeobject_href) );
466         }
467         hreflist.push_back( std::string(value) );
468         std::string hrefs = hreflist_write_svg(hreflist);
470         SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str());
472         // make sure there is an original-d for paths!!!
473         sp_lpe_item_create_original_path_recursive(lpeitem);
475         LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject;
476         if (lpeobj && lpeobj->lpe) {
477             Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe;
478             // Ask the path effect to reset itself if it doesn't have parameters yet
479             if (reset) {
480                 // has to be called when all the subitems have their lpes applied
481                 lpe->resetDefaults(lpeitem);
482             }
484             // perform this once when the effect is applied
485             lpe->doOnApply(SP_LPE_ITEM(lpeitem));
487             // if the effect expects a number of mouse clicks to set a parameter path, perform the
488             // necessary preparations
489             if (lpe->acceptsNumParams() > 0) {
490                 lpe->doAcceptPathPreparations(lpeitem);
491             }
492         }
494         //Enable the path effects now that everything is ready to apply the new path effect
495         sp_lpe_item_enable_path_effects(lpeitem, true);
497         // Apply the path effect
498         sp_lpe_item_update_patheffect(lpeitem, true, true);
499     }
502 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
504     const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
505     gchar *hrefstr = g_strdup_printf("#%s", repr_id);
506     sp_lpe_item_add_path_effect(lpeitem, hrefstr, false);
507     g_free(hrefstr);
510 void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
512     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
513     if (!lperef)
514         return;
516     PathEffectList new_list = *lpeitem->path_effect_list;
517     new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
518     std::string r = patheffectlist_write_svg(new_list);
520     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
522     if (!keep_paths) {
523         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
524     }
527 void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths)
529     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
531     if (!keep_paths) {
532         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
533     }
536 void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem)
538     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
539     if (!lperef)
540         return;
542     PathEffectList new_list = *lpeitem->path_effect_list;
543     PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
544     if (cur_it != new_list.end()) {
545         PathEffectList::iterator down_it = cur_it;
546         down_it++;
547         if (down_it != new_list.end()) { // perhaps current effect is already last effect
548             std::iter_swap(cur_it, down_it);
549         }
550     }
551     std::string r = patheffectlist_write_svg(new_list);
552     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
554     sp_lpe_item_cleanup_original_path_recursive(lpeitem);
557 void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem)
559     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
560     if (!lperef)
561         return;
563     PathEffectList new_list = *lpeitem->path_effect_list;
564     PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
565     if (cur_it != new_list.end() && cur_it != new_list.begin()) {
566         PathEffectList::iterator up_it = cur_it;
567         up_it--;
568         std::iter_swap(cur_it, up_it);
569     }
570     std::string r = patheffectlist_write_svg(new_list);
572     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
574     sp_lpe_item_cleanup_original_path_recursive(lpeitem);
578 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
580     return !lpeitem->path_effect_list->empty();
583 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
585     SPObject *parent = lpeitem->parent;
586     if (parent && SP_IS_LPE_ITEM(parent)) {
587         return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent));
588     }
589     else {
590         return sp_lpe_item_has_path_effect(lpeitem);
591     }
594 Inkscape::LivePathEffect::Effect*
595 sp_lpe_item_has_path_effect_of_type(SPLPEItem *lpeitem, int type)
597     std::list<Inkscape::LivePathEffect::LPEObjectReference *>::iterator i;
598     for (i = lpeitem->path_effect_list->begin(); i != lpeitem->path_effect_list->end(); ++i) {
599         if ((*i)->lpeobject->lpe->effectType() == type) {
600             return (*i)->lpeobject->lpe;
601         }
602     }
603     return NULL;
606 /* Return false if the item is not a path or already has a shape applied */
607 bool sp_lpe_item_can_accept_freehand_shape(SPLPEItem *lpeitem)
609     if (!SP_IS_PATH(lpeitem))
610         return false;
612     if (sp_lpe_item_has_path_effect_of_type(lpeitem, Inkscape::LivePathEffect::FREEHAND_SHAPE))
613         return false;
615     return true;
618 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
620     Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem);
621     if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) {
622         lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
623     }
626 static void
627 sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
629     if (((SPObjectClass *) (parent_class))->child_added)
630         (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
632     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
633         SPObject *ochild = sp_object_get_child_by_repr(object, child);
634         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
635             sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
636         }
637     }
640 static void
641 sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
643     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
644         SPObject *ochild = sp_object_get_child_by_repr(object, child);
645         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
646             sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
647         }
648     }
650     if (((SPObjectClass *) (parent_class))->remove_child)
651         (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
654 static std::string patheffectlist_write_svg(PathEffectList const & list)
656     HRefList hreflist;
657     for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it)
658     {
659         hreflist.push_back( std::string((*it)->lpeobject_href) );
660     }
661     return hreflist_write_svg(hreflist);
664 /**
665  *  THE function that should be used to generate any patheffectlist string.
666  * one of the methods to change the effect list:
667  *  - create temporary href list
668  *  - populate the templist with the effects from the old list that you want to have and their order
669  *  - call this function with temp list as param
670  */
671 static std::string hreflist_write_svg(HRefList const & list)
673     std::string r;
674     bool semicolon_first = false;
675     for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it)
676     {
677         if (semicolon_first) {
678             r += ';';
679         }
680         semicolon_first = true;
682         r += (*it);
683     }
684     return r;
687 // Return a copy of the effect list
688 PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem)
690     return *lpeitem->path_effect_list;
693 Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
695     if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
696         sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
698     return lpeitem->current_path_effect;
701 Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem)
703     Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
705     if (lperef && lperef->lpeobject)
706         return lperef->lpeobject->lpe;
707     else
708         return NULL;
711 bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef)
713     for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
714         if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
715             lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
716             lpeitem->current_path_effect = (*it);  // current_path_effect should always be a pointer from the path_effect_list !
717             return true;
718         }
719     }
721     return false;
724 void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
725                                         LivePathEffectObject * new_lpeobj)
727     HRefList hreflist;
728     for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
729     {
730         if ((*it)->lpeobject == old_lpeobj) {
731             const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
732             gchar *hrefstr = g_strdup_printf("#%s", repr_id);
733             hreflist.push_back( std::string(hrefstr) );
734             g_free(hrefstr);
735         }
736         else {
737             hreflist.push_back( std::string((*it)->lpeobject_href) );
738         }
739     }
740     std::string r = hreflist_write_svg(hreflist);
741     SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
744 // Enable or disable the path effects of the item.
745 // The counter allows nested calls
746 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
748     if (enable) {
749         lpeitem->path_effects_enabled++;
750     }
751     else {
752         lpeitem->path_effects_enabled--;
753     }
756 // Are the path effects enabled on this item ?
757 bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
759     return lpeitem->path_effects_enabled > 0;
762 /*
763   Local Variables:
764   mode:c++
765   c-file-style:"stroustrup"
766   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
767   indent-tabs-mode:nil
768   fill-column:99
769   End:
770 */
771 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :