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;
157 }
159 Effect::~Effect (void)
160 {
161 if (get_last_effect() == this)
162 set_last_effect(NULL);
163 return;
164 }
166 bool
167 Effect::check (void)
168 {
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;
178 }
180 bool
181 Effect::prefs (Inkscape::UI::View::View * doc)
182 {
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;
203 }
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)
217 {
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;
229 }
231 void
232 Effect::set_last_effect (Effect * in_effect)
233 {
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;
244 }
246 #define EFFECTS_LIST "effects-list"
248 bool
249 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
250 {
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;
265 }
267 Gtk::VBox *
268 Effect::get_info_widget(void)
269 {
270 return Extension::get_info_widget();
271 }
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)
281 {
282 return make_action_helper(view, &vector, static_cast<void *>(_effect));
283 }
285 /** \brief Decode the verb code and take appropriate action */
286 void
287 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
288 {
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;
301 }
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, 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 :