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 } // children of "effect"
46 break; // there can only be one effect
47 } // find "effect"
48 } // children of "inkscape-extension"
49 } // if we have an XML file
51 if (_effects_list == NULL)
52 find_effects_list(inkscape_get_menus(INKSCAPE));
54 if (_effects_list != NULL) {
55 _menu_node = sp_repr_new("verb");
56 _menu_node->setAttribute("verb-id", this->get_id(), false);
58 merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
59 }
61 return;
62 }
64 void
65 Effect::merge_menu (Inkscape::XML::Node * base,
66 Inkscape::XML::Node * start,
67 Inkscape::XML::Node * patern,
68 Inkscape::XML::Node * mergee) {
69 Glib::ustring mergename;
70 Inkscape::XML::Node * tomerge = NULL;
71 Inkscape::XML::Node * submenu = NULL;
73 /* printf("Merge menu with '%s' '%s' '%s'\n",
74 base != NULL ? base->name() : "NULL",
75 patern != NULL ? patern->name() : "NULL",
76 mergee != NULL ? mergee->name() : "NULL"); */
78 if (patern == NULL) {
79 // Merge the verb name
80 tomerge = mergee;
81 mergename = _(this->get_name());
82 } else {
83 gchar const * menuname = patern->attribute("name");
84 if (menuname == NULL) menuname = patern->attribute("_name");
85 if (menuname == NULL) return;
87 tomerge = sp_repr_new("submenu");
88 tomerge->setAttribute("name", menuname, false);
90 mergename = _(menuname);
91 }
93 int position = -1;
95 if (start != NULL) {
96 Inkscape::XML::Node * menupass;
97 for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
98 gchar const * compare_char = NULL;
99 if (!strcmp(menupass->name(), "verb")) {
100 gchar const * verbid = menupass->attribute("verb-id");
101 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
102 if (verb == NULL) {
103 continue;
104 }
105 compare_char = verb->get_name();
106 } else if (!strcmp(menupass->name(), "submenu")) {
107 compare_char = menupass->attribute("name");
108 if (compare_char == NULL)
109 compare_char = menupass->attribute("_name");
110 }
112 /* This will cause us to skip tags we don't understand */
113 if (compare_char == NULL) {
114 continue;
115 }
117 Glib::ustring compare(_(compare_char));
119 if (mergename == compare) {
120 Inkscape::GC::release(tomerge);
121 tomerge = NULL;
122 submenu = menupass;
123 break;
124 }
126 if (mergename < compare) {
127 position = menupass->position();
128 break;
129 }
130 } // for menu items
131 } // start != NULL
133 if (tomerge != NULL) {
134 base->appendChild(tomerge);
135 Inkscape::GC::release(tomerge);
136 if (position != -1)
137 tomerge->setPosition(position);
138 }
140 if (patern != NULL) {
141 if (submenu == NULL)
142 submenu = tomerge;
143 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
144 }
146 return;
147 }
149 Effect::~Effect (void)
150 {
151 if (get_last_effect() == this)
152 set_last_effect(NULL);
153 return;
154 }
156 bool
157 Effect::check (void)
158 {
159 if (!Extension::check()) {
160 /** \todo Check to see if parent has this as its only child,
161 if so, delete it too */
162 if (_menu_node != NULL)
163 sp_repr_unparent(_menu_node);
164 _menu_node = NULL;
165 return false;
166 }
167 return true;
168 }
170 bool
171 Effect::prefs (Inkscape::UI::View::View * doc)
172 {
173 if (!loaded())
174 set_state(Extension::STATE_LOADED);
175 if (!loaded()) return false;
177 Gtk::Widget * controls;
178 controls = imp->prefs_effect(this, doc);
179 if (controls == NULL) {
180 // std::cout << "No preferences for Effect" << std::endl;
181 return true;
182 }
184 PrefDialog * dialog = new PrefDialog(this->get_name(), controls);
185 int response = dialog->run();
186 dialog->hide();
188 delete dialog;
190 if (response == Gtk::RESPONSE_OK) return true;
192 return false;
193 }
195 /**
196 \brief The function that 'does' the effect itself
197 \param doc The Inkscape::UI::View::View to do the effect on
199 This function first insures that the extension is loaded, and if not,
200 loads it. It then calls the implemention to do the actual work. It
201 also resets the last effect pointer to be this effect. Finally, it
202 executes a \c sp_document_done to commit the changes to the undo
203 stack.
204 */
205 void
206 Effect::effect (Inkscape::UI::View::View * doc)
207 {
208 if (!loaded())
209 set_state(Extension::STATE_LOADED);
210 if (!loaded()) return;
212 set_last_effect(this);
213 imp->effect(this, doc);
215 sp_document_done(doc->doc());
217 return;
218 }
220 void
221 Effect::set_last_effect (Effect * in_effect)
222 {
223 if (in_effect == NULL) {
224 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
225 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
226 } else if (_last_effect == NULL) {
227 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
228 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
229 }
231 _last_effect = in_effect;
232 return;
233 }
235 #define EFFECTS_LIST "effects-list"
237 bool
238 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
239 {
240 if (menustruct == NULL) return false;
241 for (Inkscape::XML::Node * child = menustruct;
242 child != NULL;
243 child = child->next()) {
244 if (!strcmp(child->name(), EFFECTS_LIST)) {
245 _effects_list = child;
246 return true;
247 }
248 Inkscape::XML::Node * firstchild = child->firstChild();
249 if (firstchild != NULL)
250 if (find_effects_list(firstchild))
251 return true;
252 }
253 return false;
254 }
256 /** \brief Create an action for a \c EffectVerb
257 \param view Which view the action should be created for
258 \return The built action.
260 Calls \c make_action_helper with the \c vector.
261 */
262 SPAction *
263 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
264 {
265 return make_action_helper(view, &vector, static_cast<void *>(_effect));
266 }
268 /** \brief Decode the verb code and take appropriate action */
269 void
270 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
271 {
272 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
273 // SPDocument * current_document = current_view->doc;
274 Effect * effect = reinterpret_cast<Effect *>(data);
276 if (effect == NULL) return;
277 if (current_view == NULL) return;
279 // std::cout << "Executing: " << effect->get_name() << std::endl;
280 if (effect->prefs(current_view))
281 effect->effect(current_view);
283 return;
284 }
286 /**
287 * Action vector to define functions called if a staticly defined file verb
288 * is called.
289 */
290 SPActionEventVector Effect::EffectVerb::vector =
291 {{NULL},Effect::EffectVerb::perform, NULL, NULL, NULL};
294 } } /* namespace Inkscape, Extension */
296 /*
297 Local Variables:
298 mode:c++
299 c-file-style:"stroustrup"
300 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
301 indent-tabs-mode:nil
302 fill-column:99
303 End:
304 */
305 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :