1 #define __SP_SWITCH_CPP__
3 /*
4 * SVG <switch> implementation
5 *
6 * Authors:
7 * Andrius R. <knutux@gmail.com>
8 * MenTaLguY <mental@rydia.net>
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 for (SPObject *child = sp_object_first_child(_group) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
76 if (SP_IS_ITEM(child) && sp_item_evaluate(SP_ITEM(child)))
77 return child;
78 }
79 return NULL;
80 }
82 GSList *CSwitch::_childList(bool add_ref, SPObject::Action action) {
83 if ( action != SPObject::ActionGeneral ) {
84 return _group->childList(add_ref, action);
85 }
87 SPObject *child = _evaluateFirst();
88 if (NULL == child)
89 return NULL;
91 if (add_ref)
92 g_object_ref (G_OBJECT (child));
94 return g_slist_prepend (NULL, child);
95 }
97 gchar *CSwitch::getDescription() {
98 gint len = getItemCount();
99 return g_strdup_printf(
100 ngettext("<b>Conditional group</b> of <b>%d</b> object",
101 "<b>Conditional group</b> of <b>%d</b> objects",
102 len), len);
103 }
105 void CSwitch::onChildAdded(Inkscape::XML::Node *) {
106 _reevaluate(true);
107 }
109 void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
110 _reevaluate();
111 }
113 void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
114 {
115 _reevaluate();
116 }
118 void CSwitch::_reevaluate(bool /*add_to_arena*/) {
119 SPObject *evaluated_child = _evaluateFirst();
120 if (!evaluated_child || _cached_item == evaluated_child) {
121 return;
122 }
124 _releaseLastItem(_cached_item);
126 SPItem * child;
127 for ( GSList *l = _childList(false, SPObject::ActionShow);
128 NULL != l ; l = g_slist_remove (l, l->data))
129 {
130 SPObject *o = SP_OBJECT (l->data);
131 if ( !SP_IS_ITEM (o) ) {
132 continue;
133 }
135 child = SP_ITEM (o);
136 child->setEvaluated(o == evaluated_child);
137 }
139 _cached_item = evaluated_child;
140 _release_connection = evaluated_child->connectRelease(sigc::bind(sigc::ptr_fun(&CSwitch::_releaseItem), this));
142 _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
143 }
145 void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
146 {
147 selection->_releaseLastItem(obj);
148 }
150 void CSwitch::_releaseLastItem(SPObject *obj)
151 {
152 if (NULL == _cached_item || _cached_item != obj)
153 return;
155 _release_connection.disconnect();
156 _cached_item = NULL;
157 }
159 void CSwitch::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) {
160 SPObject *evaluated_child = _evaluateFirst();
162 NRArenaItem *ac = NULL;
163 NRArenaItem *ar = NULL;
164 SPItem * child;
165 GSList *l = _childList(false, SPObject::ActionShow);
166 while (l) {
167 SPObject *o = SP_OBJECT (l->data);
168 if (SP_IS_ITEM (o)) {
169 child = SP_ITEM (o);
170 child->setEvaluated(o == evaluated_child);
171 ac = sp_item_invoke_show (child, arena, key, flags);
172 if (ac) {
173 nr_arena_item_add_child (ai, ac, ar);
174 ar = ac;
175 }
176 }
177 l = g_slist_remove (l, o);
178 }
179 }