Code

Remove working file phoebedom.h from tree.
[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 "macros.h"
27 #include "attributes.h"
28 #include "sp-lpe-item.h"
29 #include "xml/repr.h"
30 #include "uri.h"
32 /* LPEItem base class */
34 static void sp_lpe_item_class_init(SPLPEItemClass *klass);
35 static void sp_lpe_item_init(SPLPEItem *lpe_item);
36 static void sp_lpe_item_finalize(GObject *object);
38 static void sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
39 static void sp_lpe_item_release(SPObject *object);
40 static void sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value);
41 static void sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags);
42 static void sp_lpe_item_modified (SPObject *object, unsigned int flags);
43 static Inkscape::XML::Node *sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
45 static void sp_lpe_item_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
46 static void sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child);
48 static void lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem);
49 static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem);
51 static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem);
52 static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem);
54 static SPItemClass *parent_class;
56 GType
57 sp_lpe_item_get_type()
58 {
59     static GType lpe_item_type = 0;
61     if (!lpe_item_type) {
62         GTypeInfo lpe_item_info = {
63             sizeof(SPLPEItemClass),
64             NULL, NULL,
65             (GClassInitFunc) sp_lpe_item_class_init,
66             NULL, NULL,
67             sizeof(SPLPEItem),
68             16,
69             (GInstanceInitFunc) sp_lpe_item_init,
70             NULL,    /* value_table */
71         };
72         lpe_item_type = g_type_register_static(SP_TYPE_ITEM, "SPLPEItem", &lpe_item_info, (GTypeFlags)0);
73     }
74     return lpe_item_type;
75 }
77 static void
78 sp_lpe_item_class_init(SPLPEItemClass *klass)
79 {    
80     GObjectClass *gobject_class;
81     SPObjectClass *sp_object_class;
83     gobject_class = (GObjectClass *) klass;
84     sp_object_class = (SPObjectClass *) klass;
85     parent_class = (SPItemClass *)g_type_class_peek_parent (klass);
87     gobject_class->finalize = sp_lpe_item_finalize;
89     sp_object_class->build = sp_lpe_item_build;
90     sp_object_class->release = sp_lpe_item_release;
91     sp_object_class->set = sp_lpe_item_set;
92     sp_object_class->update = sp_lpe_item_update;
93     sp_object_class->modified = sp_lpe_item_modified;
94     sp_object_class->write = sp_lpe_item_write;
95     sp_object_class->child_added = sp_lpe_item_child_added;
96     sp_object_class->remove_child = sp_lpe_item_remove_child;
97     
98     klass->update_patheffect = NULL;
99 }
101 static void
102 sp_lpe_item_init(SPLPEItem *lpeitem)
104     lpeitem->path_effect_ref  = new Inkscape::LivePathEffect::LPEObjectReference(SP_OBJECT(lpeitem));
105     new (&lpeitem->lpe_modified_connection) sigc::connection();
108 static void
109 sp_lpe_item_finalize(GObject *object)
111     if (((GObjectClass *) (parent_class))->finalize) {
112         (* ((GObjectClass *) (parent_class))->finalize)(object);
113     }
116 /**
117  * Reads the Inkscape::XML::Node, and initializes SPLPEItem variables.  For this to get called,
118  * our name must be associated with a repr via "sp_object_type_register".  Best done through
119  * sp-object-repr.cpp's repr_name_entries array.
120  */
121 static void
122 sp_lpe_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
124     SP_LPE_ITEM(object)->path_effect_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(lpeobject_ref_changed), SP_LPE_ITEM(object)));
126     sp_object_read_attr(object, "inkscape:path-effect");
127     
128     if (((SPObjectClass *) parent_class)->build) {
129         ((SPObjectClass *) parent_class)->build(object, document, repr);
130     }
133 /**
134  * Drops any allocated memory.
135  */
136 static void
137 sp_lpe_item_release(SPObject *object)
139     SPLPEItem *lpeitem;
140     lpeitem = (SPLPEItem *) object;
142     lpeitem->path_effect_ref->detach();
144     lpeitem->lpe_modified_connection.disconnect();
145     lpeitem->lpe_modified_connection.~connection();
147     if (((SPObjectClass *) parent_class)->release)
148         ((SPObjectClass *) parent_class)->release(object);
151 /**
152  * Sets a specific value in the SPLPEItem.
153  */
154 static void
155 sp_lpe_item_set(SPObject *object, unsigned int key, gchar const *value)
157     SPLPEItem *lpeitem = (SPLPEItem *) object;
159     switch (key) {
160         case SP_ATTR_INKSCAPE_PATH_EFFECT:
161             if ( value && lpeitem->path_effect_ref->lpeobject_href 
162                     && ( strcmp(value, lpeitem->path_effect_ref->lpeobject_href) == 0 ) ) {
163                 /* No change, do nothing. */
164             } else {
165                 if (value) {
166                     // Now do the attaching, which emits the changed signal.
167                     try {
168                         lpeitem->path_effect_ref->link((gchar*)value);
169                     } catch (Inkscape::BadURIException &e) {
170                         g_warning("%s", e.what());
171                         lpeitem->path_effect_ref->detach();
172                     }
173                 } else {
174                     // Detach, which emits the changed signal.
175                     lpeitem->path_effect_ref->detach();
176                 }
177             }
178             break;
179         default:
180             if (((SPObjectClass *) parent_class)->set) {
181                 ((SPObjectClass *) parent_class)->set(object, key, value);
182             }
183             break;
184     }
187 /**
188  * Receives update notifications.
189  */
190 static void
191 sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags)
193     if (((SPObjectClass *) parent_class)->update) {
194         ((SPObjectClass *) parent_class)->update(object, ctx, flags);
195     }
198 /**
199  * Sets modified flag for all sub-item views.
200  */
201 static void
202 sp_lpe_item_modified (SPObject *object, unsigned int flags)
204         if (((SPObjectClass *) (parent_class))->modified) {
205           (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
206         }
209 /**
210  * Writes its settings to an incoming repr object, if any.
211  */
212 static Inkscape::XML::Node *
213 sp_lpe_item_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
215     SPLPEItem *lpeitem = (SPLPEItem *) object;
217     if ( sp_lpe_item_has_path_effect(lpeitem) ) {
218         repr->setAttribute("inkscape:path-effect", lpeitem->path_effect_ref->lpeobject_href);
219     } else {
220         repr->setAttribute("inkscape:path-effect", NULL);
221     }
223     if (((SPObjectClass *)(parent_class))->write) {
224         ((SPObjectClass *)(parent_class))->write(object, repr, flags);
225     }
227     return repr;
231 LivePathEffectObject *
232 sp_lpe_item_get_livepatheffectobject(SPLPEItem *lpeitem) {
233     if (!lpeitem) return NULL;
235     if (sp_lpe_item_has_path_effect(lpeitem)) {
236         return lpeitem->path_effect_ref->lpeobject;
237     } else {
238         return NULL;
239     }
242 Inkscape::LivePathEffect::Effect *
243 sp_lpe_item_get_livepatheffect(SPLPEItem *lpeitem) {
244     if (!lpeitem) return NULL;
246     LivePathEffectObject * lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
247     if (lpeobj)
248         return lpeobj->lpe;
249     else
250         return NULL;
253 void sp_lpe_item_perform_path_effect(SPLPEItem *lpeitem, SPCurve *curve) {
254     if (!lpeitem) return;
255     if (!curve) return;
257     if (sp_lpe_item_has_path_effect(lpeitem)) {
258         LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
259         lpeobj->lpe->doEffect(curve);
260     }
261     
262     SPObject *parent = lpeitem->parent;
263     if (parent && SP_IS_LPE_ITEM(parent))
264         sp_lpe_item_perform_path_effect(SP_LPE_ITEM(parent), curve);
267 /**
268  * Calls any registered handlers for the update_patheffect action
269  */
270 void
271 sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool write)
273 #ifdef SHAPE_VERBOSE
274     g_message("sp_lpe_item_update_patheffect: %p\n", lpeitem);
275 #endif
276     g_return_if_fail (lpeitem != NULL);
277     g_return_if_fail (SP_IS_LPE_ITEM (lpeitem));
279     if (sp_lpe_item_has_path_effect(lpeitem)) {
280         LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
281         lpeobj->lpe->doBeforeEffect(lpeitem);
282     }
284     if (SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (lpeitem))->update_patheffect) {
285         SP_LPE_ITEM_CLASS (G_OBJECT_GET_CLASS (lpeitem))->update_patheffect (lpeitem, write);
286     }
289 /**
290  * Gets called when (re)attached to another lpeobject.
291  */
292 static void
293 lpeobject_ref_changed(SPObject *old_ref, SPObject *ref, SPLPEItem *lpeitem)
295     if (old_ref) {
296         sp_signal_disconnect_by_data(old_ref, lpeitem);
297     }
298     if ( IS_LIVEPATHEFFECT(ref) && ref != lpeitem )
299     {
300         lpeitem->lpe_modified_connection.disconnect();
301         lpeitem->lpe_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&lpeobject_ref_modified), lpeitem));
302         lpeobject_ref_modified(ref, 0, lpeitem);
303     }
306 /**
307  * Gets called when lpeobject repr contents change: i.e. parameter change.
308  */
309 static void
310 lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem)
312     sp_lpe_item_update_patheffect (lpeitem, true);
315 static void
316 sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
318     if (SP_IS_GROUP(lpeitem)) {
319         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
320         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
321             SPObject *subitem = static_cast<SPObject *>(iter->data);
322             if (SP_IS_LPE_ITEM(subitem)) {
323                 sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
324             }
325         }
326     }
327     else if (SP_IS_PATH(lpeitem)) {
328         Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem);
329         if ( !pathrepr->attribute("inkscape:original-d") ) {
330             pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));
331         }
332     }
335 static void
336 sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
338     if (SP_IS_GROUP(lpeitem)) {
339         GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
340         for ( GSList const *iter = item_list; iter; iter = iter->next ) {
341             SPObject *subitem = static_cast<SPObject *>(iter->data);
342             if (SP_IS_LPE_ITEM(subitem)) {
343                 sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
344             }
345         }
346     }
347     else if (SP_IS_PATH(lpeitem)) {
348         Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
349         if (!sp_lpe_item_has_path_effect_recursive(lpeitem) 
350                 && repr->attribute("inkscape:original-d")) {
351             repr->setAttribute("d", repr->attribute("inkscape:original-d"));
352             repr->setAttribute("inkscape:original-d", NULL);
353         }
354         else {
355             sp_lpe_item_update_patheffect(lpeitem, true);
356         }
357     }
360 void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, gchar *value)
362     if (!value) {
363         sp_lpe_item_remove_path_effect(lpeitem, false);
364     } else {
365         SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", value);
366         
367         // make sure there is an original-d for paths!!!
368         sp_lpe_item_create_original_path_recursive(lpeitem);
369     }
372 void sp_lpe_item_set_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj)
374     const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id");
375     gchar *hrefstr = g_strdup_printf("#%s", repr_id);
376     sp_lpe_item_set_path_effect(lpeitem, hrefstr);
377     g_free(hrefstr);
380 void sp_lpe_item_remove_path_effect(SPLPEItem *lpeitem, bool keep_paths)
382     Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem);
383     repr->setAttribute("inkscape:path-effect", NULL);
384     
385     if (!keep_paths) {
386         sp_lpe_item_cleanup_original_path_recursive(lpeitem);
387     }
390 bool sp_lpe_item_has_path_effect(SPLPEItem *lpeitem)
392     return lpeitem->path_effect_ref && lpeitem->path_effect_ref->lpeobject;
395 bool sp_lpe_item_has_path_effect_recursive(SPLPEItem *lpeitem)
397     SPObject *parent = lpeitem->parent;
398     if (parent && SP_IS_LPE_ITEM(parent)) {
399         return sp_lpe_item_has_path_effect(lpeitem) || sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(parent));
400     }
401     else {
402         return sp_lpe_item_has_path_effect(lpeitem);
403     }
406 void sp_lpe_item_edit_next_param_oncanvas(SPLPEItem *lpeitem, SPDesktop *dt)
408     LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(lpeitem);
409     if (lpeobj && lpeobj->lpe) {
410         lpeobj->lpe->editNextParamOncanvas(SP_ITEM(lpeitem), dt);
411     }
414 static void
415 sp_lpe_item_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
417     if (((SPObjectClass *) (parent_class))->child_added)
418         (* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
419         
420     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
421         SPObject *ochild = sp_object_get_child_by_repr(object, child);
422         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
423             sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(ochild));
424         }
425     }
428 static void
429 sp_lpe_item_remove_child (SPObject * object, Inkscape::XML::Node * child)
431     if (SP_IS_LPE_ITEM(object) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(object))) {
432         SPObject *ochild = sp_object_get_child_by_repr(object, child);
433         if ( ochild && SP_IS_LPE_ITEM(ochild) ) {
434             sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild));
435         }
436     }
438     if (((SPObjectClass *) (parent_class))->remove_child)
439         (* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
442 /*
443   Local Variables:
444   mode:c++
445   c-file-style:"stroustrup"
446   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
447   indent-tabs-mode:nil
448   fill-column:99
449   End:
450 */
451 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :