Code

Fixed crash when draw height was zero.
[inkscape.git] / src / extension / effect.cpp
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     bool hidden = false;
37     no_doc = false;
39     if (repr != NULL) {
41         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
42             if (!strcmp(child->name(), "effect")) {
43                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
44                   no_doc = true;
45                 }
46                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
47                     if (!strcmp(effect_child->name(), "effects-menu")) {
48                         // printf("Found local effects menu in %s\n", this->get_name());
49                         local_effects_menu = sp_repr_children(effect_child);
50                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
51                             hidden = true;
52                         }
53                     }
54                     if (!strcmp(effect_child->name(), "menu-name") ||
55                             !strcmp(effect_child->name(), "_menu-name")) {
56                         // printf("Found local effects menu in %s\n", this->get_name());
57                         _verb.set_name(sp_repr_children(effect_child)->content());
58                     }
59                     if (!strcmp(effect_child->name(), "menu-tip") ||
60                             !strcmp(effect_child->name(), "_menu-tip")) {
61                         // printf("Found local effects menu in %s\n", this->get_name());
62                         _verb.set_tip(sp_repr_children(effect_child)->content());
63                     }
64                 } // children of "effect"
65                 break; // there can only be one effect
66             } // find "effect"
67         } // children of "inkscape-extension"
68     } // if we have an XML file
70     if (_effects_list == NULL)
71         find_effects_list(inkscape_get_menus(INKSCAPE));
73     if (_effects_list != NULL) {
74         Inkscape::XML::Document *xml_doc;
75         xml_doc = _effects_list->document();
76         _menu_node = xml_doc->createElement("verb");
77         _menu_node->setAttribute("verb-id", this->get_id(), false);
79         if (!hidden)
80             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
81     }
83     return;
84 }
86 void
87 Effect::merge_menu (Inkscape::XML::Node * base,
88                     Inkscape::XML::Node * start,
89                     Inkscape::XML::Node * patern,
90                     Inkscape::XML::Node * mergee) {
91     Glib::ustring mergename;
92     Inkscape::XML::Node * tomerge = NULL;
93     Inkscape::XML::Node * submenu = NULL;
95     /* printf("Merge menu with '%s' '%s' '%s'\n",
96             base != NULL ? base->name() : "NULL",
97             patern != NULL ? patern->name() : "NULL",
98             mergee != NULL ? mergee->name() : "NULL"); */
100     if (patern == NULL) {
101         // Merge the verb name
102         tomerge = mergee;
103         mergename = _(this->get_name());
104     } else {
105         gchar const * menuname = patern->attribute("name");
106         if (menuname == NULL) menuname = patern->attribute("_name");
107         if (menuname == NULL) return;
108         
109         Inkscape::XML::Document *xml_doc;
110         xml_doc = base->document();
111         tomerge = xml_doc->createElement("submenu");
112         tomerge->setAttribute("name", menuname, false);
114         mergename = _(menuname);
115     }
117     int position = -1;
119     if (start != NULL) {
120         Inkscape::XML::Node * menupass;
121         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
122             gchar const * compare_char = NULL;
123             if (!strcmp(menupass->name(), "verb")) {
124                 gchar const * verbid = menupass->attribute("verb-id");
125                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
126                 if (verb == NULL) {
127                     continue;
128                 }
129                 compare_char = verb->get_name();
130             } else if (!strcmp(menupass->name(), "submenu")) {
131                 compare_char = menupass->attribute("name");
132                 if (compare_char == NULL)
133                     compare_char = menupass->attribute("_name");
134             }
136             /* This will cause us to skip tags we don't understand */
137             if (compare_char == NULL) {
138                 continue;
139             }
141             Glib::ustring compare(_(compare_char));
143             if (mergename == compare) {
144                 Inkscape::GC::release(tomerge);
145                 tomerge = NULL;
146                 submenu = menupass;
147                 break;
148             }
150             if (mergename < compare) {
151                 position = menupass->position();
152                 break;
153             }
154         } // for menu items
155     } // start != NULL
157     if (tomerge != NULL) {
158         base->appendChild(tomerge);
159         Inkscape::GC::release(tomerge);
160         if (position != -1)
161             tomerge->setPosition(position);
162     }
164     if (patern != NULL) {
165         if (submenu == NULL)
166             submenu = tomerge;
167         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
168     }
170     return;
173 Effect::~Effect (void)
175     if (get_last_effect() == this)
176         set_last_effect(NULL);
177     return;
180 bool
181 Effect::check (void)
183     if (!Extension::check()) {
184         /** \todo  Check to see if parent has this as its only child,
185                    if so, delete it too */
186         if (_menu_node != NULL)
187             sp_repr_unparent(_menu_node);
188         _menu_node = NULL;
189         return false;
190     }
191     return true;
194 bool
195 Effect::prefs (Inkscape::UI::View::View * doc)
197     if (!loaded())
198         set_state(Extension::STATE_LOADED);
199     if (!loaded()) return false;
201     Gtk::Widget * controls;
202     controls = imp->prefs_effect(this, doc);
203     if (controls == NULL) {
204         // std::cout << "No preferences for Effect" << std::endl;
205         return true;
206     }
208     PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
209     int response = dialog->run();
210     dialog->hide();
212     delete dialog;
214     if (response == Gtk::RESPONSE_OK) return true;
216     return false;
219 /**
220     \brief  The function that 'does' the effect itself
221     \param  doc  The Inkscape::UI::View::View to do the effect on
223     This function first insures that the extension is loaded, and if not,
224     loads it.  It then calls the implemention to do the actual work.  It
225     also resets the last effect pointer to be this effect.  Finally, it
226     executes a \c sp_document_done to commit the changes to the undo
227     stack.
228 */
229 void
230 Effect::effect (Inkscape::UI::View::View * doc)
232     if (!loaded())
233         set_state(Extension::STATE_LOADED);
234     if (!loaded()) return;
236     set_last_effect(this);
237     imp->effect(this, doc);
239     sp_document_done(doc->doc(), SP_VERB_NONE, _(this->get_name()));
241     return;
244 void
245 Effect::set_last_effect (Effect * in_effect)
247     if (in_effect == NULL) {
248         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
249         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
250     } else if (_last_effect == NULL) {
251         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
252         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
253     }
255     _last_effect = in_effect;
256     return;
259 #define  EFFECTS_LIST  "effects-list"
261 bool
262 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
264     if (menustruct == NULL) return false;
265     for (Inkscape::XML::Node * child = menustruct;
266             child != NULL;
267             child = child->next()) {
268         if (!strcmp(child->name(), EFFECTS_LIST)) {
269             _effects_list = child;
270             return true;
271         }
272         Inkscape::XML::Node * firstchild = child->firstChild();
273         if (firstchild != NULL)
274             if (find_effects_list(firstchild))
275                 return true;
276     }
277     return false;
280 Gtk::VBox *
281 Effect::get_info_widget(void)
283     return Extension::get_info_widget();
286 /** \brief  Create an action for a \c EffectVerb
287     \param  view  Which view the action should be created for
288     \return The built action.
290     Calls \c make_action_helper with the \c vector.
291 */
292 SPAction *
293 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
295     return make_action_helper(view, &vector, static_cast<void *>(_effect));
298 /** \brief  Decode the verb code and take appropriate action */
299 void
300 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
302     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
303 //  SPDocument * current_document = current_view->doc;
304     Effect * effect = reinterpret_cast<Effect *>(data);
306     if (effect == NULL) return;
307     if (current_view == NULL) return;
309     // std::cout << "Executing: " << effect->get_name() << std::endl;
310     if (effect->prefs(current_view))
311         effect->effect(current_view);
313     return;
316 /**
317  * Action vector to define functions called if a staticly defined file verb
318  * is called.
319  */
320 SPActionEventVector Effect::EffectVerb::vector =
321             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
324 } }  /* namespace Inkscape, Extension */
326 /*
327   Local Variables:
328   mode:c++
329   c-file-style:"stroustrup"
330   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
331   indent-tabs-mode:nil
332   fill-column:99
333   End:
334 */
335 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :