1 /*
2 * Authors:
3 * Ted Gould <ted@gould.cx>
4 *
5 * Copyright (C) 2002-2006 Authors
6 *
7 * Released under GNU GPL, read the file 'COPYING' for more information
8 */
10 #include "inkscape-private.h"
11 #include "helper/action.h"
12 #include "document.h"
13 #include "prefdialog.h"
14 #include "implementation/implementation.h"
15 #include "effect.h"
16 #include "ui/view/view.h"
18 /* Inkscape::Extension::Effect */
20 namespace Inkscape {
21 namespace Extension {
23 Effect * Effect::_last_effect = NULL;
24 Inkscape::XML::Node * Effect::_effects_list = NULL;
26 Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
27 : Extension(in_repr, in_imp), _verb(get_id(), get_name(), NULL, NULL, this), _menu_node(NULL)
28 {
29 Inkscape::XML::Node * local_effects_menu = NULL;
31 // This is a weird hack
32 if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
33 return;
35 if (repr != NULL) {
36 Inkscape::XML::Node * child_repr;
38 for (child_repr = sp_repr_children(repr); child_repr != NULL; child_repr = child_repr->next()) {
39 if (!strcmp(child_repr->name(), "effect")) {
40 for (child_repr = sp_repr_children(child_repr); child_repr != NULL; child_repr = child_repr->next()) {
41 if (!strcmp(child_repr->name(), "effects-menu")) {
42 // printf("Found local effects menu in %s\n", this->get_name());
43 local_effects_menu = sp_repr_children(child_repr);
44 }
45 if (!strcmp(child_repr->name(), "menu-name")) {
46 // printf("Found local effects menu in %s\n", this->get_name());
47 _verb.set_name(sp_repr_children(child_repr)->content());
48 }
49 if (!strcmp(child_repr->name(), "menu-tip")) {
50 // printf("Found local effects menu in %s\n", this->get_name());
51 _verb.set_tip(sp_repr_children(child_repr)->content());
52 }
53 } // children of "effect"
54 break; // there can only be one effect
55 } // find "effect"
56 } // children of "inkscape-extension"
57 } // if we have an XML file
59 if (_effects_list == NULL)
60 find_effects_list(inkscape_get_menus(INKSCAPE));
62 if (_effects_list != NULL) {
63 _menu_node = sp_repr_new("verb");
64 _menu_node->setAttribute("verb-id", this->get_id(), false);
66 merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
67 }
69 return;
70 }
72 void
73 Effect::merge_menu (Inkscape::XML::Node * base,
74 Inkscape::XML::Node * start,
75 Inkscape::XML::Node * patern,
76 Inkscape::XML::Node * mergee) {
77 Glib::ustring mergename;
78 Inkscape::XML::Node * tomerge = NULL;
79 Inkscape::XML::Node * submenu = NULL;
81 /* printf("Merge menu with '%s' '%s' '%s'\n",
82 base != NULL ? base->name() : "NULL",
83 patern != NULL ? patern->name() : "NULL",
84 mergee != NULL ? mergee->name() : "NULL"); */
86 if (patern == NULL) {
87 // Merge the verb name
88 tomerge = mergee;
89 mergename = _(this->get_name());
90 } else {
91 gchar const * menuname = patern->attribute("name");
92 if (menuname == NULL) menuname = patern->attribute("_name");
93 if (menuname == NULL) return;
95 tomerge = sp_repr_new("submenu");
96 tomerge->setAttribute("name", menuname, false);
98 mergename = _(menuname);
99 }
101 int position = -1;
103 if (start != NULL) {
104 Inkscape::XML::Node * menupass;
105 for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
106 gchar const * compare_char = NULL;
107 if (!strcmp(menupass->name(), "verb")) {
108 gchar const * verbid = menupass->attribute("verb-id");
109 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
110 if (verb == NULL) {
111 continue;
112 }
113 compare_char = verb->get_name();
114 } else if (!strcmp(menupass->name(), "submenu")) {
115 compare_char = menupass->attribute("name");
116 if (compare_char == NULL)
117 compare_char = menupass->attribute("_name");
118 }
120 /* This will cause us to skip tags we don't understand */
121 if (compare_char == NULL) {
122 continue;
123 }
125 Glib::ustring compare(_(compare_char));
127 if (mergename == compare) {
128 Inkscape::GC::release(tomerge);
129 tomerge = NULL;
130 submenu = menupass;
131 break;
132 }
134 if (mergename < compare) {
135 position = menupass->position();
136 break;
137 }
138 } // for menu items
139 } // start != NULL
141 if (tomerge != NULL) {
142 base->appendChild(tomerge);
143 Inkscape::GC::release(tomerge);
144 if (position != -1)
145 tomerge->setPosition(position);
146 }
148 if (patern != NULL) {
149 if (submenu == NULL)
150 submenu = tomerge;
151 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
152 }
154 return;
155 }
157 Effect::~Effect (void)
158 {
159 if (get_last_effect() == this)
160 set_last_effect(NULL);
161 return;
162 }
164 bool
165 Effect::check (void)
166 {
167 if (!Extension::check()) {
168 /** \todo Check to see if parent has this as its only child,
169 if so, delete it too */
170 if (_menu_node != NULL)
171 sp_repr_unparent(_menu_node);
172 _menu_node = NULL;
173 return false;
174 }
175 return true;
176 }
178 bool
179 Effect::prefs (Inkscape::UI::View::View * doc)
180 {
181 if (!loaded())
182 set_state(Extension::STATE_LOADED);
183 if (!loaded()) return false;
185 Gtk::Widget * controls;
186 controls = imp->prefs_effect(this, doc);
187 if (controls == NULL) {
188 // std::cout << "No preferences for Effect" << std::endl;
189 return true;
190 }
192 PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
193 int response = dialog->run();
194 dialog->hide();
196 delete dialog;
198 if (response == Gtk::RESPONSE_OK) return true;
200 return false;
201 }
203 /**
204 \brief The function that 'does' the effect itself
205 \param doc The Inkscape::UI::View::View to do the effect on
207 This function first insures that the extension is loaded, and if not,
208 loads it. It then calls the implemention to do the actual work. It
209 also resets the last effect pointer to be this effect. Finally, it
210 executes a \c sp_document_done to commit the changes to the undo
211 stack.
212 */
213 void
214 Effect::effect (Inkscape::UI::View::View * doc)
215 {
216 if (!loaded())
217 set_state(Extension::STATE_LOADED);
218 if (!loaded()) return;
220 set_last_effect(this);
221 imp->effect(this, doc);
223 sp_document_done(doc->doc());
225 return;
226 }
228 void
229 Effect::set_last_effect (Effect * in_effect)
230 {
231 if (in_effect == NULL) {
232 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
233 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
234 } else if (_last_effect == NULL) {
235 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
236 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
237 }
239 _last_effect = in_effect;
240 return;
241 }
243 #define EFFECTS_LIST "effects-list"
245 bool
246 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
247 {
248 if (menustruct == NULL) return false;
249 for (Inkscape::XML::Node * child = menustruct;
250 child != NULL;
251 child = child->next()) {
252 if (!strcmp(child->name(), EFFECTS_LIST)) {
253 _effects_list = child;
254 return true;
255 }
256 Inkscape::XML::Node * firstchild = child->firstChild();
257 if (firstchild != NULL)
258 if (find_effects_list(firstchild))
259 return true;
260 }
261 return false;
262 }
264 /** \brief Create an action for a \c EffectVerb
265 \param view Which view the action should be created for
266 \return The built action.
268 Calls \c make_action_helper with the \c vector.
269 */
270 SPAction *
271 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
272 {
273 return make_action_helper(view, &vector, static_cast<void *>(_effect));
274 }
276 /** \brief Decode the verb code and take appropriate action */
277 void
278 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
279 {
280 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
281 // SPDocument * current_document = current_view->doc;
282 Effect * effect = reinterpret_cast<Effect *>(data);
284 if (effect == NULL) return;
285 if (current_view == NULL) return;
287 // std::cout << "Executing: " << effect->get_name() << std::endl;
288 if (effect->prefs(current_view))
289 effect->effect(current_view);
291 return;
292 }
294 /**
295 * Action vector to define functions called if a staticly defined file verb
296 * is called.
297 */
298 SPActionEventVector Effect::EffectVerb::vector =
299 {{NULL},Effect::EffectVerb::perform, NULL, NULL, NULL};
302 } } /* namespace Inkscape, Extension */
304 /*
305 Local Variables:
306 mode:c++
307 c-file-style:"stroustrup"
308 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
309 indent-tabs-mode:nil
310 fill-column:99
311 End:
312 */
313 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :