Code

cbfb5119504b583990a57c68af863b4a94f28512
[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"
19 #include "sp-flowregion.h"
21 #include "display/canvas-bpath.h"
24 #include "livarot/Path.h"
25 #include "livarot/Shape.h"
27 static void sp_flowregion_class_init (SPFlowregionClass *klass);
28 static void sp_flowregion_init (SPFlowregion *group);
29 static void sp_flowregion_dispose (GObject *object);
31 static void sp_flowregion_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
32 static void sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child);
33 static void sp_flowregion_update (SPObject *object, SPCtx *ctx, guint flags);
34 static void sp_flowregion_modified (SPObject *object, guint flags);
35 static Inkscape::XML::Node *sp_flowregion_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
37 static gchar * sp_flowregion_description (SPItem * item);
39 static SPItemClass * flowregion_parent_class;
41 static void sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass);
42 static void sp_flowregionexclude_init (SPFlowregionExclude *group);
43 static void sp_flowregionexclude_dispose (GObject *object);
45 static void sp_flowregionexclude_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
46 static void sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child);
47 static void sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, guint flags);
48 static void sp_flowregionexclude_modified (SPObject *object, guint flags);
49 static Inkscape::XML::Node *sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
51 static gchar * sp_flowregionexclude_description (SPItem * item);
53 static SPItemClass * flowregionexclude_parent_class;
56 static void         GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat);
58 GType
59 sp_flowregion_get_type (void)
60 {
61         static GType group_type = 0;
62         if (!group_type) {
63                 GTypeInfo group_info = {
64                         sizeof (SPFlowregionClass),
65                         NULL,   /* base_init */
66                         NULL,   /* base_finalize */
67                         (GClassInitFunc) sp_flowregion_class_init,
68                         NULL,   /* class_finalize */
69                         NULL,   /* class_data */
70                         sizeof (SPFlowregion),
71                         16,     /* n_preallocs */
72                         (GInstanceInitFunc) sp_flowregion_init,
73                         NULL,   /* value_table */
74                 };
75                 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregion", &group_info, (GTypeFlags)0);
76         }
77         return group_type;
78 }
80 static void
81 sp_flowregion_class_init (SPFlowregionClass *klass)
82 {
83         GObjectClass * object_class;
84         SPObjectClass * sp_object_class;
85         SPItemClass * item_class;
87         object_class = (GObjectClass *) klass;
88         sp_object_class = (SPObjectClass *) klass;
89         item_class = (SPItemClass *) klass;
91         flowregion_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
93         object_class->dispose = sp_flowregion_dispose;
95         sp_object_class->child_added = sp_flowregion_child_added;
96         sp_object_class->remove_child = sp_flowregion_remove_child;
97         sp_object_class->update = sp_flowregion_update;
98         sp_object_class->modified = sp_flowregion_modified;
99         sp_object_class->write = sp_flowregion_write;
101         item_class->description = sp_flowregion_description;
104 static void
105 sp_flowregion_init (SPFlowregion *group)
107         new (&group->computed) std::vector<Shape*>;
110 static void
111 sp_flowregion_dispose(GObject *object)
113         SPFlowregion *group=(SPFlowregion *)object;
114     for (std::vector<Shape*>::iterator it = group->computed.begin() ; it != group->computed.end() ; it++)
115         delete *it;
116     group->computed.~vector<Shape*>();
119 static void
120 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
122         SPItem *item;
124         item = SP_ITEM (object);
126         if (((SPObjectClass *) (flowregion_parent_class))->child_added)
127                 (* ((SPObjectClass *) (flowregion_parent_class))->child_added) (object, child, ref);
129         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
132 /* fixme: hide (Lauris) */
134 static void
135 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
137         if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
138                 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
140         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
144 static void
145 sp_flowregion_update (SPObject *object, SPCtx *ctx, unsigned int flags)
147         SPFlowregion *group;
148         SPObject *child;
149         SPItemCtx *ictx, cctx;
150         GSList *l;
152         group = SP_FLOWREGION (object);
153         ictx = (SPItemCtx *) ctx;
154         cctx = *ictx;
156         if (((SPObjectClass *) (flowregion_parent_class))->update)
157                 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
159         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
160         flags &= SP_OBJECT_MODIFIED_CASCADE;
162         l = NULL;
163         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
164                 g_object_ref (G_OBJECT (child));
165                 l = g_slist_prepend (l, child);
166         }
167         l = g_slist_reverse (l);
168         while (l) {
169                 child = SP_OBJECT (l->data);
170                 l = g_slist_remove (l, child);
171                 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
172                         if (SP_IS_ITEM (child)) {
173                                 SPItem const &chi = *SP_ITEM(child);
174                                 cctx.i2doc = chi.transform * ictx->i2doc;
175                                 cctx.i2vp = chi.transform * ictx->i2vp;
176                                 child->updateDisplay((SPCtx *)&cctx, flags);
177                         } else {
178                                 child->updateDisplay(ctx, flags);
179                         }
180                 }
181                 g_object_unref (G_OBJECT (child));
182         }
184         group->UpdateComputed();
187 void             SPFlowregion::UpdateComputed(void)
189         SPObject* object=SP_OBJECT(this);
191     NR::Matrix itr_mat = from_2geom(sp_item_i2root_affine (SP_ITEM(object)));
192     itr_mat = itr_mat.inverse();
194     for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++)
195         delete *it;
196     computed.clear();
198         for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
199         Shape *shape = NULL;
200                 GetDest(child,&shape,itr_mat);
201         computed.push_back(shape);
202         }
205 static void
206 sp_flowregion_modified (SPObject *object, guint flags)
208         SPFlowregion *group;
209         SPObject *child;
210         GSList *l;
212         group = SP_FLOWREGION (object);
214         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
215         flags &= SP_OBJECT_MODIFIED_CASCADE;
217         l = NULL;
218         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
219                 g_object_ref (G_OBJECT (child));
220                 l = g_slist_prepend (l, child);
221         }
222         l = g_slist_reverse (l);
223         while (l) {
224                 child = SP_OBJECT (l->data);
225                 l = g_slist_remove (l, child);
226                 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
227                         child->emitModified(flags);
228                 }
229                 g_object_unref (G_OBJECT (child));
230         }
233 static Inkscape::XML::Node *
234 sp_flowregion_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
236     if (flags & SP_OBJECT_WRITE_BUILD) {
237         if ( repr == NULL ) {
238             repr = xml_doc->createElement("svg:flowRegion");
239         }
241         GSList *l = NULL;
242         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
243             Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
244             if (crepr) l = g_slist_prepend(l, crepr);
245         }
247         while (l) {
248             repr->addChild((Inkscape::XML::Node *) l->data, NULL);
249             Inkscape::GC::release((Inkscape::XML::Node *) l->data);
250             l = g_slist_remove(l, l->data);
251         }
253     } else {
254         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
255             child->updateRepr(flags);
256         }
257     }
259         if (((SPObjectClass *) (flowregion_parent_class))->write)
260                 ((SPObjectClass *) (flowregion_parent_class))->write (object, xml_doc, repr, flags);
262         return repr;
266 static gchar *sp_flowregion_description(SPItem */*item*/)
268         // TRANSLATORS: "Flow region" is an area where text is allowed to flow
269         return g_strdup_printf(_("Flow region"));
272 /*
273  *
274  */
276 GType
277 sp_flowregionexclude_get_type (void)
279         static GType group_type = 0;
280         if (!group_type) {
281                 GTypeInfo group_info = {
282                         sizeof (SPFlowregionExcludeClass),
283                         NULL,   /* base_init */
284                         NULL,   /* base_finalize */
285                         (GClassInitFunc) sp_flowregionexclude_class_init,
286                         NULL,   /* class_finalize */
287                         NULL,   /* class_data */
288                         sizeof (SPFlowregionExclude),
289                         16,     /* n_preallocs */
290                         (GInstanceInitFunc) sp_flowregionexclude_init,
291                         NULL,   /* value_table */
292                 };
293                 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
294         }
295         return group_type;
298 static void
299 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
301         GObjectClass * object_class;
302         SPObjectClass * sp_object_class;
303         SPItemClass * item_class;
305         object_class = (GObjectClass *) klass;
306         sp_object_class = (SPObjectClass *) klass;
307         item_class = (SPItemClass *) klass;
309         flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
311         object_class->dispose = sp_flowregionexclude_dispose;
313         sp_object_class->child_added = sp_flowregionexclude_child_added;
314         sp_object_class->remove_child = sp_flowregionexclude_remove_child;
315         sp_object_class->update = sp_flowregionexclude_update;
316         sp_object_class->modified = sp_flowregionexclude_modified;
317         sp_object_class->write = sp_flowregionexclude_write;
319         item_class->description = sp_flowregionexclude_description;
322 static void
323 sp_flowregionexclude_init (SPFlowregionExclude *group)
325         group->computed = NULL;
328 static void
329 sp_flowregionexclude_dispose(GObject *object)
331         SPFlowregionExclude *group=(SPFlowregionExclude *)object;
332     if (group->computed) {
333         delete group->computed;
334         group->computed = NULL;
335     }
338 static void
339 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
341         SPItem *item;
343         item = SP_ITEM (object);
345         if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
346                 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
348         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
351 /* fixme: hide (Lauris) */
353 static void
354 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
356         if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
357                 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
359         object->requestModified(SP_OBJECT_MODIFIED_FLAG);
363 static void
364 sp_flowregionexclude_update (SPObject *object, SPCtx *ctx, unsigned int flags)
366         SPFlowregionExclude *group;
367         SPObject *child;
368         SPItemCtx *ictx, cctx;
369         GSList *l;
371         group = SP_FLOWREGIONEXCLUDE (object);
372         ictx = (SPItemCtx *) ctx;
373         cctx = *ictx;
375         if (((SPObjectClass *) (flowregionexclude_parent_class))->update)
376                 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
378         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
379         flags &= SP_OBJECT_MODIFIED_CASCADE;
381         l = NULL;
382         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
383                 g_object_ref (G_OBJECT (child));
384                 l = g_slist_prepend (l, child);
385         }
386         l = g_slist_reverse (l);
387         while (l) {
388                 child = SP_OBJECT (l->data);
389                 l = g_slist_remove (l, child);
390                 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
391                         if (SP_IS_ITEM (child)) {
392                                 SPItem const &chi = *SP_ITEM(child);
393                                 cctx.i2doc = chi.transform * ictx->i2doc;
394                                 cctx.i2vp = chi.transform * ictx->i2vp;
395                                 child->updateDisplay((SPCtx *)&cctx, flags);
396                         } else {
397                                 child->updateDisplay(ctx, flags);
398                         }
399                 }
400                 g_object_unref (G_OBJECT (child));
401         }
403         group->UpdateComputed();
405 void             SPFlowregionExclude::UpdateComputed(void)
407         SPObject* object=SP_OBJECT(this);
409     if (computed) {
410         delete computed;
411         computed = NULL;
412     }
413     NR::Matrix itr_mat = from_2geom(sp_item_i2root_affine (SP_ITEM(object)));
414     itr_mat = itr_mat.inverse();
416         for (SPObject* child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
417                 GetDest(child,&computed,itr_mat);
418         }
421 static void
422 sp_flowregionexclude_modified (SPObject *object, guint flags)
424         SPFlowregionExclude *group;
425         SPObject *child;
426         GSList *l;
428         group = SP_FLOWREGIONEXCLUDE (object);
430         if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
431         flags &= SP_OBJECT_MODIFIED_CASCADE;
433         l = NULL;
434         for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
435                 g_object_ref (G_OBJECT (child));
436                 l = g_slist_prepend (l, child);
437         }
438         l = g_slist_reverse (l);
439         while (l) {
440                 child = SP_OBJECT (l->data);
441                 l = g_slist_remove (l, child);
442                 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
443                         child->emitModified(flags);
444                 }
445                 g_object_unref (G_OBJECT (child));
446         }
449 static Inkscape::XML::Node *
450 sp_flowregionexclude_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
452     if (flags & SP_OBJECT_WRITE_BUILD) {
453         if ( repr == NULL ) {
454             repr = xml_doc->createElement("svg:flowRegionExclude");
455         }
457         GSList *l = NULL;
458         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
459             Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
460             if (crepr) l = g_slist_prepend(l, crepr);
461         }
463         while (l) {
464             repr->addChild((Inkscape::XML::Node *) l->data, NULL);
465             Inkscape::GC::release((Inkscape::XML::Node *) l->data);
466             l = g_slist_remove(l, l->data);
467         }
469     } else {
470         for ( SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
471             child->updateRepr(flags);
472         }
473     }
475         if (((SPObjectClass *) (flowregionexclude_parent_class))->write)
476                 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, xml_doc, repr, flags);
478         return repr;
482 static gchar *sp_flowregionexclude_description(SPItem */*item*/)
484         /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
485          * flow excluded region.  flowRegionExclude in SVG 1.2: see
486          * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
487          * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
488         return g_strdup_printf(_("Flow excluded region"));
491 /*
492  *
493  */
495 static void         UnionShape(Shape **base_shape, Shape const *add_shape)
497     if (*base_shape == NULL)
498         *base_shape = new Shape;
499         if ( (*base_shape)->hasEdges() == false ) {
500                 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
501         } else if ( add_shape->hasEdges() ) {
502                 Shape* temp=new Shape;
503                 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
504                 delete *base_shape;
505                 *base_shape = temp;
506         }
509 static void         GetDest(SPObject* child,Shape **computed,NR::Matrix itr_mat)
511         if ( child == NULL ) return;
513         SPCurve *curve=NULL;
515         SPObject* u_child=child;
516         if ( SP_IS_USE(u_child) ) {
517                 u_child=SP_USE(u_child)->child;
518         }
519         if ( SP_IS_SHAPE (u_child) ) {
520                 curve = sp_shape_get_curve (SP_SHAPE (u_child));
521         } else if ( SP_IS_TEXT (u_child) ) {
522         curve = SP_TEXT (u_child)->getNormalizedBpath ();
523         }
525         if ( curve ) {
526                 Path*   temp=new Path;
527         Geom::Matrix tr_mat = sp_item_i2root_affine (SP_ITEM(u_child));
528         tr_mat = to_2geom(itr_mat) * tr_mat;
529         temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
530                 Shape*  n_shp=new Shape;
531                 temp->Convert(0.25);
532                 temp->Fill(n_shp,0);
533                 Shape*  uncross=new Shape;
534                 SPStyle* style=SP_OBJECT_STYLE(u_child);
535                 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
536                         uncross->ConvertToShape(n_shp,fill_oddEven);
537                 } else {
538                         uncross->ConvertToShape(n_shp,fill_nonZero);
539                 }
540                 UnionShape(computed, uncross);
541                 delete uncross;
542                 delete n_shp;
543                 delete temp;
544                 curve->unref();
545         } else {
546 //              printf("no curve\n");
547         }