diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index a27344ebca69fd14c2672741ba90d8830c2d3b14..afd36d2ddef30cf1a68293cd86112984c86cf416 100644 (file)
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
-#define __SP_LPE_ITEM_CPP__
-
/** \file
* Base class for live path effect items
*/
/** \file
* Base class for live path effect items
*/
* Authors:
* Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
* Bastien Bouclet <bgkweb@gmail.com>
* Authors:
* Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
* Bastien Bouclet <bgkweb@gmail.com>
+ * Abhishek Sharma
*
* Copyright (C) 2008 authors
*
*
* Copyright (C) 2008 authors
*
#include "message-stack.h"
#include "inkscape.h"
#include "desktop.h"
#include "message-stack.h"
#include "inkscape.h"
#include "desktop.h"
-#include "node-context.h"
#include "shape-editor.h"
#include <algorithm>
#include "shape-editor.h"
#include <algorithm>
static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable);
-static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
lpeitem->path_effect_list = new PathEffectList();
lpeitem->current_path_effect = NULL;
lpeitem->path_effect_list = new PathEffectList();
lpeitem->current_path_effect = NULL;
- new (&lpeitem->lpe_modified_connection) sigc::connection();
+ lpeitem->lpe_modified_connection_list = new std::list<sigc::connection>();
}
static void
}
static void
static void
sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
{
static void
sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
{
- sp_object_read_attr(object, "inkscape:path-effect");
+ object->readAttr( "inkscape:path-effect" );
if (((SPObjectClass *) parent_class)->build) {
((SPObjectClass *) parent_class)->build(object, document, repr);
if (((SPObjectClass *) parent_class)->build) {
((SPObjectClass *) parent_class)->build(object, document, repr);
{
SPLPEItem *lpeitem = (SPLPEItem *) object;
{
SPLPEItem *lpeitem = (SPLPEItem *) object;
- lpeitem->lpe_modified_connection.disconnect();
- lpeitem->lpe_modified_connection.~connection();
+ // disconnect all modified listeners:
+ for (std::list<sigc::connection>::iterator mod_it = lpeitem->lpe_modified_connection_list->begin();
+ mod_it != lpeitem->lpe_modified_connection_list->end(); ++mod_it)
+ {
+ mod_it->disconnect();
+ }
+ delete lpeitem->lpe_modified_connection_list;
+ lpeitem->lpe_modified_connection_list = NULL;
PathEffectList::iterator it = lpeitem->path_effect_list->begin();
while ( it != lpeitem->path_effect_list->end() ) {
PathEffectList::iterator it = lpeitem->path_effect_list->begin();
while ( it != lpeitem->path_effect_list->end() ) {
it = lpeitem->path_effect_list->erase(it);
}
// delete the list itself
it = lpeitem->path_effect_list->erase(it);
}
// delete the list itself
- delete SP_LPE_ITEM(object)->path_effect_list;
+ delete lpeitem->path_effect_list;
+ lpeitem->path_effect_list = NULL;
if (((SPObjectClass *) parent_class)->release)
((SPObjectClass *) parent_class)->release(object);
if (((SPObjectClass *) parent_class)->release)
((SPObjectClass *) parent_class)->release(object);
// Disable the path effects while populating the LPE list
sp_lpe_item_enable_path_effects(lpeitem, false);
// Disable the path effects while populating the LPE list
sp_lpe_item_enable_path_effects(lpeitem, false);
+ // disconnect all modified listeners:
+ for ( std::list<sigc::connection>::iterator mod_it = lpeitem->lpe_modified_connection_list->begin();
+ mod_it != lpeitem->lpe_modified_connection_list->end();
+ ++mod_it)
+ {
+ mod_it->disconnect();
+ }
+ lpeitem->lpe_modified_connection_list->clear();
// Clear the path effect list
PathEffectList::iterator it = lpeitem->path_effect_list->begin();
while ( it != lpeitem->path_effect_list->end() )
// Clear the path effect list
PathEffectList::iterator it = lpeitem->path_effect_list->begin();
while ( it != lpeitem->path_effect_list->end() )
std::string href;
while (std::getline(iss, href, ';'))
{
std::string href;
while (std::getline(iss, href, ';'))
{
- Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
- path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
- // Now do the attaching, which emits the changed signal.
- // Fixme, it should not do this changed signal and updating before all effects are added to the path_effect_list
+ Inkscape::LivePathEffect::LPEObjectReference *path_effect_ref = new Inkscape::LivePathEffect::LPEObjectReference(object);
try {
path_effect_ref->link(href.c_str());
} catch (Inkscape::BadURIException e) {
try {
path_effect_ref->link(href.c_str());
} catch (Inkscape::BadURIException e) {
}
lpeitem->path_effect_list->push_back(path_effect_ref);
}
lpeitem->path_effect_list->push_back(path_effect_ref);
- if ( !(path_effect_ref->lpeobject && path_effect_ref->lpeobject->get_lpe()) ) {
+ if ( path_effect_ref->lpeobject && path_effect_ref->lpeobject->get_lpe() ) {
+ // connect modified-listener
+ lpeitem->lpe_modified_connection_list->push_back(
+ path_effect_ref->lpeobject->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem)) );
+ } else {
// something has gone wrong in finding the right patheffect.
g_warning("Unknown LPE type specified, LPE stack effectively disabled");
// keep the effect in the lpestack, so the whole stack is effectively disabled but maintained
// something has gone wrong in finding the right patheffect.
g_warning("Unknown LPE type specified, LPE stack effectively disabled");
// keep the effect in the lpestack, so the whole stack is effectively disabled but maintained
}
// update the helperpaths of all LPEs applied to the item
}
// update the helperpaths of all LPEs applied to the item
- // TODO: is there a more canonical place for this, since we don't have instant access to the item's nodepath?
- // FIXME: this is called multiple (at least 3) times; how can we avoid this?
-
- // FIXME: ditch inkscape_active_event_context()
- SPEventContext *ec = inkscape_active_event_context();
- if (!SP_IS_NODE_CONTEXT(ec)) return;
- ShapeEditor *sh = ec->shape_editor;
- g_assert(sh);
- if (!sh->has_nodepath()) return;
-
- Inkscape::NodePath::Path *np = sh->get_nodepath();
- sp_nodepath_update_helperpaths(np);
+ // TODO: re-add for the new node tool
}
/**
}
/**
@@ -283,11 +285,13 @@ sp_lpe_item_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::
{
SPLPEItem *lpeitem = (SPLPEItem *) object;
{
SPLPEItem *lpeitem = (SPLPEItem *) object;
- if ( sp_lpe_item_has_path_effect(lpeitem) ) {
- std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
- repr->setAttribute("inkscape:path-effect", href.c_str());
- } else {
- repr->setAttribute("inkscape:path-effect", NULL);
+ if (flags & SP_OBJECT_WRITE_EXT) {
+ if ( sp_lpe_item_has_path_effect(lpeitem) ) {
+ std::string href = patheffectlist_write_svg(*lpeitem->path_effect_list);
+ repr->setAttribute("inkscape:path-effect", href.c_str());
+ } else {
+ repr->setAttribute("inkscape:path-effect", NULL);
+ }
}
if (((SPObjectClass *)(parent_class))->write) {
}
if (((SPObjectClass *)(parent_class))->write) {
if (dynamic_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)) {
if (!lpe->isVisible()) {
// we manually disable text for LPEPathLength
if (dynamic_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)) {
if (!lpe->isVisible()) {
// we manually disable text for LPEPathLength
- dynamic_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)->hideCanvasText();
+ // use static_cast, because we already checked for the right type above
+ static_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)->hideCanvasText();
}
}
}
}
}
}
@@ -405,28 +410,14 @@ sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
}
/**
}
/**
- * Gets called when (re)attached to another lpeobject.
- */
-static void
-lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
-{
- if (old_ref) {
- sp_signal_disconnect_by_data(old_ref, lpeitem);
- }
- if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
- {
- lpeitem->lpe_modified_connection.disconnect();
- lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
- lpeobject_ref_modified(ref, 0, lpeitem);
- }
-}
-
-/**
- * Gets called when lpeobject repr contents change: i.e. parameter change.
+ * Gets called when any of the lpestack's lpeobject repr contents change: i.e. parameter change in any of the stacked LPEs
*/
static void
lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
{
*/
static void
lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
{
+#ifdef SHAPE_VERBOSE
+ g_message("lpeobject_ref_modified");
+#endif
sp_lpe_item_update_patheffect (lpeitem, true, true);
}
sp_lpe_item_update_patheffect (lpeitem, true, true);
}
@@ -541,7 +532,11 @@ void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths)
new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
std::string r = patheffectlist_write_svg(new_list);
new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
std::string r = patheffectlist_write_svg(new_list);
- SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+ if (!r.empty()) {
+ SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+ } else {
+ SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL);
+ }
if (!keep_paths) {
sp_lpe_item_cleanup_original_path_recursive(lpeitem);
if (!keep_paths) {
sp_lpe_item_cleanup_original_path_recursive(lpeitem);
@@ -685,7 +680,7 @@ sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape:
(* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
(* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
- SPObject *ochild = sp_object_get_child_by_repr(object, child);
+ SPObject *ochild = object->get_child_by_repr(child);
if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
}
if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
}
sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
{
if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
{
if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
- SPObject *ochild = sp_object_get_child_by_repr(object, child);
+ SPObject *ochild = object->get_child_by_repr(child);
if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
}
if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
}
Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
{
Inkscape::LivePathEffect::LPEObjectReference* sp_lpe_item_get_current_lpereference(SPLPEItem *lpeitem)
{
- if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty())
+ if (!lpeitem->current_path_effect && !lpeitem->path_effect_list->empty()) {
sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
sp_lpe_item_set_current_path_effect(lpeitem, lpeitem->path_effect_list->back());
+ }
return lpeitem->current_path_effect;
}
return lpeitem->current_path_effect;
}
@@ -767,7 +763,6 @@ bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathE
{
for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
{
for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); it++) {
if ((*it)->lpeobject_repr == lperef->lpeobject_repr) {
- lpeobject_ref_changed(NULL, (*it)->lpeobject, SP_LPE_ITEM(lpeitem)); // FIXME: explain why this is here?
lpeitem->current_path_effect = (*it); // current_path_effect should always be a pointer from the path_effect_list !
return true;
}
lpeitem->current_path_effect = (*it); // current_path_effect should always be a pointer from the path_effect_list !
return true;
}
@@ -776,14 +771,21 @@ bool sp_lpe_item_set_current_path_effect(SPLPEItem *lpeitem, Inkscape::LivePathE
return false;
}
return false;
}
-void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * old_lpeobj,
- LivePathEffectObject * new_lpeobj)
+/**
+ * Writes a new "inkscape:path-effect" string to xml, where the old_lpeobjects are substituted by the new ones.
+ * Note that this method messes up the item's \c PathEffectList.
+ */
+void SPLPEItem::replacePathEffects( std::vector<LivePathEffectObject const *> const old_lpeobjs,
+ std::vector<LivePathEffectObject const *> const new_lpeobjs )
{
HRefList hreflist;
{
HRefList hreflist;
- for (PathEffectList::const_iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
+ for (PathEffectList::const_iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it)
{
{
- if ((*it)->lpeobject == old_lpeobj) {
- const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
+ LivePathEffectObject const * current_lpeobj = (*it)->lpeobject;
+ std::vector<LivePathEffectObject const *>::const_iterator found_it(std::find(old_lpeobjs.begin(), old_lpeobjs.end(), current_lpeobj));
+ if ( found_it != old_lpeobjs.end() ) {
+ std::vector<LivePathEffectObject const *>::difference_type found_index = std::distance (old_lpeobjs.begin(), found_it);
+ const gchar * repr_id = SP_OBJECT_REPR(new_lpeobjs[found_index])->attribute("id");
gchar *hrefstr = g_strdup_printf("#%s", repr_id);
hreflist.push_back( std::string(hrefstr) );
g_free(hrefstr);
gchar *hrefstr = g_strdup_printf("#%s", repr_id);
hreflist.push_back( std::string(hrefstr) );
g_free(hrefstr);
@@ -793,7 +795,49 @@ void sp_lpe_item_replace_path_effect(SPLPEItem *lpeitem, LivePathEffectObject *
}
}
std::string r = hreflist_write_svg(hreflist);
}
}
std::string r = hreflist_write_svg(hreflist);
- SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str());
+ SP_OBJECT_REPR(this)->setAttribute("inkscape:path-effect", r.c_str());
+}
+
+/**
+ * Check all effects in the stack if they are used by other items, and fork them if so.
+ * It is not recommended to fork the effects by yourself calling LivePathEffectObject::fork_private_if_necessary,
+ * use this method instead.
+ * Returns true if one or more effects were forked; returns false if nothing was done.
+ */
+bool sp_lpe_item_fork_path_effects_if_necessary(SPLPEItem *lpeitem, unsigned int nr_of_allowed_users)
+{
+ bool forked = false;
+
+ if ( sp_lpe_item_has_path_effect(lpeitem) ) {
+ // If one of the path effects is used by 2 or more items, fork it
+ // so that each object has its own independent copy of the effect.
+ // Note: replacing path effects messes up the path effect list
+
+ // Clones of the LPEItem will increase the refcount of the lpeobjects.
+ // Therefore, nr_of_allowed_users should be increased with the number of clones (i.e. refs to the lpeitem)
+ nr_of_allowed_users += SP_OBJECT(lpeitem)->hrefcount;
+
+ std::vector<LivePathEffectObject const *> old_lpeobjs, new_lpeobjs;
+ PathEffectList effect_list = sp_lpe_item_get_effect_list(lpeitem);
+ for (PathEffectList::iterator it = effect_list.begin(); it != effect_list.end(); it++)
+ {
+ LivePathEffectObject *lpeobj = (*it)->lpeobject;
+ if (lpeobj) {
+ LivePathEffectObject *forked_lpeobj = lpeobj->fork_private_if_necessary(nr_of_allowed_users);
+ if (forked_lpeobj != lpeobj) {
+ forked = true;
+ old_lpeobjs.push_back(lpeobj);
+ new_lpeobjs.push_back(forked_lpeobj);
+ }
+ }
+ }
+
+ if (forked) {
+ lpeitem->replacePathEffects(old_lpeobjs, new_lpeobjs);
+ }
+ }
+
+ return forked;
}
// Enable or disable the path effects of the item.
}
// Enable or disable the path effects of the item.
fill-column:99
End:
*/
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :