Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / sp-switch.cpp
1 /*
2  * SVG <switch> implementation
3  *
4  * Authors:
5  *   Andrius R. <knutux@gmail.com>
6  *   MenTaLguY  <mental@rydia.net>
7  *   Jon A. Cruz <jon@joncruz.org>
8  *   Abhishek Sharma
9  *
10  * Copyright (C) 2006 authors
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #include <glibmm/i18n.h>
21 #include "sp-switch.h"
22 #include "display/nr-arena-group.h"
23 #include "conditions.h"
25 #include <sigc++/functors/ptr_fun.h>
26 #include <sigc++/adaptors/bind.h>
28 static void sp_switch_class_init (SPSwitchClass *klass);
29 static void sp_switch_init (SPSwitch *group);
31 static SPGroupClass * parent_class;
33 GType CSwitch::getType (void)
34 {
35         static GType switch_type = 0;
36         if (!switch_type) {
37                 GTypeInfo switch_info = {
38                         sizeof (SPSwitchClass),
39                         NULL,   /* base_init */
40                         NULL,   /* base_finalize */
41                         (GClassInitFunc) sp_switch_class_init,
42                         NULL,   /* class_finalize */
43                         NULL,   /* class_data */
44                         sizeof (SPSwitch),
45                         16,     /* n_preallocs */
46              (GInstanceInitFunc) sp_switch_init,
47                         NULL,   /* value_table */
48                 };
49                 switch_type = g_type_register_static (SP_TYPE_GROUP, "SPSwitch", &switch_info, (GTypeFlags)0);
50         }
51         return switch_type;
52 }
54 static void
55 sp_switch_class_init (SPSwitchClass *) {
56     parent_class = (SPGroupClass *)g_type_class_ref (SP_TYPE_GROUP);
57 }
59 static void sp_switch_init (SPSwitch *group)
60 {
61     if (group->group)
62         delete group->group;
64     group->group = new CSwitch(group);
65 }
67 CSwitch::CSwitch(SPGroup *group) : CGroup(group), _cached_item(NULL) {
68 }
70 CSwitch::~CSwitch() {
71     _releaseLastItem(_cached_item);
72 }
74 SPObject *CSwitch::_evaluateFirst() {
75     SPObject *first = 0;
76     for (SPObject *child = _group->firstChild() ; child && !first ; child = child->getNext() ) {
77         if (SP_IS_ITEM(child) && sp_item_evaluate(SP_ITEM(child))) {
78             first = child;
79         }
80     }
81     return first;
82 }
84 GSList *CSwitch::_childList(bool add_ref, SPObject::Action action) {
85     if ( action != SPObject::ActionGeneral ) {
86         return _group->childList(add_ref, action);
87     }
89     SPObject *child = _evaluateFirst();
90     if (NULL == child)
91         return NULL;
93     if (add_ref)
94         g_object_ref (G_OBJECT (child));
96     return g_slist_prepend (NULL, child);
97 }
99 gchar *CSwitch::getDescription() {
100     gint len = getItemCount();
101     return g_strdup_printf(
102             ngettext("<b>Conditional group</b> of <b>%d</b> object",
103                  "<b>Conditional group</b> of <b>%d</b> objects",
104                  len), len);
107 void CSwitch::onChildAdded(Inkscape::XML::Node *) {
108     _reevaluate(true);
111 void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
112     _reevaluate();
115 void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
117     _reevaluate();
120 void CSwitch::_reevaluate(bool /*add_to_arena*/) {
121     SPObject *evaluated_child = _evaluateFirst();
122     if (!evaluated_child || _cached_item == evaluated_child) {
123         return;
124     }
126     _releaseLastItem(_cached_item);
128     SPItem * child;
129     for ( GSList *l = _childList(false, SPObject::ActionShow);
130             NULL != l ; l = g_slist_remove (l, l->data))
131     {
132         SPObject *o = SP_OBJECT (l->data);
133         if ( !SP_IS_ITEM (o) ) {
134             continue;
135         }
137         child = SP_ITEM (o);
138         child->setEvaluated(o == evaluated_child);
139     }
141     _cached_item = evaluated_child;
142     _release_connection = evaluated_child->connectRelease(sigc::bind(sigc::ptr_fun(&CSwitch::_releaseItem), this));
144     _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
147 void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
149     selection->_releaseLastItem(obj);
152 void CSwitch::_releaseLastItem(SPObject *obj)
154     if (NULL == _cached_item || _cached_item != obj)
155         return;
157     _release_connection.disconnect();
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, SPObject::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 = child->invoke_show (arena, key, flags);
174             if (ac) {
175                 nr_arena_item_add_child (ai, ac, ar);
176                 ar = ac;
177             }
178         }
179         l = g_slist_remove (l, o);
180     }
183 /*
184   Local Variables:
185   mode:c++
186   c-file-style:"stroustrup"
187   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
188   indent-tabs-mode:nil
189   fill-column:99
190   End:
191 */
192 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :