Code

patch from Gustav Broberg: undo annotations and history dialog
[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     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                             !strcmp(child_repr->name(), "_menu-name")) {
47                         // printf("Found local effects menu in %s\n", this->get_name());
48                         _verb.set_name(sp_repr_children(child_repr)->content());
49                     }
50                     if (!strcmp(child_repr->name(), "menu-tip") ||
51                             !strcmp(child_repr->name(), "_menu-tip")) {
52                         // printf("Found local effects menu in %s\n", this->get_name());
53                         _verb.set_tip(sp_repr_children(child_repr)->content());
54                     }
55                 } // children of "effect"
56                 break; // there can only be one effect
57             } // find "effect"
58         } // children of "inkscape-extension"
59     } // if we have an XML file
61     if (_effects_list == NULL)
62         find_effects_list(inkscape_get_menus(INKSCAPE));
64     if (_effects_list != NULL) {
65         _menu_node = sp_repr_new("verb");
66         _menu_node->setAttribute("verb-id", this->get_id(), false);
68         merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
69     }
71     return;
72 }
74 void
75 Effect::merge_menu (Inkscape::XML::Node * base,
76                     Inkscape::XML::Node * start,
77                     Inkscape::XML::Node * patern,
78                     Inkscape::XML::Node * mergee) {
79     Glib::ustring mergename;
80     Inkscape::XML::Node * tomerge = NULL;
81     Inkscape::XML::Node * submenu = NULL;
83     /* printf("Merge menu with '%s' '%s' '%s'\n",
84             base != NULL ? base->name() : "NULL",
85             patern != NULL ? patern->name() : "NULL",
86             mergee != NULL ? mergee->name() : "NULL"); */
88     if (patern == NULL) {
89         // Merge the verb name
90         tomerge = mergee;
91         mergename = _(this->get_name());
92     } else {
93         gchar const * menuname = patern->attribute("name");
94         if (menuname == NULL) menuname = patern->attribute("_name");
95         if (menuname == NULL) return;
97         tomerge = sp_repr_new("submenu");
98         tomerge->setAttribute("name", menuname, false);
100         mergename = _(menuname);
101     }
103     int position = -1;
105     if (start != NULL) {
106         Inkscape::XML::Node * menupass;
107         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
108             gchar const * compare_char = NULL;
109             if (!strcmp(menupass->name(), "verb")) {
110                 gchar const * verbid = menupass->attribute("verb-id");
111                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
112                 if (verb == NULL) {
113                     continue;
114                 }
115                 compare_char = verb->get_name();
116             } else if (!strcmp(menupass->name(), "submenu")) {
117                 compare_char = menupass->attribute("name");
118                 if (compare_char == NULL)
119                     compare_char = menupass->attribute("_name");
120             }
122             /* This will cause us to skip tags we don't understand */
123             if (compare_char == NULL) {
124                 continue;
125             }
127             Glib::ustring compare(_(compare_char));
129             if (mergename == compare) {
130                 Inkscape::GC::release(tomerge);
131                 tomerge = NULL;
132                 submenu = menupass;
133                 break;
134             }
136             if (mergename < compare) {
137                 position = menupass->position();
138                 break;
139             }
140         } // for menu items
141     } // start != NULL
143     if (tomerge != NULL) {
144         base->appendChild(tomerge);
145         Inkscape::GC::release(tomerge);
146         if (position != -1)
147             tomerge->setPosition(position);
148     }
150     if (patern != NULL) {
151         if (submenu == NULL)
152             submenu = tomerge;
153         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
154     }
156     return;
159 Effect::~Effect (void)
161     if (get_last_effect() == this)
162         set_last_effect(NULL);
163     return;
166 bool
167 Effect::check (void)
169     if (!Extension::check()) {
170         /** \todo  Check to see if parent has this as its only child,
171                    if so, delete it too */
172         if (_menu_node != NULL)
173             sp_repr_unparent(_menu_node);
174         _menu_node = NULL;
175         return false;
176     }
177     return true;
180 bool
181 Effect::prefs (Inkscape::UI::View::View * doc)
183     if (!loaded())
184         set_state(Extension::STATE_LOADED);
185     if (!loaded()) return false;
187     Gtk::Widget * controls;
188     controls = imp->prefs_effect(this, doc);
189     if (controls == NULL) {
190         // std::cout << "No preferences for Effect" << std::endl;
191         return true;
192     }
194     PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
195     int response = dialog->run();
196     dialog->hide();
198     delete dialog;
200     if (response == Gtk::RESPONSE_OK) return true;
202     return false;
205 /**
206     \brief  The function that 'does' the effect itself
207     \param  doc  The Inkscape::UI::View::View to do the effect on
209     This function first insures that the extension is loaded, and if not,
210     loads it.  It then calls the implemention to do the actual work.  It
211     also resets the last effect pointer to be this effect.  Finally, it
212     executes a \c sp_document_done to commit the changes to the undo
213     stack.
214 */
215 void
216 Effect::effect (Inkscape::UI::View::View * doc)
218     if (!loaded())
219         set_state(Extension::STATE_LOADED);
220     if (!loaded()) return;
222     set_last_effect(this);
223     imp->effect(this, doc);
225     sp_document_done(doc->doc(), SP_VERB_NONE, 
226                      /* TODO: annotate */ "effect.cpp:226");
228     return;
231 void
232 Effect::set_last_effect (Effect * in_effect)
234     if (in_effect == NULL) {
235         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
236         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
237     } else if (_last_effect == NULL) {
238         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
239         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
240     }
242     _last_effect = in_effect;
243     return;
246 #define  EFFECTS_LIST  "effects-list"
248 bool
249 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
251     if (menustruct == NULL) return false;
252     for (Inkscape::XML::Node * child = menustruct;
253             child != NULL;
254             child = child->next()) {
255         if (!strcmp(child->name(), EFFECTS_LIST)) {
256             _effects_list = child;
257             return true;
258         }
259         Inkscape::XML::Node * firstchild = child->firstChild();
260         if (firstchild != NULL)
261             if (find_effects_list(firstchild))
262                 return true;
263     }
264     return false;
267 Gtk::VBox *
268 Effect::get_info_widget(void)
270     return Extension::get_info_widget();
273 /** \brief  Create an action for a \c EffectVerb
274     \param  view  Which view the action should be created for
275     \return The built action.
277     Calls \c make_action_helper with the \c vector.
278 */
279 SPAction *
280 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
282     return make_action_helper(view, &vector, static_cast<void *>(_effect));
285 /** \brief  Decode the verb code and take appropriate action */
286 void
287 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
289     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
290 //  SPDocument * current_document = current_view->doc;
291     Effect * effect = reinterpret_cast<Effect *>(data);
293     if (effect == NULL) return;
294     if (current_view == NULL) return;
296     // std::cout << "Executing: " << effect->get_name() << std::endl;
297     if (effect->prefs(current_view))
298         effect->effect(current_view);
300     return;
303 /**
304  * Action vector to define functions called if a staticly defined file verb
305  * is called.
306  */
307 SPActionEventVector Effect::EffectVerb::vector =
308             {{NULL},Effect::EffectVerb::perform, NULL, NULL, NULL};
311 } }  /* namespace Inkscape, Extension */
313 /*
314   Local Variables:
315   mode:c++
316   c-file-style:"stroustrup"
317   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
318   indent-tabs-mode:nil
319   fill-column:99
320   End:
321 */
322 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :