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::Document *xml_doc, 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;
107 }
109 static void
110 sp_lpe_item_init(SPLPEItem *lpeitem)
111 {
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();
118 }
120 static void
121 sp_lpe_item_finalize(GObject *object)
122 {
123 if (((GObjectClass *) (parent_class))->finalize) {
124 (* ((GObjectClass *) (parent_class))->finalize)(object);
125 }
127 delete SP_LPE_ITEM(object)->path_effect_list;
128 }
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)
137 {
138 sp_object_read_attr(object, "inkscape:path-effect");
140 if (((SPObjectClass *) parent_class)->build) {
141 ((SPObjectClass *) parent_class)->build(object, document, repr);
142 }
143 }
145 /**
146 * Drops any allocated memory.
147 */
148 static void
149 sp_lpe_item_release(SPObject *object)
150 {
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);
159 }
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)
166 {
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 }
221 }
223 /**
224 * Receives update notifications.
225 */
226 static void
227 sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
228 {
229 if (((SPObjectClass *) parent_class)->update) {
230 ((SPObjectClass *) parent_class)->update(object, ctx, flags);
231 }
232 }
234 /**
235 * Sets modified flag for all sub-item views.
236 */
237 static void
238 sp_lpe_item_modified (SPObject *object, unsigned int flags)
239 {
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 }
248 }
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::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
255 {
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, xml_doc, repr, flags);
267 }
269 return repr;
270 }
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;
280 if (!lpeobj) {
281 g_warning("sp_lpe_item_perform_path_effect - NULL lpeobj in list!");
282 return;
283 }
284 if (!lpeobj->lpe) {
285 g_warning("sp_lpe_item_perform_path_effect - lpeobj without lpe!");
286 return;
287 }
289 if (lpeobj->lpe->isVisible()) {
290 // Groups have their doBeforeEffect called elsewhere
291 if (!SP_IS_GROUP(lpeitem)) {
292 lpeobj->lpe->doBeforeEffect(lpeitem);
293 }
295 lpeobj->lpe->doEffect(curve);
296 }
297 }
298 }
299 }
301 /**
302 * Calls any registered handlers for the update_patheffect action
303 */
304 void
305 sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
306 {
307 #ifdef SHAPE_VERBOSE
308 g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
309 #endif
310 g_return_if_fail (lpeitem != NULL);
311 g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
313 if (!sp_lpe_item_path_effects_enabled(lpeitem))
314 return;
316 SPLPEItem *top;
318 if (wholetree) {
319 SPObject *prev_parent = lpeitem;
320 SPObject *parent = prev_parent->parent;
321 while (parent && SP_IS_LPE_ITEM(parent) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent))) {
322 prev_parent = parent;
323 parent = prev_parent->parent;
324 }
325 top = SP_LPE_ITEM(prev_parent);
326 }
327 else {
328 top = lpeitem;
329 }
331 if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect) {
332 SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (top))->update_patheffect (top, write);
333 }
334 }
336 /**
337 * Gets called when (re)attached to another lpeobject.
338 */
339 static void
340 lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
341 {
342 if (old_ref) {
343 sp_signal_disconnect_by_data(old_ref, lpeitem);
344 }
345 if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
346 {
347 lpeitem->lpe_modified_connection.disconnect();
348 lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
349 lpeobject_ref_modified(ref, 0, lpeitem);
350 }
351 }
353 /**
354 * Gets called when lpeobject repr contents change: i.e. parameter change.
355 */
356 static void
357 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
358 {
359 sp_lpe_item_update_patheffect (lpeitem, true, true);
360 }
362 static void
363 sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
364 {
365 if (SP_IS_GROUP(lpeitem)) {
366 GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
367 for ( GSList const *iter = item_list; iter; iter = iter->next ) {
368 SPObject *subitem = static_cast<SPObject *>(iter->data);
369 if (SP_IS_LPE_ITEM(subitem)) {
370 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
371 }
372 }
373 }
374 else if (SP_IS_PATH(lpeitem)) {
375 Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem);
376 if ( !pathrepr->attribute("inkscape:original-d") ) {
377 pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));
378 }
379 }
380 }
382 static void
383 sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
384 {
385 if (SP_IS_GROUP(lpeitem)) {
386 GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
387 for ( GSList const *iter = item_list; iter; iter = iter->next ) {
388 SPObject *subitem = static_cast<SPObject *>(iter->data);
389 if (SP_IS_LPE_ITEM(subitem)) {
390 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
391 }
392 }
393 }
394 else if (SP_IS_PATH(lpeitem)) {
395 Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
396 if (!sp_lpe_item_has_path_effect_recursive(lpeitem)
397 && repr->attribute("inkscape:original-d")) {
398 repr->setAttribute("d", repr->attribute("inkscape:original-d"));
399 repr->setAttribute("inkscape:original-d", NULL);
400 }
401 else {
402 sp_lpe_item_update_patheffect(lpeitem, true, true);
403 }
404 }
405 }
407 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset)
408 {
409 if (value) {
410 // Apply the path effects here because in the casse of a group, lpe->resetDefaults
411 // needs that all the subitems have their effects applied
412 sp_lpe_item_update_patheffect(lpeitem, false, true);
414 // Disable the path effects while preparing the new lpe
415 sp_lpe_item_enable_path_effects(lpeitem, false);
417 // Add the new reference to the list of LPE references
418 HRefList hreflist;
419 for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
420 {
421 hreflist.push_back( std::string((*it)->lpeobject_href) );
422 }
423 hreflist.push_back( std::string(value) );
424 std::string hrefs = hreflist_write_svg(hreflist);
426 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str());
428 // make sure there is an original-d for paths!!!
429 sp_lpe_item_create_original_path_recursive(lpeitem);
431 LivePathEffectObject *lpeobj = lpeitem->path_effect_list->back()->lpeobject;
432 if (lpeobj && lpeobj->lpe) {
433 // Ask the path effect to reset itself if it doesn't have parameters yet
434 if (reset) {
435 // has to be called when all the subitems have their lpes applied
436 lpeobj->lpe->resetDefaults(lpeitem);
437 }
438 /* perform this once when the effect is applied */
439 lpeobj->lpe->doOnApply(SP_LPE_ITEM(lpeitem));
440 }
442 //Enable the path effects now that everything is ready to apply the new path effect
443 sp_lpe_item_enable_path_effects(lpeitem, true);
445 // Apply the path effect
446 sp_lpe_item_update_patheffect(lpeitem, true, true);
447 }
448 }
450 void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
451 {
452 const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
453 gchar *hrefstr = g_strdup_printf("#%s", repr_id);
454 sp_lpe_item_add_path_effect(lpeitem, hrefstr, false);
455 g_free(hrefstr);
456 }
458 void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
459 {
460 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
461 if (!lperef)
462 return;
464 PathEffectList new_list = *lpeitem->path_effect_list;
465 new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
466 std::string r = patheffectlist_write_svg(new_list);
468 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
470 if (!keep_paths) {
471 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
472 }
473 }
475 void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths)
476 {
477 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
479 if (!keep_paths) {
480 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
481 }
482 }
484 void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem)
485 {
486 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
487 if (!lperef)
488 return;
490 PathEffectList new_list = *lpeitem->path_effect_list;
491 PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
492 if (cur_it != new_list.end()) {
493 PathEffectList::iterator down_it = cur_it;
494 down_it++;
495 if (down_it != new_list.end()) { // perhaps current effect is already last effect
496 std::iter_swap(cur_it, down_it);
497 }
498 }
499 std::string r = patheffectlist_write_svg(new_list);
500 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
502 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
503 }
505 void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem)
506 {
507 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
508 if (!lperef)
509 return;
511 PathEffectList new_list = *lpeitem->path_effect_list;
512 PathEffectList::iterator cur_it = find( new_list.begin(), new_list.end(), lperef );
513 if (cur_it != new_list.end() && cur_it != new_list.begin()) {
514 PathEffectList::iterator up_it = cur_it;
515 up_it--;
516 std::iter_swap(cur_it, up_it);
517 }
518 std::string r = patheffectlist_write_svg(new_list);
520 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
522 sp_lpe_item_cleanup_original_path_recursive(lpeitem);
523 }
526 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
527 {
528 return !lpeitem->path_effect_list->empty();
529 }
531 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
532 {
533 SPObject *parent = lpeitem->parent;
534 if (parent && SP_IS_LPE_ITEM(parent)) {
535 return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent));
536 }
537 else {
538 return sp_lpe_item_has_path_effect(lpeitem);
539 }
540 }
542 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
543 {
544 Inkscape::LivePathEffect::LPEObjectReference *lperef = sp_lpe_item_get_current_lpereference(lpeitem);
545 if (lperef && lperef->lpeobject && lperef->lpeobject->lpe) {
546 lperef->lpeobject->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
547 }
548 }
550 static void
551 sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
552 {
553 if (((SPObjectClass *) (parent_class))->child_added)
554 (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
556 if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
557 SPObject *ochild = sp_object_get_child_by_repr(object, child);
558 if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
559 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
560 }
561 }
562 }
564 static void
565 sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
566 {
567 if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
568 SPObject *ochild = sp_object_get_child_by_repr(object, child);
569 if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
570 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
571 }
572 }
574 if (((SPObjectClass *) (parent_class))->remove_child)
575 (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
576 }
578 static std::string patheffectlist_write_svg(PathEffectList const & list)
579 {
580 HRefList hreflist;
581 for (PathEffectList::const_iterator it = list.begin(); it != list.end(); ++it)
582 {
583 hreflist.push_back( std::string((*it)->lpeobject_href) );
584 }
585 return hreflist_write_svg(hreflist);
586 }
588 /**
589 * THE function that should be used to generate any patheffectlist string.
590 * one of the methods to change the effect list:
591 * - create temporary href list
592 * - populate the templist with the effects from the old list that you want to have and their order
593 * - call this function with temp list as param
594 */
595 static std::string hreflist_write_svg(HRefList const & list)
596 {
597 std::string r;
598 bool semicolon_first = false;
599 for (HRefList::const_iterator it = list.begin(); it != list.end(); ++it)
600 {
601 if (semicolon_first) {
602 r += ';';
603 }
604 semicolon_first = true;
606 r += (*it);
607 }
608 return r;
609 }
611 // Return a copy of the effect list
612 PathEffectList sp_lpe_item_get_effect_list(SPLPEItem *lpeitem)
613 {
614 return *lpeitem->path_effect_list;
615 }
617 Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
618 {
619 if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
620 sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
622 return lpeitem->current_path_effect;
623 }
625 Inkscape::LivePathEffect::Effect* sp_lpe_item_get_current_lpe(SPLPEItem *lpeitem)
626 {
627 Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem);
629 if (lperef && lperef->lpeobject)
630 return lperef->lpeobject->lpe;
631 else
632 return NULL;
633 }
635 bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathEffect::LPEObjectReference* lperef)
636 {
637 for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
638 if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
639 lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
640 lpeitem->current_path_effect = (*it); // current_path_effect should always be a pointer from the path_effect_list !
641 return true;
642 }
643 }
645 return false;
646 }
648 void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
649 LivePathEffectObject * new_lpeobj)
650 {
651 HRefList hreflist;
652 for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
653 {
654 if ((*it)->lpeobject == old_lpeobj) {
655 const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
656 gchar *hrefstr = g_strdup_printf("#%s", repr_id);
657 hreflist.push_back( std::string(hrefstr) );
658 g_free(hrefstr);
659 }
660 else {
661 hreflist.push_back( std::string((*it)->lpeobject_href) );
662 }
663 }
664 std::string r = hreflist_write_svg(hreflist);
665 SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
666 }
668 // Enable or disable the path effects of the item.
669 // The counter allows nested calls
670 static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
671 {
672 if (enable) {
673 lpeitem->path_effects_enabled++;
674 }
675 else {
676 lpeitem->path_effects_enabled--;
677 }
678 }
680 // Are the path effects enabled on this item ?
681 bool sp_lpe_item_path_effects_enabled(SPLPEItem *lpeitem)
682 {
683 return lpeitem->path_effects_enabled > 0;
684 }
686 /*
687 Local Variables:
688 mode:c++
689 c-file-style:"stroustrup"
690 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
691 indent-tabs-mode:nil
692 fill-column:99
693 End:
694 */
695 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :