Code

SVG 1.1 Conditional Processing Module rendering support (<switch> element, requiredRe...
[inkscape.git] / src / sp-switch.cpp
1 #define __SP_SWITCH_CPP__
3 /*
4  * SVG <switch> implementation
5  *
6  * Authors:
7  *   Andrius R. <knutux@gmail.com>
8  *
9  * Copyright (C) 2006 authors
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #if defined(WIN32) || defined(__APPLE__)
19 # include <glibmm/i18n.h>
20 #endif
22 #include "sp-switch.h"
23 #include "display/nr-arena-group.h"
24 #include "conditions.h"
26 static void sp_switch_class_init (SPSwitchClass *klass);
27 static void sp_switch_init (SPSwitch *group);
29 static SPGroupClass * parent_class;
31 GType CSwitch::getType (void)
32 {
33         static GType switch_type = 0;
34         if (!switch_type) {
35                 GTypeInfo switch_info = {
36                         sizeof (SPSwitchClass),
37                         NULL,   /* base_init */
38                         NULL,   /* base_finalize */
39                         (GClassInitFunc) sp_switch_class_init,
40                         NULL,   /* class_finalize */
41                         NULL,   /* class_data */
42                         sizeof (SPSwitch),
43                         16,     /* n_preallocs */
44              (GInstanceInitFunc) sp_switch_init,
45                         NULL,   /* value_table */
46                 };
47                 switch_type = g_type_register_static (SP_TYPE_GROUP, "SPSwitch", &switch_info, (GTypeFlags)0);
48         }
49         return switch_type;
50 }
52 static void
53 sp_switch_class_init (SPSwitchClass *) {
54     parent_class = (SPGroupClass *)g_type_class_ref (SP_TYPE_GROUP);
55 }
57 static void sp_switch_init (SPSwitch *group)
58 {
59     if (group->group)
60         delete group->group;
62     group->group = new CSwitch(group);
63 }
65 CSwitch::CSwitch(SPGroup *group) : CGroup(group), _cached_item(NULL), _release_handler_id(0) {
66 }
68 CSwitch::~CSwitch() {
69     _releaseLastItem(_cached_item);
70 }
72 SPObject *CSwitch::_evaluateFirst() {
73     for (SPObject *child = sp_object_first_child(_group) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
74         if (sp_item_evaluate(SP_ITEM(child)))
75             return child;
76     }
77     return NULL;
78 }
80 GSList *CSwitch::_childList(bool add_ref, Action action) {
81     if ( ActionGeneral != action ) {
82         return CGroup::_childList(add_ref, action);
83     }
85     SPObject *child = _evaluateFirst();
86     if (NULL == child)
87         return NULL;
89     if (add_ref)
90         g_object_ref (G_OBJECT (child));
92     return g_slist_prepend (NULL, child);
93 }
95 gchar *CSwitch::getDescription() {
96     gint len = getItemCount();
97     return g_strdup_printf(
98             ngettext("<b>Conditional group</b> of <b>%d</b> object",
99                  "<b>Conditional group</b> of <b>%d</b> objects",
100                  len), len);
103 void CSwitch::onChildAdded(Inkscape::XML::Node *) {
104     _reevaluate(true);
107 void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
108     _reevaluate();
111 void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
113     _reevaluate();
116 void CSwitch::_reevaluate(bool add_to_arena) {
117     SPObject *evaluated_child = _evaluateFirst();
118     if (!evaluated_child || _cached_item == evaluated_child) {
119         return;
120     }
122     _releaseLastItem(_cached_item);
124     SPItem * child;
125     for ( GSList *l = _childList(false, ActionShow);
126             NULL != l ; l = g_slist_remove (l, l->data))
127     {
128         SPObject *o = SP_OBJECT (l->data);
129         if ( !SP_IS_ITEM (o) ) {
130             continue;
131         }
133         child = SP_ITEM (o);
134         child->setEvaluated(o == evaluated_child);
135     }
137     _cached_item = evaluated_child;
138     _release_handler_id = g_signal_connect(
139                                     G_OBJECT(evaluated_child), "release",
140                                     G_CALLBACK(&CSwitch::_releaseItem),
141                                     this);
143     _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
146 void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
148     selection->_releaseLastItem(obj);
151 void CSwitch::_releaseLastItem(SPObject *obj)
153     if (NULL == _cached_item || _cached_item != obj)
154         return;
156     g_signal_handler_disconnect(G_OBJECT(_cached_item), _release_handler_id);
157     _release_handler_id = 0;
158     _cached_item = NULL;
161 void CSwitch::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) {
162     SPObject *evaluated_child = _evaluateFirst();
164     NRArenaItem *ac = NULL;
165     NRArenaItem *ar = NULL;
166     SPItem * child;
167     GSList *l = _childList(false, ActionShow);
168     while (l) {
169         SPObject *o = SP_OBJECT (l->data);
170         if (SP_IS_ITEM (o)) {
171             child = SP_ITEM (o);
172             child->setEvaluated(o == evaluated_child);
173             ac = sp_item_invoke_show (child, arena, key, flags);
174             if (ac) {
175                 nr_arena_item_add_child (ai, ac, ar);
176                 ar = ac;
177                 nr_arena_item_unref (ac);
178             }
179         }
180         l = g_slist_remove (l, o);
181     }