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());
227 return;
228 }
230 void
231 Effect::set_last_effect (Effect * in_effect)
232 {
233 if (in_effect == NULL) {
234 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
235 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
236 } else if (_last_effect == NULL) {
237 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
238 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
239 }
241 _last_effect = in_effect;
242 return;
243 }
245 #define EFFECTS_LIST "effects-list"
247 bool
248 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
249 {
250 if (menustruct == NULL) return false;
251 for (Inkscape::XML::Node * child = menustruct;
252 child != NULL;
253 child = child->next()) {
254 if (!strcmp(child->name(), EFFECTS_LIST)) {
255 _effects_list = child;
256 return true;
257 }
258 Inkscape::XML::Node * firstchild = child->firstChild();
259 if (firstchild != NULL)
260 if (find_effects_list(firstchild))
261 return true;
262 }
263 return false;
264 }
266 Gtk::VBox *
267 Effect::get_info_widget(void)
268 {
269 return Extension::get_info_widget();
270 }
272 /** \brief Create an action for a \c EffectVerb
273 \param view Which view the action should be created for
274 \return The built action.
276 Calls \c make_action_helper with the \c vector.
277 */
278 SPAction *
279 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
280 {
281 return make_action_helper(view, &vector, static_cast<void *>(_effect));
282 }
284 /** \brief Decode the verb code and take appropriate action */
285 void
286 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
287 {
288 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
289 // SPDocument * current_document = current_view->doc;
290 Effect * effect = reinterpret_cast<Effect *>(data);
292 if (effect == NULL) return;
293 if (current_view == NULL) return;
295 // std::cout << "Executing: " << effect->get_name() << std::endl;
296 if (effect->prefs(current_view))
297 effect->effect(current_view);
299 return;
300 }
302 /**
303 * Action vector to define functions called if a staticly defined file verb
304 * is called.
305 */
306 SPActionEventVector Effect::EffectVerb::vector =
307 {{NULL},Effect::EffectVerb::perform, NULL, NULL, NULL};
310 } } /* namespace Inkscape, Extension */
312 /*
313 Local Variables:
314 mode:c++
315 c-file-style:"stroustrup"
316 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
317 indent-tabs-mode:nil
318 fill-column:99
319 End:
320 */
321 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :