Code

a20f1c6e93dc4ef596e74100448a0137b1a34387
[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 "document.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 {
40     Inkscape::XML::Node * local_effects_menu = NULL;
42     // This is a weird hack
43     if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
44         return;
46     bool hidden = false;
48     no_doc = false;
50     if (repr != NULL) {
52         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
53             if (!strcmp(child->name(), "effect")) {
54                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
55                   no_doc = true;
56                 }
57                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
58                     if (!strcmp(effect_child->name(), "effects-menu")) {
59                         // printf("Found local effects menu in %s\n", this->get_name());
60                         local_effects_menu = sp_repr_children(effect_child);
61                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
62                             hidden = true;
63                         }
64                     }
65                     if (!strcmp(effect_child->name(), "menu-name") ||
66                             !strcmp(effect_child->name(), "_menu-name")) {
67                         // printf("Found local effects menu in %s\n", this->get_name());
68                         _verb.set_name(sp_repr_children(effect_child)->content());
69                     }
70                     if (!strcmp(effect_child->name(), "menu-tip") ||
71                             !strcmp(effect_child->name(), "_menu-tip")) {
72                         // printf("Found local effects menu in %s\n", this->get_name());
73                         _verb.set_tip(sp_repr_children(effect_child)->content());
74                     }
75                 } // children of "effect"
76                 break; // there can only be one effect
77             } // find "effect"
78         } // children of "inkscape-extension"
79     } // if we have an XML file
81     if (_effects_list == NULL && INKSCAPE != NULL) {
82         find_effects_list(inkscape_get_menus(INKSCAPE));
83     }
85     if (_effects_list != NULL) {
86         Inkscape::XML::Document *xml_doc;
87         xml_doc = _effects_list->document();
88         _menu_node = xml_doc->createElement("verb");
89         _menu_node->setAttribute("verb-id", this->get_id(), false);
91         if (!hidden)
92             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
93     }
95     return;
96 }
98 void
99 Effect::merge_menu (Inkscape::XML::Node * base,
100                     Inkscape::XML::Node * start,
101                     Inkscape::XML::Node * patern,
102                     Inkscape::XML::Node * mergee) {
103     Glib::ustring mergename;
104     Inkscape::XML::Node * tomerge = NULL;
105     Inkscape::XML::Node * submenu = NULL;
107     /* printf("Merge menu with '%s' '%s' '%s'\n",
108             base != NULL ? base->name() : "NULL",
109             patern != NULL ? patern->name() : "NULL",
110             mergee != NULL ? mergee->name() : "NULL"); */
112     if (patern == NULL) {
113         // Merge the verb name
114         tomerge = mergee;
115         mergename = _(this->get_name());
116     } else {
117         gchar const * menuname = patern->attribute("name");
118         if (menuname == NULL) menuname = patern->attribute("_name");
119         if (menuname == NULL) return;
120         
121         Inkscape::XML::Document *xml_doc;
122         xml_doc = base->document();
123         tomerge = xml_doc->createElement("submenu");
124         tomerge->setAttribute("name", menuname, false);
126         mergename = _(menuname);
127     }
129     int position = -1;
131     if (start != NULL) {
132         Inkscape::XML::Node * menupass;
133         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
134             gchar const * compare_char = NULL;
135             if (!strcmp(menupass->name(), "verb")) {
136                 gchar const * verbid = menupass->attribute("verb-id");
137                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
138                 if (verb == NULL) {
139                     continue;
140                 }
141                 compare_char = verb->get_name();
142             } else if (!strcmp(menupass->name(), "submenu")) {
143                 compare_char = menupass->attribute("name");
144                 if (compare_char == NULL)
145                     compare_char = menupass->attribute("_name");
146             }
148             /* This will cause us to skip tags we don't understand */
149             if (compare_char == NULL) {
150                 continue;
151             }
153             Glib::ustring compare(_(compare_char));
155             if (mergename == compare) {
156                 Inkscape::GC::release(tomerge);
157                 tomerge = NULL;
158                 submenu = menupass;
159                 break;
160             }
162             if (mergename < compare) {
163                 position = menupass->position();
164                 break;
165             }
166         } // for menu items
167     } // start != NULL
169     if (tomerge != NULL) {
170         base->appendChild(tomerge);
171         Inkscape::GC::release(tomerge);
172         if (position != -1)
173             tomerge->setPosition(position);
174     }
176     if (patern != NULL) {
177         if (submenu == NULL)
178             submenu = tomerge;
179         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
180     }
182     return;
185 Effect::~Effect (void)
187     if (get_last_effect() == this)
188         set_last_effect(NULL);
189     return;
192 bool
193 Effect::check (void)
195     if (!Extension::check()) {
196         /** \todo  Check to see if parent has this as its only child,
197                    if so, delete it too */
198         if (_menu_node != NULL)
199             sp_repr_unparent(_menu_node);
200         _menu_node = NULL;
201         return false;
202     }
203     return true;
206 bool
207 Effect::prefs (Inkscape::UI::View::View * doc)
209     if (!loaded())
210         set_state(Extension::STATE_LOADED);
211     if (!loaded()) return false;
213     sigc::signal<void> * changeSignal = new sigc::signal<void>;
215     Gtk::Widget * controls;
216     controls = imp->prefs_effect(this, doc, changeSignal);
218     ExecutionEnv executionEnv(this, doc, controls, changeSignal);
220     timer->lock();
221     executionEnv.run();
222     timer->unlock();
224     return true;
227 /**
228     \brief  The function that 'does' the effect itself
229     \param  doc  The Inkscape::UI::View::View to do the effect on
231     This function first insures that the extension is loaded, and if not,
232     loads it.  It then calls the implemention to do the actual work.  It
233     also resets the last effect pointer to be this effect.  Finally, it
234     executes a \c sp_document_done to commit the changes to the undo
235     stack.
236 */
237 void
238 Effect::effect (Inkscape::UI::View::View * doc)
240     printf("Execute effect\n");
241     if (!loaded())
242         set_state(Extension::STATE_LOADED);
243     if (!loaded()) return;
246     ExecutionEnv executionEnv(this, doc, NULL);
247     executionEnv.run();
249     return;
252 /** \brief  Sets which effect was called last
253     \param in_effect  The effect that has been called
254     
255     This function sets the static variable \c _last_effect and it
256     ensures that the last effect verb is sensitive.
258     If the \c in_effect variable is \c NULL then the last effect
259     verb is made insesitive.
260 */
261 void
262 Effect::set_last_effect (Effect * in_effect)
264     if (in_effect == NULL) {
265         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
266         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
267     } else if (_last_effect == NULL) {
268         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
269         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
270     }
272     _last_effect = in_effect;
273     return;
276 #define  EFFECTS_LIST  "effects-list"
278 bool
279 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
281     if (menustruct == NULL) return false;
282     for (Inkscape::XML::Node * child = menustruct;
283             child != NULL;
284             child = child->next()) {
285         if (!strcmp(child->name(), EFFECTS_LIST)) {
286             _effects_list = child;
287             return true;
288         }
289         Inkscape::XML::Node * firstchild = child->firstChild();
290         if (firstchild != NULL)
291             if (find_effects_list(firstchild))
292                 return true;
293     }
294     return false;
297 Gtk::VBox *
298 Effect::get_info_widget(void)
300     return Extension::get_info_widget();
303 /** \brief  Create an action for a \c EffectVerb
304     \param  view  Which view the action should be created for
305     \return The built action.
307     Calls \c make_action_helper with the \c vector.
308 */
309 SPAction *
310 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
312     return make_action_helper(view, &vector, static_cast<void *>(this));
315 /** \brief  Decode the verb code and take appropriate action */
316 void
317 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
319     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
320 //  SPDocument * current_document = current_view->doc;
321     Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
322     Effect * effect = ev->_effect;
324     if (effect == NULL) return;
325     if (current_view == NULL) return;
327     if (ev->_showPrefs) {
328         effect->prefs(current_view);
329     } else {
330         effect->effect(current_view);
331     }
333     return;
336 /**
337  * Action vector to define functions called if a staticly defined file verb
338  * is called.
339  */
340 SPActionEventVector Effect::EffectVerb::vector =
341             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
344 } }  /* namespace Inkscape, Extension */
346 /*
347   Local Variables:
348   mode:c++
349   c-file-style:"stroustrup"
350   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
351   indent-tabs-mode:nil
352   fill-column:99
353   End:
354 */
355 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :