Code

LPE: add Paste LPE verb + menu item. add scale ratios to curve stitch and path-along...
[inkscape.git] / src / ui / dialog / livepatheffect-editor.cpp
1 /**\r
2  * \brief LivePathEffect dialog\r
3  *\r
4  * Authors:\r
5  *   Johan Engelen <j.b.c.engelen@utwente.nl>\r
6  *\r
7  * Copyright (C) 2007 Author\r
8  *\r
9  * Released under GNU GPL.  Read the file 'COPYING' for more information.\r
10  */\r
11 \r
12 #ifdef HAVE_CONFIG_H\r
13 # include <config.h>\r
14 #endif\r
15 \r
16 #include <glibmm/i18n.h>\r
17 #include "livepatheffect-editor.h"\r
18 #include "verbs.h"\r
19 #include "selection.h"\r
20 #include "sp-shape.h"\r
21 #include "sp-path.h"\r
22 #include "live_effects/effect.h"\r
23 #include "live_effects/lpeobject.h"\r
24 #include "gtkmm/widget.h"\r
25 #include <vector>\r
26 #include "inkscape.h"\r
27 #include "desktop-handles.h"\r
28 #include "desktop.h"\r
29 #include "document-private.h"\r
30 #include "xml/node.h"\r
31 #include "xml/document.h"\r
32 \r
33 namespace Inkscape {\r
34 class Application;\r
35 \r
36 namespace UI {\r
37 namespace Dialog {\r
38 \r
39 \r
40 /*####################\r
41  * Callback functions\r
42  */\r
43 static void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data)\r
44 {\r
45     LivePathEffectEditor *lpeeditor = static_cast<LivePathEffectEditor *>(data);\r
46     lpeeditor->onSelectionChanged(selection);\r
47 }\r
48 \r
49 static void lpeeditor_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)\r
50 {\r
51     lpeeditor_selection_changed (selection, data);\r
52 }\r
53 \r
54 \r
55 static void lpeeditor_desktop_change(Inkscape::Application*, SPDesktop* desktop, void *data)\r
56 {\r
57     if (!desktop) {\r
58         return;\r
59     }\r
60     LivePathEffectEditor* editor = reinterpret_cast<LivePathEffectEditor*>(data);\r
61     editor->setDesktop(desktop);\r
62 }\r
63 \r
64 \r
65 \r
66 /*#######################\r
67  * LivePathEffectEditor\r
68  */\r
69 LivePathEffectEditor::LivePathEffectEditor(Behavior::BehaviorFactory behavior_factory) \r
70     : Dialog (behavior_factory, "dialogs.livepatheffect", SP_VERB_DIALOG_LIVE_PATH_EFFECT),\r
71       combo_effecttype(Inkscape::LivePathEffect::LPETypeConverter),\r
72       button_apply(_("_Apply"), _("Apply chosen effect to selection")),\r
73       button_remove(_("_Remove"), _("Remove effect from selection")),\r
74       effectwidget(NULL),\r
75       explain_label("", Gtk::ALIGN_CENTER),\r
76       effectapplication_frame(_("Apply new effect")),\r
77       effectcontrol_frame(_("Current effect")),\r
78       current_desktop(NULL)\r
79 {\r
80     // Top level vbox\r
81     Gtk::VBox *vbox = get_vbox();\r
82     vbox->set_spacing(4);\r
83 \r
84     effectapplication_vbox.set_spacing(4);\r
85     effectcontrol_vbox.set_spacing(4);\r
86 \r
87     effectapplication_vbox.pack_start(combo_effecttype, true, true);\r
88     effectapplication_vbox.pack_start(button_apply, true, true);\r
89     effectapplication_vbox.pack_start(button_remove, true, true);\r
90     effectapplication_frame.add(effectapplication_vbox);\r
91 \r
92     effectcontrol_vbox.pack_start(explain_label, true, true);\r
93     effectcontrol_frame.add(effectcontrol_vbox);\r
94 \r
95     vbox->pack_start(effectapplication_frame, true, true);\r
96     vbox->pack_start(effectcontrol_frame, true, true);\r
97 \r
98     // connect callback functions to buttons\r
99     button_apply.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onApply));\r
100     button_remove.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onRemove));\r
101 \r
102     // connect callback functions to changes in selected desktop.\r
103     g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",\r
104                        G_CALLBACK(lpeeditor_desktop_change), this);\r
105 \r
106     g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop",\r
107                        G_CALLBACK(lpeeditor_desktop_change), this);\r
108 \r
109     setDesktop(SP_ACTIVE_DESKTOP);\r
110     show_all_children();\r
111 }\r
112 \r
113 LivePathEffectEditor::~LivePathEffectEditor() \r
114 {\r
115     if (effectwidget) {\r
116         effectcontrol_vbox.remove(*effectwidget);\r
117         effectwidget = NULL;\r
118     }\r
119 \r
120     if (current_desktop) {\r
121         selection_changed_connection.disconnect();\r
122         selection_modified_connection.disconnect();\r
123     }\r
124 }\r
125 \r
126 void\r
127 LivePathEffectEditor::showParams(LivePathEffect::Effect* effect)\r
128 {\r
129     if (effectwidget) {\r
130         effectcontrol_vbox.remove(*effectwidget);\r
131         effectwidget = NULL;\r
132     }\r
133 \r
134     explain_label.set_markup("<b>" + effect->getName() + "</b>");\r
135     effectwidget = effect->getWidget();\r
136     if (effectwidget) {\r
137         effectcontrol_vbox.pack_start(*effectwidget, true, true);\r
138     }\r
139 \r
140     effectcontrol_vbox.show_all_children();\r
141     // fixme: do resizing of dialog \r
142 }\r
143 \r
144 void\r
145 LivePathEffectEditor::showText(Glib::ustring const &str)\r
146 {\r
147     if (effectwidget) {\r
148         effectcontrol_vbox.remove(*effectwidget);\r
149         effectwidget = NULL;\r
150     }\r
151 \r
152     explain_label.set_label(str);\r
153 \r
154     // fixme: do resizing of dialog ?\r
155 }\r
156 \r
157 void\r
158 LivePathEffectEditor::set_sensitize_all(bool sensitive)\r
159 {\r
160     combo_effecttype.set_sensitive(sensitive);\r
161     button_apply.set_sensitive(sensitive);\r
162     button_remove.set_sensitive(sensitive);\r
163 }\r
164 \r
165 void\r
166 LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)\r
167 {\r
168     if ( sel && !sel->isEmpty() ) {\r
169         SPItem *item = sel->singleItem();\r
170         if ( item ) {\r
171             if ( SP_IS_SHAPE(item) ) {\r
172                 SPShape *shape = SP_SHAPE(item);\r
173                 LivePathEffectObject *lpeobj = sp_shape_get_livepatheffectobject(shape);\r
174                 set_sensitize_all(true);\r
175                 if (lpeobj) {\r
176                     if (lpeobj->lpe) {\r
177                         showParams(lpeobj->lpe);\r
178                     } else {\r
179                         showText(_("Unknown effect is applied"));\r
180                     }\r
181                 } else {\r
182                     showText(_("No effect applied"));\r
183                     button_remove.set_sensitive(false);\r
184                 }\r
185             } else {\r
186                 showText(_("Item is not a shape"));\r
187                 set_sensitize_all(false);\r
188             }\r
189         } else {\r
190             showText(_("Only one item can be selected"));\r
191             set_sensitize_all(false);\r
192         }\r
193     } else {\r
194         showText(_("Empty selection"));\r
195         set_sensitize_all(false);\r
196     }\r
197 }\r
198 \r
199 void \r
200 LivePathEffectEditor::setDesktop(SPDesktop *desktop)\r
201 {\r
202 \r
203     if ( desktop == current_desktop ) {\r
204         return;\r
205     }\r
206 \r
207     if (current_desktop) {\r
208         selection_changed_connection.disconnect();\r
209         selection_modified_connection.disconnect();\r
210     }\r
211 \r
212     current_desktop = desktop;\r
213     if (desktop) {\r
214         Inkscape::Selection *selection = sp_desktop_selection(desktop);\r
215         selection_changed_connection = selection->connectChanged(\r
216             sigc::bind (sigc::ptr_fun(&lpeeditor_selection_changed), this ) );\r
217         selection_modified_connection = selection->connectModified(\r
218             sigc::bind (sigc::ptr_fun(&lpeeditor_selection_modified), this ) );\r
219 \r
220         onSelectionChanged(selection);\r
221     } else {\r
222         onSelectionChanged(NULL);\r
223     }\r
224 }\r
225 \r
226 \r
227 \r
228 \r
229 /*########################################################################\r
230 # BUTTON CLICK HANDLERS    (callbacks)\r
231 ########################################################################*/\r
232 \r
233 // TODO:  factor out the effect applying code which can be called from anywhere. (selection-chemistry.cpp also needs it)\r
234 \r
235 void\r
236 LivePathEffectEditor::onApply()\r
237 {\r
238     Inkscape::Selection *sel = _getSelection();\r
239     if ( sel && !sel->isEmpty() ) {\r
240         SPItem *item = sel->singleItem();\r
241         if ( item && SP_IS_SHAPE(item) ) {\r
242             SPDocument *doc = current_desktop->doc();\r
243 \r
244             const Util::EnumData<LivePathEffect::EffectType>* data = combo_effecttype.get_active_data();\r
245             if (!data) return;\r
246 \r
247             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);\r
248             Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");\r
249             repr->setAttribute("effect", data->key.c_str() );\r
250 \r
251             SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute\r
252             const gchar * repr_id = repr->attribute("id");\r
253             Inkscape::GC::release(repr);\r
254 \r
255             gchar *href = g_strdup_printf("#%s", repr_id);\r
256             sp_shape_set_path_effect(SP_SHAPE(item), href);\r
257             g_free(href);\r
258 \r
259             // make sure there is an original-d for paths!!!\r
260             if ( SP_IS_PATH(item) ) {\r
261                 Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(item);\r
262                 if ( ! pathrepr->attribute("inkscape:original-d") ) {\r
263                     pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d"));\r
264                 }\r
265             }\r
266 \r
267             sp_document_done(doc, SP_VERB_DIALOG_LIVE_PATH_EFFECT, \r
268                              _("Create and apply live effect"));\r
269         }\r
270     }\r
271 }\r
272 \r
273 void\r
274 LivePathEffectEditor::onRemove()\r
275 {\r
276     Inkscape::Selection *sel = _getSelection();\r
277     if ( sel && !sel->isEmpty() ) {\r
278         SPItem *item = sel->singleItem();\r
279         if ( item && SP_IS_SHAPE(item) ) {\r
280             sp_shape_remove_path_effect(SP_SHAPE(item));\r
281             sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT, \r
282                                _("Remove live path effect") );\r
283         }\r
284     }\r
285 }\r
286 \r
287 \r
288 \r
289 } // namespace Dialog\r
290 } // namespace UI\r
291 } // namespace Inkscape\r
292 \r