1 /*
2 */
4 #ifdef HAVE_CONFIG_H
5 # include "config.h"
6 #endif
7 #include <glibmm/i18n.h>
9 #include <xml/repr.h>
10 #include "display/curve.h"
11 #include "sp-shape.h"
12 #include "sp-text.h"
13 #include "sp-use.h"
14 #include "style.h"
15 #include "document.h"
16 #include "sp-title.h"
17 #include "sp-desc.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);
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;
102 }
104 static void
105 sp_flowregion_init (SPFlowregion *group)
106 {
107 new (&group->computed) std::vector<Shape*>;
108 }
110 static void
111 sp_flowregion_dispose(GObject *object)
112 {
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*>();
117 }
119 static void
120 sp_flowregion_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
121 {
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);
130 }
132 /* fixme: hide (Lauris) */
134 static void
135 sp_flowregion_remove_child (SPObject * object, Inkscape::XML::Node * child)
136 {
137 if (((SPObjectClass *) (flowregion_parent_class))->remove_child)
138 (* ((SPObjectClass *) (flowregion_parent_class))->remove_child) (object, child);
140 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
141 }
144 static void sp_flowregion_update(SPObject *object, SPCtx *ctx, unsigned int flags)
145 {
146 SPFlowregion *group = SP_FLOWREGION(object);
148 SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx);
149 SPItemCtx cctx = *ictx;
151 if (((SPObjectClass *) (flowregion_parent_class))->update) {
152 ((SPObjectClass *) (flowregion_parent_class))->update (object, ctx, flags);
153 }
155 if (flags & SP_OBJECT_MODIFIED_FLAG) {
156 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
157 }
158 flags &= SP_OBJECT_MODIFIED_CASCADE;
160 GSList *l = NULL;
161 for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) {
162 g_object_ref( G_OBJECT(child) );
163 l = g_slist_prepend(l, child);
164 }
165 l = g_slist_reverse(l);
166 while (l) {
167 SPObject *child = SP_OBJECT(l->data);
168 l = g_slist_remove(l, child);
169 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
170 if (SP_IS_ITEM (child)) {
171 SPItem const &chi = *SP_ITEM(child);
172 cctx.i2doc = chi.transform * ictx->i2doc;
173 cctx.i2vp = chi.transform * ictx->i2vp;
174 child->updateDisplay((SPCtx *)&cctx, flags);
175 } else {
176 child->updateDisplay(ctx, flags);
177 }
178 }
179 g_object_unref (G_OBJECT(child));
180 }
182 group->UpdateComputed();
183 }
185 void SPFlowregion::UpdateComputed(void)
186 {
187 for (std::vector<Shape*>::iterator it = computed.begin() ; it != computed.end() ; it++) {
188 delete *it;
189 }
190 computed.clear();
192 for (SPObject* child = firstChild() ; child ; child = child->getNext() ) {
193 Shape *shape = 0;
194 GetDest(child, &shape);
195 computed.push_back(shape);
196 }
197 }
199 static void sp_flowregion_modified(SPObject *object, guint flags)
200 {
201 SP_FLOWREGION(object); // ensure it is the proper type.
203 if (flags & SP_OBJECT_MODIFIED_FLAG) {
204 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
205 }
206 flags &= SP_OBJECT_MODIFIED_CASCADE;
208 GSList *l = NULL;
209 for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) {
210 g_object_ref( G_OBJECT(child) );
211 l = g_slist_prepend(l, child);
212 }
213 l = g_slist_reverse(l);
214 while (l) {
215 SPObject *child = SP_OBJECT(l->data);
216 l = g_slist_remove(l, child);
217 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
218 child->emitModified(flags);
219 }
220 g_object_unref( G_OBJECT(child) );
221 }
222 }
224 static Inkscape::XML::Node *sp_flowregion_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
225 {
226 if (flags & SP_OBJECT_WRITE_BUILD) {
227 if ( repr == NULL ) {
228 repr = xml_doc->createElement("svg:flowRegion");
229 }
231 GSList *l = NULL;
232 for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) {
233 if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) {
234 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
235 if (crepr) {
236 l = g_slist_prepend(l, crepr);
237 }
238 }
239 }
241 while (l) {
242 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
243 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
244 l = g_slist_remove(l, l->data);
245 }
247 } else {
248 for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) {
249 if ( !SP_IS_TITLE(child) && !SP_IS_DESC(child) ) {
250 child->updateRepr(flags);
251 }
252 }
253 }
255 if (((SPObjectClass *) (flowregion_parent_class))->write) {
256 ((SPObjectClass *) (flowregion_parent_class))->write (object, xml_doc, repr, flags);
257 }
259 return repr;
260 }
263 static gchar *sp_flowregion_description(SPItem */*item*/)
264 {
265 // TRANSLATORS: "Flow region" is an area where text is allowed to flow
266 return g_strdup_printf(_("Flow region"));
267 }
269 /*
270 *
271 */
273 GType
274 sp_flowregionexclude_get_type (void)
275 {
276 static GType group_type = 0;
277 if (!group_type) {
278 GTypeInfo group_info = {
279 sizeof (SPFlowregionExcludeClass),
280 NULL, /* base_init */
281 NULL, /* base_finalize */
282 (GClassInitFunc) sp_flowregionexclude_class_init,
283 NULL, /* class_finalize */
284 NULL, /* class_data */
285 sizeof (SPFlowregionExclude),
286 16, /* n_preallocs */
287 (GInstanceInitFunc) sp_flowregionexclude_init,
288 NULL, /* value_table */
289 };
290 group_type = g_type_register_static (SP_TYPE_ITEM, "SPFlowregionExclude", &group_info, (GTypeFlags)0);
291 }
292 return group_type;
293 }
295 static void
296 sp_flowregionexclude_class_init (SPFlowregionExcludeClass *klass)
297 {
298 GObjectClass * object_class;
299 SPObjectClass * sp_object_class;
300 SPItemClass * item_class;
302 object_class = (GObjectClass *) klass;
303 sp_object_class = (SPObjectClass *) klass;
304 item_class = (SPItemClass *) klass;
306 flowregionexclude_parent_class = (SPItemClass *)g_type_class_ref (SP_TYPE_ITEM);
308 object_class->dispose = sp_flowregionexclude_dispose;
310 sp_object_class->child_added = sp_flowregionexclude_child_added;
311 sp_object_class->remove_child = sp_flowregionexclude_remove_child;
312 sp_object_class->update = sp_flowregionexclude_update;
313 sp_object_class->modified = sp_flowregionexclude_modified;
314 sp_object_class->write = sp_flowregionexclude_write;
316 item_class->description = sp_flowregionexclude_description;
317 }
319 static void
320 sp_flowregionexclude_init (SPFlowregionExclude *group)
321 {
322 group->computed = NULL;
323 }
325 static void
326 sp_flowregionexclude_dispose(GObject *object)
327 {
328 SPFlowregionExclude *group=(SPFlowregionExclude *)object;
329 if (group->computed) {
330 delete group->computed;
331 group->computed = NULL;
332 }
333 }
335 static void
336 sp_flowregionexclude_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
337 {
338 SPItem *item;
340 item = SP_ITEM (object);
342 if (((SPObjectClass *) (flowregionexclude_parent_class))->child_added)
343 (* ((SPObjectClass *) (flowregionexclude_parent_class))->child_added) (object, child, ref);
345 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
346 }
348 /* fixme: hide (Lauris) */
350 static void
351 sp_flowregionexclude_remove_child (SPObject * object, Inkscape::XML::Node * child)
352 {
353 if (((SPObjectClass *) (flowregionexclude_parent_class))->remove_child)
354 (* ((SPObjectClass *) (flowregionexclude_parent_class))->remove_child) (object, child);
356 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
357 }
360 static void sp_flowregionexclude_update(SPObject *object, SPCtx *ctx, unsigned int flags)
361 {
362 SPFlowregionExclude *group = SP_FLOWREGIONEXCLUDE (object);
364 SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx);
365 SPItemCtx cctx = *ictx;
367 if (((SPObjectClass *) (flowregionexclude_parent_class))->update) {
368 ((SPObjectClass *) (flowregionexclude_parent_class))->update (object, ctx, flags);
369 }
371 if (flags & SP_OBJECT_MODIFIED_FLAG) {
372 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
373 }
374 flags &= SP_OBJECT_MODIFIED_CASCADE;
376 GSList *l = NULL;
377 for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) {
378 g_object_ref( G_OBJECT(child) );
379 l = g_slist_prepend(l, child);
380 }
381 l = g_slist_reverse (l);
382 while (l) {
383 SPObject *child = SP_OBJECT(l->data);
384 l = g_slist_remove(l, child);
385 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
386 if (SP_IS_ITEM (child)) {
387 SPItem const &chi = *SP_ITEM(child);
388 cctx.i2doc = chi.transform * ictx->i2doc;
389 cctx.i2vp = chi.transform * ictx->i2vp;
390 child->updateDisplay((SPCtx *)&cctx, flags);
391 } else {
392 child->updateDisplay(ctx, flags);
393 }
394 }
395 g_object_unref( G_OBJECT(child) );
396 }
398 group->UpdateComputed();
399 }
401 void SPFlowregionExclude::UpdateComputed(void)
402 {
403 if (computed) {
404 delete computed;
405 computed = NULL;
406 }
408 for ( SPObject* child = firstChild() ; child ; child = child->getNext() ) {
409 GetDest(child, &computed);
410 }
411 }
413 static void sp_flowregionexclude_modified(SPObject *object, guint flags)
414 {
415 SP_FLOWREGIONEXCLUDE(object); // Ensure it is the proper type
417 if (flags & SP_OBJECT_MODIFIED_FLAG) {
418 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
419 }
420 flags &= SP_OBJECT_MODIFIED_CASCADE;
422 GSList *l = NULL;
423 for ( SPObject *child = object->firstChild() ; child ; child = child->getNext() ) {
424 g_object_ref( G_OBJECT(child) );
425 l = g_slist_prepend(l, child);
426 }
427 l = g_slist_reverse (l);
428 while (l) {
429 SPObject *child = SP_OBJECT(l->data);
430 l = g_slist_remove(l, child);
431 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
432 child->emitModified(flags);
433 }
434 g_object_unref( G_OBJECT(child) );
435 }
436 }
438 static Inkscape::XML::Node *sp_flowregionexclude_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
439 {
440 if (flags & SP_OBJECT_WRITE_BUILD) {
441 if ( repr == NULL ) {
442 repr = xml_doc->createElement("svg:flowRegionExclude");
443 }
445 GSList *l = NULL;
446 for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) {
447 Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
448 if (crepr) {
449 l = g_slist_prepend(l, crepr);
450 }
451 }
453 while (l) {
454 repr->addChild((Inkscape::XML::Node *) l->data, NULL);
455 Inkscape::GC::release((Inkscape::XML::Node *) l->data);
456 l = g_slist_remove(l, l->data);
457 }
459 } else {
460 for ( SPObject *child = object->firstChild() ; child; child = child->getNext() ) {
461 child->updateRepr(flags);
462 }
463 }
465 if (((SPObjectClass *) (flowregionexclude_parent_class))->write) {
466 ((SPObjectClass *) (flowregionexclude_parent_class))->write (object, xml_doc, repr, flags);
467 }
469 return repr;
470 }
473 static gchar *sp_flowregionexclude_description(SPItem */*item*/)
474 {
475 /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
476 * flow excluded region. flowRegionExclude in SVG 1.2: see
477 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
478 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
479 return g_strdup_printf(_("Flow excluded region"));
480 }
482 /*
483 *
484 */
486 static void UnionShape(Shape **base_shape, Shape const *add_shape)
487 {
488 if (*base_shape == NULL)
489 *base_shape = new Shape;
490 if ( (*base_shape)->hasEdges() == false ) {
491 (*base_shape)->Copy(const_cast<Shape*>(add_shape));
492 } else if ( add_shape->hasEdges() ) {
493 Shape* temp=new Shape;
494 temp->Booleen(const_cast<Shape*>(add_shape), *base_shape, bool_op_union);
495 delete *base_shape;
496 *base_shape = temp;
497 }
498 }
500 static void GetDest(SPObject* child,Shape **computed)
501 {
502 if ( child == NULL ) return;
504 SPCurve *curve=NULL;
505 Geom::Matrix tr_mat;
507 SPObject* u_child=child;
508 if ( SP_IS_USE(u_child) ) {
509 u_child=SP_USE(u_child)->child;
510 tr_mat = SP_ITEM(u_child)->getRelativeTransform(SP_OBJECT_PARENT(child));
511 } else {
512 tr_mat = SP_ITEM(u_child)->transform;
513 }
514 if ( SP_IS_SHAPE (u_child) ) {
515 curve = SP_SHAPE (u_child)->getCurve ();
516 } else if ( SP_IS_TEXT (u_child) ) {
517 curve = SP_TEXT (u_child)->getNormalizedBpath ();
518 }
520 if ( curve ) {
521 Path* temp=new Path;
522 temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
523 Shape* n_shp=new Shape;
524 temp->Convert(0.25);
525 temp->Fill(n_shp,0);
526 Shape* uncross=new Shape;
527 SPStyle* style=SP_OBJECT_STYLE(u_child);
528 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
529 uncross->ConvertToShape(n_shp,fill_oddEven);
530 } else {
531 uncross->ConvertToShape(n_shp,fill_nonZero);
532 }
533 UnionShape(computed, uncross);
534 delete uncross;
535 delete n_shp;
536 delete temp;
537 curve->unref();
538 } else {
539 // printf("no curve\n");
540 }
541 }
543 /*
544 Local Variables:
545 mode:c++
546 c-file-style:"stroustrup"
547 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
548 indent-tabs-mode:nil
549 fill-column:99
550 End:
551 */
552 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :