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"
36 #include <algorithm>
38 /* LPEItem base class */
40 static void sp_lpe_item_class_init(SPLPEItemClass *klass);
41 static void sp_lpe_item_init(SPLPEItem *lpe_item);
42 static void sp_lpe_item_finalize(GObject *object);
44 static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
45 static void sp_lpe_item_release(SPObject *object);
46 static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value);
47 static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags);
48 static void sp_lpe_item_modified (SPObject *object, unsigned int flags);
49 static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags);
51 static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
52 static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child);
54 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
56 static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
57 static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
59 static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
60 static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem);
61 typedef std::list<std::string> HRefList;
62 static std::string patheffectlist_write_svg(PathEffectList const & list);
63 static std::string hreflist_write_svg(HRefList const & list);
65 static SPItemClass *parent_class;
67 GType
68 sp_lpe_item_get_type()
69 {
70 static GType lpe_item_type = 0;
72 if (!lpe_item_type) {
73 GTypeInfo lpe_item_info = {
74 sizeof(SPLPEItemClass),
75 NULL, NULL,
76 (GClassInitFunc) sp_lpe_item_class_init,
77 NULL, NULL,
78 sizeof(SPLPEItem),
79 16,
80 (GInstanceInitFunc) sp_lpe_item_init,
81 NULL, /* value_table */
82 };
83 lpe_item_type = g_type_register_static(SP_TYPE_ITEM, "SPLPEItem", &lpe_item_info, (GTypeFlags)0);
84 }
85 return lpe_item_type;
86 }
88 static void
89 sp_lpe_item_class_init(SPLPEItemClass *klass)
90 {
91 GObjectClass *gobject_class;
92 SPObjectClass *sp_object_class;
94 gobject_class = (GObjectClass *) klass;
95 sp_object_class = (SPObjectClass *) klass;
96 parent_class = (SPItemClass *)g_type_class_peek_parent (klass);
98 gobject_class->finalize = sp_lpe_item_finalize;
100 sp_object_class->build = sp_lpe_item_build;
101 sp_object_class->release = sp_lpe_item_release;
102 sp_object_class->set = sp_lpe_item_set;
103 sp_object_class->update = sp_lpe_item_update;
104 sp_object_class->modified = sp_lpe_item_modified;
105 sp_object_class->write = sp_lpe_item_write;
106 sp_object_class->child_added = sp_lpe_item_child_added;
107 sp_object_class->remove_child = sp_lpe_item_remove_child;
109 klass->update_patheffect = NULL;
110 }
112 static void
113 sp_lpe_item_init(SPLPEItem *lpeitem)
114 {
115 lpeitem->path_effects_enabled = 1;
117 lpeitem->path_effect_list = new PathEffectList();
118 lpeitem->current_path_effect = NULL;
120 new (&lpeitem->lpe_modified_connection) sigc::connection();
121 }
123 static void
124 sp_lpe_item_finalize(GObject *object)
125 {
126 if (((GObjectClass *) (parent_class))->finalize) {
127 (* ((GObjectClass *) (parent_class))->finalize)(object);
128 }
130 delete SP_LPE_ITEM(object)->path_effect_list;
131 }
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)
140 {
141 sp_object_read_attr(object, "inkscape:path-effect");
143 if (((SPObjectClass *) parent_class)->build) {
144 ((SPObjectClass *) parent_class)->build(object, document, repr);
145 }
146 }
148 /**
149 * Drops any allocated memory.
150 */
151 static void
152 sp_lpe_item_release(SPObject *object)
153 {
154 SPLPEItem *lpeitem;
155 lpeitem = (SPLPEItem *) object;
157 lpeitem->lpe_modified_connection.disconnect();
158 lpeitem->lpe_modified_connection.~connection();
160 if (((SPObjectClass *) parent_class)->release)
161 ((SPObjectClass *) parent_class)->release(object);
162 }
164 /**
165 * Sets a specific value in the SPLPEItem.
166 */
167 static void
168 sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value)
169 {
170 SPLPEItem *lpeitem = (SPLPEItem *) object;
172 switch (key) {
173 case SP_ATTR_INKSCAPE_PATH_EFFECT:
174 {
175 lpeitem->current_path_effect = NULL;
177 // Disable the path effects while populating the LPE list
178 sp_lpe_item_enable_path_effects(lpeitem, false);
180 // Clear the path effect list
181 PathEffectList::iterator it = lpeitem->path_effect_list->begin();
182 while ( it != lpeitem->path_effect_list->end() )
183 {
184 (*it)->unlink();
185 delete *it;
186 it = lpeitem->path_effect_list->erase(it);
187 }
189 // Parse the contents of "value" to rebuild the path effect reference list
190 if ( value ) {
191 std::istringstream iss(value);
192 std::string href;
193 while (std::getline(iss, href, ';'))
194 {
195 Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref;
196 path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
197 path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
198 // Now do the attaching, which emits the changed signal.
199 // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list
200 try {
201 path_effect_ref->link(href.c_str());
202 } catch (Inkscape::BadURIException &e) {
203 g_warning("BadURIException: %s", e.what());
204 path_effect_ref->unlink();
205 delete path_effect_ref;
206 path_effect_ref = NULL;
207 }
209 if (path_effect_ref) {
210 lpeitem->path_effect_list->push_back(path_effect_ref);
211 }
212 }
213 }
215 sp_lpe_item_enable_path_effects(lpeitem, true);
216 }
217 break;
218 default:
219 if (((SPObjectClass *) parent_class)->set) {
220 ((SPObjectClass *) parent_class)->set(object, key, value);
221 }
222 break;
223 }
224 }
226 /**
227 * Receives update notifications.
228 */
229 static void
230 sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
231 {
232 if (((SPObjectClass *) parent_class)->update) {
233 ((SPObjectClass *) parent_class)->update(object, ctx, flags);
234 }
235 }
237 /**
238 * Sets modified flag for all sub-item views.
239 */
240 static void
241 sp_lpe_item_modified (SPObject *object, unsigned int flags)
242 {
244 if (SP_IS_GROUP(object) && (flags & SP_OBJECT_MODIFIED_FLAG) && (flags & SP_OBJECT_USER_MODIFIED_FLAG_B)) {
245 sp_lpe_item_update_patheffect(SP_LPE_ITEM(object), true, true);
246 }
248 if (((SPObjectClass *) (parent_class))->modified) {
249 (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
250 }
251 }
253 /**
254 * Writes its settings to an incoming repr object, if any.
255 */
256 static Inkscape::XML::Node *
257 sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
258 {
259 SPLPEItem *lpeitem = (SPLPEItem *) object;
261 if ( sp_lpe_item_has_path_effect(lpeitem) ) {
262 std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
263 repr->setAttribute("inkscape:path-effect", href.c_str());
264 } else {
265 repr->setAttribute("inkscape:path-effect", NULL);
266 }
268 if (((SPObjectClass *)(parent_class))->write) {
269 ((SPObjectClass *)(parent_class))->write(object, xml_doc, repr, flags);
270 }
272 return repr;
273 }
275 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) {
276 if (!lpeitem) return;
277 if (!curve) return;
279 if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) {
280 for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
281 {
282 LivePathEffectObject *lpeobj = (*it)->lpeobject;
283 if (!lpeobj) {
284 g_warning("sp_lpe_item_perform_path_effect - NULL lpeobj in list!");
285 return;
286 }
287 if (!lpeobj->lpe) {
288 g_warning("sp_lpe_item_perform_path_effect - lpeobj without lpe!");
289 return;
290 }
292 Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe;
293 if (lpe->isVisible()) {
294 if (lpe->acceptsNumParams() > 0 && !lpe->pathParamAccepted()) {
295 // if the effect expects mouse input before being applied and the input is not finished
296 // yet, we don't alter the path
297 return;
298 }
300 // Groups have their doBeforeEffect called elsewhere
301 if (!SP_IS_GROUP(lpeitem)) {
302 lpe->doBeforeEffect(lpeitem);
303 }
305 try {
306 lpe->doEffect(curve);
307 }
308 catch (std::exception & e) {
309 g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what());
310 SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
311 _("An exception occurred during execution of the Path Effect.") );
312 }
313 }
314 }
315 }
316 }
318 /**
319 * Calls any registered handlers for the update_patheffect action
320 */
321 void
322 sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
323 {
324 #ifdef SHAPE_VERBOSE
325 g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
326 #endif
327 g_return_if_fail (lpeitem != NULL);
328 g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
330 if (!sp_lpe_item_path_effects_enabled(lpeitem))
331 return;
333 SPLPEItem *top;
335 if (wholetree) {
336 SPObject *prev_parent = lpeitem;
337 SPObject *parent = prev_parent->parent;
338 while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) {
339 prev_parent = parent;
340 parent = prev_parent->parent;
341 }
342 top = SP_LPE_ITEM(prev_parent);
343 }
344 else {
345 top = lpeitem;
346 }
348 if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) {
349 SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write);
350 }
351 }
353 /**
354 * Gets called when (re)attached to another lpeobject.
355 */
356 static void
357 lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
358 {
359 if (old_ref) {
360 sp_signal_disconnect_by_data(old_ref, lpeitem);
361 }
362 if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
363 {
364 lpeitem->lpe_modified_connection.disconnect();
365 lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
366 lpeobject_ref_modified(ref, 0, lpeitem);
367 }
368 }
370 /**
371 * Gets called when lpeobject repr contents change: i.e. parameter change.
372 */
373 static void
374 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
375 {
376 sp_lpe_item_update_patheffect (lpeitem, true, true);
377 }
379 static void
380 sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
381 {
382 if (SP_IS_GROUP(lpeitem)) {
383 GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
384 for ( GSList const *iter = item_list; iter; iter = iter->next ) {
385 SPObject *subitem = static_cast<SPObject *>(iter->data);
386 if (SP_IS_LPE_ITEM(subitem)) {
387 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
388 }
389 }
390 }
391 else if (SP_IS_PATH(lpeitem)) {
392 Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem);
393 if ( !pathrepr->attribute("inkscape:original-d") ) {
394 pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));
395 }
396 }
397 }
399 static void
400 sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
401 {
402 if (SP_IS_GROUP(lpeitem)) {
403 GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
404 for ( GSList const *iter = item_list; iter; iter = iter->next ) {
405 SPObject *subitem = static_cast<SPObject *>(iter->data);
406 if (SP_IS_LPE_ITEM(subitem)) {
407 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
408 }
409 }
410 }
411 else if (SP_IS_PATH(lpeitem)) {
412 Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
413 if (!sp_lpe_item_has_path_effect_recursive(lpeitem)
414 && repr->attribute("inkscape:original-d")) {
415 repr->setAttribute("d", repr->attribute("inkscape:original-d"));
416 repr->setAttribute("inkscape:original-d", NULL);
417 }
418 else {
419 sp_lpe_item_update_patheffect(lpeitem, true, true);
420 }
421 }
422 }
424 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
425 {
426 if (value) {
427 // Apply the path effects here because in the casse of a group, lpe->resetDefaults
428 // needs that all the subitems have their effects applied
429 sp_lpe_item_update_patheffect(lpeitem, false, true);
431 // Disable the path effects while preparing the new lpe
432 sp_lpe_item_enable_path_effects(lpeitem, false);
434 // Add the new reference to the list of LPE references
435 HRefList hreflist;
436 for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
437 {
438 hreflist.push_back( std::string((*it)->lpeobject_href) );
439 }
440 hreflist.push_back( std::string(value) );
441 std::string hrefs = hreflist_write_svg(hreflist);
443 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str());
445 // make sure there is an original-d for paths!!!
446 sp_lpe_item_create_original_path_recursive(lpeitem);
448 LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject;
449 if (lpeobj && lpeobj->lpe) {
450 Inkscape::LivePathEffect::Effect *lpe = lpeobj->lpe;
451 // Ask the path effect to reset itself if it doesn't have parameters yet
452 if (reset) {
453 // has to be called when all the subitems have their lpes applied
454 lpe->resetDefaults(lpeitem);
455 }
457 // perform this once when the effect is applied
458 lpe->doOnApply(SP_LPE_ITEM(lpeitem));
460 // if the effect expects a number of mouse clicks to set a parameter path, perform the
461 // necessary preparations
462 if (lpe->acceptsNumParams() > 0) {
463 lpe->doAcceptPathPreparations(lpeitem);
464 }
465 }
467 //Enable the path effects now that everything is ready to apply the new path effect
468 sp_lpe_item_enable_path_effects(lpeitem, true);
470 // Apply the path effect
471 sp_lpe_item_update_patheffect(lpeitem, true, true);
472 }
473 }
475 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
476 {
477 const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
478 gchar *hrefstr = g_strdup_printf("#%s", repr_id);
479 sp_lpe_item_add_path_effect(lpeitem, hrefstr, false);
480 g_free(hrefstr);
481 }
483 void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
484 {
485 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
486 if (!lperef)
487 return;
489 PathEffectList new_list = *lpeitem->path_effect_list;
490 new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
491 std::string r = patheffectlist_write_svg(new_list);
493 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
495 if (!keep_paths) {
496 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
497 }
498 }
500 void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths)
501 {
502 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
504 if (!keep_paths) {
505 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
506 }
507 }
509 void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem)
510 {
511 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
512 if (!lperef)
513 return;
515 PathEffectList new_list = *lpeitem->path_effect_list;
516 PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
517 if (cur_it != new_list.end()) {
518 PathEffectList::iterator down_it = cur_it;
519 down_it++;
520 if (down_it != new_list.end()) { // perhaps current effect is already last effect
521 std::iter_swap(cur_it, down_it);
522 }
523 }
524 std::string r = patheffectlist_write_svg(new_list);
525 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
527 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
528 }
530 void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem)
531 {
532 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
533 if (!lperef)
534 return;
536 PathEffectList new_list = *lpeitem->path_effect_list;
537 PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
538 if (cur_it != new_list.end() && cur_it != new_list.begin()) {
539 PathEffectList::iterator up_it = cur_it;
540 up_it--;
541 std::iter_swap(cur_it, up_it);
542 }
543 std::string r = patheffectlist_write_svg(new_list);
545 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
547 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
548 }
551 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
552 {
553 return !lpeitem->path_effect_list->empty();
554 }
556 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
557 {
558 SPObject *parent = lpeitem->parent;
559 if (parent && SP_IS_LPE_ITEM(parent)) {
560 return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent));
561 }
562 else {
563 return sp_lpe_item_has_path_effect(lpeitem);
564 }
565 }
567 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
568 {
569 Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem);
570 if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) {
571 lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
572 }
573 }
575 static void
576 sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
577 {
578 if (((SPObjectClass *) (parent_class))->child_added)
579 (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
581 if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
582 SPObject *ochild = sp_object_get_child_by_repr(object, child);
583 if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
584 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
585 }
586 }
587 }
589 static void
590 sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
591 {
592 if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
593 SPObject *ochild = sp_object_get_child_by_repr(object, child);
594 if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
595 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
596 }
597 }
599 if (((SPObjectClass *) (parent_class))->remove_child)
600 (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
601 }
603 static std::string patheffectlist_write_svg(PathEffectList const & list)
604 {
605 HRefList hreflist;
606 for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it)
607 {
608 hreflist.push_back( std::string((*it)->lpeobject_href) );
609 }
610 return hreflist_write_svg(hreflist);
611 }
613 /**
614 * THE function that should be used to generate any patheffectlist string.
615 * one of the methods to change the effect list:
616 * - create temporary href list
617 * - populate the templist with the effects from the old list that you want to have and their order
618 * - call this function with temp list as param
619 */
620 static std::string hreflist_write_svg(HRefList const & list)
621 {
622 std::string r;
623 bool semicolon_first = false;
624 for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it)
625 {
626 if (semicolon_first) {
627 r += ';';
628 }
629 semicolon_first = true;
631 r += (*it);
632 }
633 return r;
634 }
636 // Return a copy of the effect list
637 PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem)
638 {
639 return *lpeitem->path_effect_list;
640 }
642 Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
643 {
644 if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
645 sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
647 return lpeitem->current_path_effect;
648 }
650 Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem)
651 {
652 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
654 if (lperef && lperef->lpeobject)
655 return lperef->lpeobject->lpe;
656 else
657 return NULL;
658 }
660 bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef)
661 {
662 for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
663 if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
664 lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
665 lpeitem->current_path_effect = (*it); // current_path_effect should always be a pointer from the path_effect_list !
666 return true;
667 }
668 }
670 return false;
671 }
673 void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
674 LivePathEffectObject * new_lpeobj)
675 {
676 HRefList hreflist;
677 for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
678 {
679 if ((*it)->lpeobject == old_lpeobj) {
680 const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
681 gchar *hrefstr = g_strdup_printf("#%s", repr_id);
682 hreflist.push_back( std::string(hrefstr) );
683 g_free(hrefstr);
684 }
685 else {
686 hreflist.push_back( std::string((*it)->lpeobject_href) );
687 }
688 }
689 std::string r = hreflist_write_svg(hreflist);
690 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
691 }
693 // Enable or disable the path effects of the item.
694 // The counter allows nested calls
695 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
696 {
697 if (enable) {
698 lpeitem->path_effects_enabled++;
699 }
700 else {
701 lpeitem->path_effects_enabled--;
702 }
703 }
705 // Are the path effects enabled on this item ?
706 bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
707 {
708 return lpeitem->path_effects_enabled > 0;
709 }
711 /*
712 Local Variables:
713 mode:c++
714 c-file-style:"stroustrup"
715 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
716 indent-tabs-mode:nil
717 fill-column:99
718 End:
719 */
720 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :