Code

r16892@shi: ted | 2007-10-29 21:33:09 -0700
[inkscape.git] / src / extension / effect.cpp
1 /*
2  * Authors:
3  *   Ted Gould <ted@gould.cx>
4  *
5  * Copyright (C) 2002-2007 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 "ui/view/view.h"
13 #include "desktop-handles.h"
14 #include "selection.h"
15 #include "sp-namedview.h"
16 #include "desktop.h"
17 #include "implementation/implementation.h"
18 #include "effect.h"
19 #include "execution-env.h"
20 #include "timer.h"
24 /* Inkscape::Extension::Effect */
26 namespace Inkscape {
27 namespace Extension {
29 Effect * Effect::_last_effect = NULL;
30 Inkscape::XML::Node * Effect::_effects_list = NULL;
32 Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
33     : Extension(in_repr, in_imp),
34       _id_noprefs(Glib::ustring(get_id()) + ".noprefs"),
35       _name_noprefs(Glib::ustring(get_name()) + _(" (No preferences)")),
36       _verb(get_id(), get_name(), NULL, NULL, this, true),
37       _verb_nopref(_id_noprefs.c_str(), _name_noprefs.c_str(), NULL, NULL, this, false),
38       _menu_node(NULL), _workingDialog(true),
39       _prefDialog(NULL)
40 {
41     Inkscape::XML::Node * local_effects_menu = NULL;
43     // This is a weird hack
44     if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
45         return;
47     bool hidden = false;
49     no_doc = false;
51     if (repr != NULL) {
53         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
54             if (!strcmp(child->name(), "effect")) {
55                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
56                   no_doc = true;
57                 }
58                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
59                     if (!strcmp(effect_child->name(), "effects-menu")) {
60                         // printf("Found local effects menu in %s\n", this->get_name());
61                         local_effects_menu = sp_repr_children(effect_child);
62                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
63                             hidden = true;
64                         }
65                     }
66                     if (!strcmp(effect_child->name(), "menu-name") ||
67                             !strcmp(effect_child->name(), "_menu-name")) {
68                         // printf("Found local effects menu in %s\n", this->get_name());
69                         _verb.set_name(sp_repr_children(effect_child)->content());
70                     }
71                     if (!strcmp(effect_child->name(), "menu-tip") ||
72                             !strcmp(effect_child->name(), "_menu-tip")) {
73                         // printf("Found local effects menu in %s\n", this->get_name());
74                         _verb.set_tip(sp_repr_children(effect_child)->content());
75                     }
76                 } // children of "effect"
77                 break; // there can only be one effect
78             } // find "effect"
79         } // children of "inkscape-extension"
80     } // if we have an XML file
82     if (_effects_list == NULL && INKSCAPE != NULL) {
83         find_effects_list(inkscape_get_menus(INKSCAPE));
84     }
86     if (_effects_list != NULL) {
87         Inkscape::XML::Document *xml_doc;
88         xml_doc = _effects_list->document();
89         _menu_node = xml_doc->createElement("verb");
90         _menu_node->setAttribute("verb-id", this->get_id(), false);
92         if (!hidden)
93             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
94     }
96     return;
97 }
99 void
100 Effect::merge_menu (Inkscape::XML::Node * base,
101                     Inkscape::XML::Node * start,
102                     Inkscape::XML::Node * patern,
103                     Inkscape::XML::Node * mergee) {
104     Glib::ustring mergename;
105     Inkscape::XML::Node * tomerge = NULL;
106     Inkscape::XML::Node * submenu = NULL;
108     /* printf("Merge menu with '%s' '%s' '%s'\n",
109             base != NULL ? base->name() : "NULL",
110             patern != NULL ? patern->name() : "NULL",
111             mergee != NULL ? mergee->name() : "NULL"); */
113     if (patern == NULL) {
114         // Merge the verb name
115         tomerge = mergee;
116         mergename = _(this->get_name());
117     } else {
118         gchar const * menuname = patern->attribute("name");
119         if (menuname == NULL) menuname = patern->attribute("_name");
120         if (menuname == NULL) return;
121         
122         Inkscape::XML::Document *xml_doc;
123         xml_doc = base->document();
124         tomerge = xml_doc->createElement("submenu");
125         tomerge->setAttribute("name", menuname, false);
127         mergename = _(menuname);
128     }
130     int position = -1;
132     if (start != NULL) {
133         Inkscape::XML::Node * menupass;
134         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
135             gchar const * compare_char = NULL;
136             if (!strcmp(menupass->name(), "verb")) {
137                 gchar const * verbid = menupass->attribute("verb-id");
138                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
139                 if (verb == NULL) {
140                     continue;
141                 }
142                 compare_char = verb->get_name();
143             } else if (!strcmp(menupass->name(), "submenu")) {
144                 compare_char = menupass->attribute("name");
145                 if (compare_char == NULL)
146                     compare_char = menupass->attribute("_name");
147             }
149             /* This will cause us to skip tags we don't understand */
150             if (compare_char == NULL) {
151                 continue;
152             }
154             Glib::ustring compare(_(compare_char));
156             if (mergename == compare) {
157                 Inkscape::GC::release(tomerge);
158                 tomerge = NULL;
159                 submenu = menupass;
160                 break;
161             }
163             if (mergename < compare) {
164                 position = menupass->position();
165                 break;
166             }
167         } // for menu items
168     } // start != NULL
170     if (tomerge != NULL) {
171         base->appendChild(tomerge);
172         Inkscape::GC::release(tomerge);
173         if (position != -1)
174             tomerge->setPosition(position);
175     }
177     if (patern != NULL) {
178         if (submenu == NULL)
179             submenu = tomerge;
180         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
181     }
183     return;
186 Effect::~Effect (void)
188     if (get_last_effect() == this)
189         set_last_effect(NULL);
190     return;
193 bool
194 Effect::check (void)
196     if (!Extension::check()) {
197         /** \todo  Check to see if parent has this as its only child,
198                    if so, delete it too */
199         if (_menu_node != NULL)
200             sp_repr_unparent(_menu_node);
201         _menu_node = NULL;
202         return false;
203     }
204     return true;
207 bool
208 Effect::prefs (Inkscape::UI::View::View * doc)
210     if (_prefDialog != NULL) {
211         _prefDialog->raise();
212         return true;
213     }
215     if (!loaded())
216         set_state(Extension::STATE_LOADED);
217     if (!loaded()) return false;
219     sigc::signal<void> * changeSignal = new sigc::signal<void>;
221     Gtk::Widget * controls;
222         SPDesktop * spdesktop = (SPDesktop *)doc;
223         Implementation::ImplementationDocumentCache * docCache = imp->newDocCache(this, spdesktop->doc());
224     controls = imp->prefs_effect(this, doc, changeSignal, docCache);
226     ExecutionEnv executionEnv(this, doc, controls, changeSignal, NULL, docCache);
228     timer->lock();
229     executionEnv.run();
230     timer->unlock();
232     return true;
235 /**
236     \brief  The function that 'does' the effect itself
237     \param  doc  The Inkscape::UI::View::View to do the effect on
239     This function first insures that the extension is loaded, and if not,
240     loads it.  It then calls the implemention to do the actual work.  It
241     also resets the last effect pointer to be this effect.  Finally, it
242     executes a \c sp_document_done to commit the changes to the undo
243     stack.
244 */
245 void
246 Effect::effect (Inkscape::UI::View::View * doc)
248     //printf("Execute effect\n");
249     if (!loaded())
250         set_state(Extension::STATE_LOADED);
251     if (!loaded()) return;
254     ExecutionEnv executionEnv(this, doc, NULL);
255     executionEnv.run();
257     return;
260 /** \brief  Sets which effect was called last
261     \param in_effect  The effect that has been called
262     
263     This function sets the static variable \c _last_effect and it
264     ensures that the last effect verb is sensitive.
266     If the \c in_effect variable is \c NULL then the last effect
267     verb is made insesitive.
268 */
269 void
270 Effect::set_last_effect (Effect * in_effect)
272     if (in_effect == NULL) {
273         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
274         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
275     } else if (_last_effect == NULL) {
276         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
277         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
278     }
280     _last_effect = in_effect;
281     return;
284 #define  EFFECTS_LIST  "effects-list"
286 bool
287 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
289     if (menustruct == NULL) return false;
290     for (Inkscape::XML::Node * child = menustruct;
291             child != NULL;
292             child = child->next()) {
293         if (!strcmp(child->name(), EFFECTS_LIST)) {
294             _effects_list = child;
295             return true;
296         }
297         Inkscape::XML::Node * firstchild = child->firstChild();
298         if (firstchild != NULL)
299             if (find_effects_list(firstchild))
300                 return true;
301     }
302     return false;
305 Gtk::VBox *
306 Effect::get_info_widget(void)
308     return Extension::get_info_widget();
311 void
312 Effect::set_pref_dialog (PrefDialog * prefdialog)
314     _prefDialog = prefdialog;
315     if (_prefDialog == NULL) {
316         timer->unlock();
317     } else {
318         timer->lock();
319     }
320     return;
323 /** \brief  Create an action for a \c EffectVerb
324     \param  view  Which view the action should be created for
325     \return The built action.
327     Calls \c make_action_helper with the \c vector.
328 */
329 SPAction *
330 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
332     return make_action_helper(view, &vector, static_cast<void *>(this));
335 /** \brief  Decode the verb code and take appropriate action */
336 void
337 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
339     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
340 //  SPDocument * current_document = current_view->doc;
341     Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
342     Effect * effect = ev->_effect;
344     if (effect == NULL) return;
345     if (current_view == NULL) return;
347     if (ev->_showPrefs) {
348         effect->prefs(current_view);
349     } else {
350         effect->effect(current_view);
351     }
353     return;
356 /**
357  * Action vector to define functions called if a staticly defined file verb
358  * is called.
359  */
360 SPActionEventVector Effect::EffectVerb::vector =
361             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
364 } }  /* namespace Inkscape, Extension */
366 /*
367   Local Variables:
368   mode:c++
369   c-file-style:"stroustrup"
370   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
371   indent-tabs-mode:nil
372   fill-column:99
373   End:
374 */
375 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :