Code

Support for title and desc elements when serializing as Plain SVG.
[inkscape.git] / src / sp-flowregion.cpp
1 #define __SP_FLOWREGION_C__
3 /*
4  */
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9 #include <glibmm/i18n.h>
11 #include <xml/repr.h>
12 #include "display/curve.h"
13 #include "sp-shape.h"
14 #include "sp-text.h"
15 #include "sp-use.h"
16 #include "style.h"
17 #include "document.h"
18 #include "sp-title.h"
19 #include "sp-desc.h"
21 #include "sp-flowregion.h"
23 #include "display/canvas-bpath.h"
26 #include "livarot/Path.h"
27 #include "livarot/Shape.h"
29 static void sp_flowregion_class_init (SPFlowregionClass *klass);
30 static void sp_flowregion_init (SPFlowregion *group);
31 static void sp_flowregion_dispose (GObject *object);
33 static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
34 static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child);
35 static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags);
36 static void sp_flowregion_modified (SPObject *object, guint flags);
37 static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
39 static gchar * sp_flowregion_description (SPItem * item);
41 static SPItemClass * flowregion_parent_class;
43 static void sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass);
44 static void sp_flowregionexclude_init (SPFlowregionExclude *group);
45 static void sp_flowregionexclude_dispose (GObject *object);
47 static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
48 static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child);
49 static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags);
50 static void sp_flowregionexclude_modified (SPObject *object, guint flags);
51 static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
53 static gchar * sp_flowregionexclude_description (SPItem * item);
55 static SPItemClass * flowregionexclude_parent_class;
58 static void         GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat);
60 GType
61 sp_flowregion_get_type (void)
62 {
63         static GType group_type = 0;
64         if (!group_type) {
65                 GTypeInfo group_info = {
66                         sizeof (SPFlowregionClass),
67                         NULL,   /* base_init */
68                         NULL,   /* base_finalize */
69                         (GClassInitFunc) sp_flowregion_class_init,
70                         NULL,   /* class_finalize */
71                         NULL,   /* class_data */
72                         sizeof (SPFlowregion),
73                         16,     /* n_preallocs */
74                         (GInstanceInitFunc) sp_flowregion_init,
75                         NULL,   /* value_table */
76                 };
77                 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregion", &group_info, (GTypeFlags)0);
78         }
79         return group_type;
80 }
82 static void
83 sp_flowregion_class_init (SPFlowregionClass *klass)
84 {
85         GObjectClass * object_class;
86         SPObjectClass * sp_object_class;
87         SPItemClass * item_class;
89         object_class = (GObjectClass *) klass;
90         sp_object_class = (SPObjectClass *) klass;
91         item_class = (SPItemClass *) klass;
93         flowregion_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
95         object_class->dispose = sp_flowregion_dispose;
97         sp_object_class->child_added = sp_flowregion_child_added;
98         sp_object_class->remove_child = sp_flowregion_remove_child;
99         sp_object_class->update = sp_flowregion_update;
100         sp_object_class->modified = sp_flowregion_modified;
101         sp_object_class->write = sp_flowregion_write;
103         item_class->description = sp_flowregion_description;
106 static void
107 sp_flowregion_init (SPFlowregion *group)
109         new (&group->computed) std::vector<Shape*>;
112 static void
113 sp_flowregion_dispose(GObject *object)
115         SPFlowregion *group=(SPFlowregion *)object;
116     for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; it++)
117         delete *it;
118     group->computed.~vector<Shape*>();
121 static void
122 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
124         SPItem *item;
126         item = SP_ITEM (object);
128         if (((SPObjectClass *) (flowregion_parent_class))->child_added)
129                 (* ((SPObjectClass *) (flowregion_parent_class))->child_added) (object, child, ref);
131         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
134 /* fixme: hide (Lauris) */
136 static void
137 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
139         if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
140                 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
142         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
146 static void
147 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
149         SPFlowregion *group;
150         SPObject *child;
151         SPItemCtx *ictx, cctx;
152         GSList *l;
154         group = SP_FLOWREGION (object);
155         ictx = (SPItemCtx *) ctx;
156         cctx = *ictx;
158         if (((SPObjectClass *) (flowregion_parent_class))->update)
159                 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
161         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
162         flags &= SP_OBJECT_MODIFIED_CASCADE;
164         l = NULL;
165         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
166                 g_object_ref (G_OBJECT (child));
167                 l = g_slist_prepend (l, child);
168         }
169         l = g_slist_reverse (l);
170         while (l) {
171                 child = SP_OBJECT (l->data);
172                 l = g_slist_remove (l, child);
173                 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
174                         if (SP_IS_ITEM (child)) {
175                                 SPItem const &chi = *SP_ITEM(child);
176                                 cctx.i2doc = chi.transform * ictx->i2doc;
177                                 cctx.i2vp = chi.transform * ictx->i2vp;
178                                 child->updateDisplay((SPCtx *)&cctx, flags);
179                         } else {
180                                 child->updateDisplay(ctx, flags);
181                         }
182                 }
183                 g_object_unref (G_OBJECT (child));
184         }
186         group->UpdateComputed();
189 void             SPFlowregion::UpdateComputed(void)
191         SPObject* object=SP_OBJECT(this);
193     NR::Matrix itr_mat (sp_item_i2root_affine (SP_ITEM(object)));
194     itr_mat = itr_mat.inverse();
196     for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++)
197         delete *it;
198     computed.clear();
200         for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
201         Shape *shape = NULL;
202                 GetDest(child,&shape,itr_mat);
203         computed.push_back(shape);
204         }
207 static void
208 sp_flowregion_modified (SPObject *object, guint flags)
210         SPFlowregion *group;
211         SPObject *child;
212         GSList *l;
214         group = SP_FLOWREGION (object);
216         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
217         flags &= SP_OBJECT_MODIFIED_CASCADE;
219         l = NULL;
220         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
221                 g_object_ref (G_OBJECT (child));
222                 l = g_slist_prepend (l, child);
223         }
224         l = g_slist_reverse (l);
225         while (l) {
226                 child = SP_OBJECT (l->data);
227                 l = g_slist_remove (l, child);
228                 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
229                         child->emitModified(flags);
230                 }
231                 g_object_unref (G_OBJECT (child));
232         }
235 static Inkscape::XML::Node *
236 sp_flowregion_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
238     if (flags & SP_OBJECT_WRITE_BUILD) {
239         if ( repr == NULL ) {
240             repr = xml_doc->createElement("svg:flowRegion");
241         }
243         GSList *l = NULL;
244         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
245             if (SP_IS_TITLE(child) || SP_IS_DESC(child)) continue;
246             Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
247             if (crepr) l = g_slist_prepend(l, crepr);
248         }
250         while (l) {
251             repr->addChild((Inkscape::XML::Node *) l->data, NULL);
252             Inkscape::GC::release((Inkscape::XML::Node *) l->data);
253             l = g_slist_remove(l, l->data);
254         }
256     } else {
257         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
258             if (SP_IS_TITLE(child) || SP_IS_DESC(child)) continue;
259             child->updateRepr(flags);
260         }
261     }
263         if (((SPObjectClass *) (flowregion_parent_class))->write)
264                 ((SPObjectClass *) (flowregion_parent_class))->write (object, xml_doc, repr, flags);
266         return repr;
270 static gchar *sp_flowregion_description(SPItem */*item*/)
272         // TRANSLATORS: "Flow region" is an area where text is allowed to flow
273         return g_strdup_printf(_("Flow region"));
276 /*
277  *
278  */
280 GType
281 sp_flowregionexclude_get_type (void)
283         static GType group_type = 0;
284         if (!group_type) {
285                 GTypeInfo group_info = {
286                         sizeof (SPFlowregionExcludeClass),
287                         NULL,   /* base_init */
288                         NULL,   /* base_finalize */
289                         (GClassInitFunc) sp_flowregionexclude_class_init,
290                         NULL,   /* class_finalize */
291                         NULL,   /* class_data */
292                         sizeof (SPFlowregionExclude),
293                         16,     /* n_preallocs */
294                         (GInstanceInitFunc) sp_flowregionexclude_init,
295                         NULL,   /* value_table */
296                 };
297                 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
298         }
299         return group_type;
302 static void
303 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
305         GObjectClass * object_class;
306         SPObjectClass * sp_object_class;
307         SPItemClass * item_class;
309         object_class = (GObjectClass *) klass;
310         sp_object_class = (SPObjectClass *) klass;
311         item_class = (SPItemClass *) klass;
313         flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
315         object_class->dispose = sp_flowregionexclude_dispose;
317         sp_object_class->child_added = sp_flowregionexclude_child_added;
318         sp_object_class->remove_child = sp_flowregionexclude_remove_child;
319         sp_object_class->update = sp_flowregionexclude_update;
320         sp_object_class->modified = sp_flowregionexclude_modified;
321         sp_object_class->write = sp_flowregionexclude_write;
323         item_class->description = sp_flowregionexclude_description;
326 static void
327 sp_flowregionexclude_init (SPFlowregionExclude *group)
329         group->computed = NULL;
332 static void
333 sp_flowregionexclude_dispose(GObject *object)
335         SPFlowregionExclude *group=(SPFlowregionExclude *)object;
336     if (group->computed) {
337         delete group->computed;
338         group->computed = NULL;
339     }
342 static void
343 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
345         SPItem *item;
347         item = SP_ITEM (object);
349         if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
350                 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
352         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
355 /* fixme: hide (Lauris) */
357 static void
358 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
360         if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
361                 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
363         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
367 static void
368 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
370         SPFlowregionExclude *group;
371         SPObject *child;
372         SPItemCtx *ictx, cctx;
373         GSList *l;
375         group = SP_FLOWREGIONEXCLUDE (object);
376         ictx = (SPItemCtx *) ctx;
377         cctx = *ictx;
379         if (((SPObjectClass *) (flowregionexclude_parent_class))->update)
380                 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
382         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
383         flags &= SP_OBJECT_MODIFIED_CASCADE;
385         l = NULL;
386         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
387                 g_object_ref (G_OBJECT (child));
388                 l = g_slist_prepend (l, child);
389         }
390         l = g_slist_reverse (l);
391         while (l) {
392                 child = SP_OBJECT (l->data);
393                 l = g_slist_remove (l, child);
394                 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
395                         if (SP_IS_ITEM (child)) {
396                                 SPItem const &chi = *SP_ITEM(child);
397                                 cctx.i2doc = chi.transform * ictx->i2doc;
398                                 cctx.i2vp = chi.transform * ictx->i2vp;
399                                 child->updateDisplay((SPCtx *)&cctx, flags);
400                         } else {
401                                 child->updateDisplay(ctx, flags);
402                         }
403                 }
404                 g_object_unref (G_OBJECT (child));
405         }
407         group->UpdateComputed();
409 void             SPFlowregionExclude::UpdateComputed(void)
411         SPObject* object=SP_OBJECT(this);
413     if (computed) {
414         delete computed;
415         computed = NULL;
416     }
417     NR::Matrix itr_mat (sp_item_i2root_affine (SP_ITEM(object)));
418     itr_mat = itr_mat.inverse();
420         for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
421                 GetDest(child,&computed,itr_mat);
422         }
425 static void
426 sp_flowregionexclude_modified (SPObject *object, guint flags)
428         SPFlowregionExclude *group;
429         SPObject *child;
430         GSList *l;
432         group = SP_FLOWREGIONEXCLUDE (object);
434         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
435         flags &= SP_OBJECT_MODIFIED_CASCADE;
437         l = NULL;
438         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
439                 g_object_ref (G_OBJECT (child));
440                 l = g_slist_prepend (l, child);
441         }
442         l = g_slist_reverse (l);
443         while (l) {
444                 child = SP_OBJECT (l->data);
445                 l = g_slist_remove (l, child);
446                 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
447                         child->emitModified(flags);
448                 }
449                 g_object_unref (G_OBJECT (child));
450         }
453 static Inkscape::XML::Node *
454 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
456     if (flags & SP_OBJECT_WRITE_BUILD) {
457         if ( repr == NULL ) {
458             repr = xml_doc->createElement("svg:flowRegionExclude");
459         }
461         GSList *l = NULL;
462         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
463             Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
464             if (crepr) l = g_slist_prepend(l, crepr);
465         }
467         while (l) {
468             repr->addChild((Inkscape::XML::Node *) l->data, NULL);
469             Inkscape::GC::release((Inkscape::XML::Node *) l->data);
470             l = g_slist_remove(l, l->data);
471         }
473     } else {
474         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
475             child->updateRepr(flags);
476         }
477     }
479         if (((SPObjectClass *) (flowregionexclude_parent_class))->write)
480                 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, xml_doc, repr, flags);
482         return repr;
486 static gchar *sp_flowregionexclude_description(SPItem */*item*/)
488         /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
489          * flow excluded region.  flowRegionExclude in SVG 1.2: see
490          * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
491          * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
492         return g_strdup_printf(_("Flow excluded region"));
495 /*
496  *
497  */
499 static void         UnionShape(Shape **base_shape, Shape const *add_shape)
501     if (*base_shape == NULL)
502         *base_shape = new Shape;
503         if ( (*base_shape)->hasEdges() == false ) {
504                 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
505         } else if ( add_shape->hasEdges() ) {
506                 Shape* temp=new Shape;
507                 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
508                 delete *base_shape;
509                 *base_shape = temp;
510         }
513 static void         GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
515         if ( child == NULL ) return;
517         SPCurve *curve=NULL;
519         SPObject* u_child=child;
520         if ( SP_IS_USE(u_child) ) {
521                 u_child=SP_USE(u_child)->child;
522         }
523         if ( SP_IS_SHAPE (u_child) ) {
524                 curve = sp_shape_get_curve (SP_SHAPE (u_child));
525         } else if ( SP_IS_TEXT (u_child) ) {
526         curve = SP_TEXT (u_child)->getNormalizedBpath ();
527         }
529         if ( curve ) {
530                 Path*   temp=new Path;
531         Geom::Matrix tr_mat = sp_item_i2root_affine (SP_ITEM(u_child));
532         tr_mat = (Geom::Matrix)itr_mat * tr_mat;
533         temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
534                 Shape*  n_shp=new Shape;
535                 temp->Convert(0.25);
536                 temp->Fill(n_shp,0);
537                 Shape*  uncross=new Shape;
538                 SPStyle* style=SP_OBJECT_STYLE(u_child);
539                 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
540                         uncross->ConvertToShape(n_shp,fill_oddEven);
541                 } else {
542                         uncross->ConvertToShape(n_shp,fill_nonZero);
543                 }
544                 UnionShape(computed, uncross);
545                 delete uncross;
546                 delete n_shp;
547                 delete temp;
548                 curve->unref();
549         } else {
550 //              printf("no curve\n");
551         }