c92d015f53f1e67e41b7e66c3a942405ca00557c
1 /**
2 * \brief LivePathEffect dialog
3 *
4 * Authors:
5 * Johan Engelen <j.b.c.engelen@utwente.nl>
6 * Steren Giannini <steren.giannini@gmail.com>
7 * Bastien Bouclet <bgkweb@gmail.com>
8 *
9 * Copyright (C) 2007 Author
10 *
11 * Released under GNU GPL. Read the file 'COPYING' for more information.
12 */
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
18 #include <glibmm/i18n.h>
19 #include "livepatheffect-editor.h"
20 #include "verbs.h"
21 #include "selection.h"
22 #include "sp-shape.h"
23 #include "sp-item-group.h"
24 #include "sp-path.h"
25 #include "sp-rect.h"
26 #include "sp-lpe-item.h"
27 #include "path-chemistry.h"
28 #include "live_effects/effect.h"
29 #include "live_effects/lpeobject.h"
30 #include "gtkmm/widget.h"
31 #include <vector>
32 #include "inkscape.h"
33 #include "desktop-handles.h"
34 #include "desktop.h"
35 #include "document-private.h"
36 #include "xml/node.h"
37 #include "xml/document.h"
38 #include <gtkmm/stock.h>
39 #include <gtkmm/toolbar.h>
41 #include "live_effects/lpeobject-reference.h"
43 namespace Inkscape {
44 class Application;
46 namespace UI {
47 namespace Dialog {
50 /*####################
51 * Callback functions
52 */
53 static void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data)
54 {
55 LivePathEffectEditor *lpeeditor = static_cast<LivePathEffectEditor *>(data);
56 lpeeditor->onSelectionChanged(selection);
57 }
60 /*#######################
61 * LivePathEffectEditor
62 */
64 LivePathEffectEditor::LivePathEffectEditor()
65 : UI::Widget::Panel("", "dialogs.livepatheffect", SP_VERB_DIALOG_LIVE_PATH_EFFECT),
66 combo_effecttype(Inkscape::LivePathEffect::LPETypeConverter),
67 effectwidget(NULL),
68 explain_label("", Gtk::ALIGN_CENTER),
69 effectapplication_frame(_("Apply new effect")),
70 effectcontrol_frame(_("Current effect")),
71 effectlist_frame(_("Effect list")),
72 button_up(Gtk::Stock::GO_UP),
73 button_down(Gtk::Stock::GO_DOWN),
74 button_apply(Gtk::Stock::ADD),
75 button_remove(Gtk::Stock::REMOVE),
76 current_desktop(NULL),
77 current_lpeitem(NULL)
78 {
79 Gtk::Box *contents = _getContents();
80 contents->set_spacing(4);
82 //Add the TreeView, inside a ScrolledWindow, with the button underneath:
83 scrolled_window.add(effectlist_view);
84 //Only show the scrollbars when they are necessary:
85 scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
87 effectapplication_hbox.set_spacing(4);
88 effectcontrol_vbox.set_spacing(4);
89 effectlist_vbox.set_spacing(4);
91 effectapplication_hbox.pack_start(combo_effecttype, true, true);
92 effectapplication_hbox.pack_start(button_apply, true, true);
93 effectapplication_frame.add(effectapplication_hbox);
95 effectlist_vbox.pack_start(scrolled_window, Gtk::PACK_EXPAND_WIDGET);
96 effectlist_vbox.pack_end(toolbar, Gtk::PACK_SHRINK);
97 // effectlist_vbox.pack_end(button_hbox, Gtk::PACK_SHRINK);
98 effectlist_frame.add(effectlist_vbox);
100 effectcontrol_vbox.pack_start(explain_label, true, true);
101 effectcontrol_frame.add(effectcontrol_vbox);
103 // button_hbox.pack_start(button_up, true, true);
104 // button_hbox.pack_start(button_down, true, true);
105 // button_hbox.pack_end(button_remove, true, true);
106 toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS);
107 // Add toolbar items to toolbar
108 toolbar.append(button_up);
109 toolbar.append(button_down);
110 toolbar.append(button_remove);
113 // Add toolbar
114 //add_toolbar(toolbar);
115 toolbar.show_all(); //Show the toolbar and all its child widgets.
118 //Create the Tree model:
119 effectlist_store = Gtk::ListStore::create(columns);
120 effectlist_view.set_model(effectlist_store);
122 effectlist_view.set_rules_hint();
123 effectlist_view.set_headers_clickable(true);
124 effectlist_view.set_headers_visible(true);
126 // Handle tree selections
127 effectlist_selection = effectlist_view.get_selection();
128 effectlist_selection->signal_changed().connect( sigc::mem_fun(*this, &LivePathEffectEditor::on_effect_selection_changed) );
130 effectlist_view.set_headers_visible(false);
131 //Add the TreeView's view columns:
132 effectlist_view.append_column("Effect", columns.col_name);
135 contents->pack_start(effectapplication_frame, false, false);
136 contents->pack_start(effectlist_frame, true, true);
137 contents->pack_start(effectcontrol_frame, false, false);
139 // connect callback functions to buttons
140 button_apply.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onApply));
141 button_remove.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onRemove));
143 button_up.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onUp));
144 button_down.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectEditor::onDown));
146 show_all_children();
148 //button_remove.hide();
149 }
151 LivePathEffectEditor::~LivePathEffectEditor()
152 {
153 if (effectwidget) {
154 effectcontrol_vbox.remove(*effectwidget);
155 delete effectwidget;
156 effectwidget = NULL;
157 }
159 if (current_desktop) {
160 selection_changed_connection.disconnect();
161 }
162 }
164 void
165 LivePathEffectEditor::showParams(LivePathEffect::Effect* effect)
166 {
167 if (effectwidget) {
168 effectcontrol_vbox.remove(*effectwidget);
169 delete effectwidget;
170 effectwidget = NULL;
171 }
173 explain_label.set_markup("<b>" + effect->getName() + "</b>");
174 effectwidget = effect->newWidget(&tooltips);
175 if (effectwidget) {
176 effectcontrol_vbox.pack_start(*effectwidget, true, true);
177 }
178 button_remove.show();
180 effectcontrol_vbox.show_all_children();
181 // fixme: add resizing of dialog
182 }
184 void
185 LivePathEffectEditor::showText(Glib::ustring const &str)
186 {
187 if (effectwidget) {
188 effectcontrol_vbox.remove(*effectwidget);
189 delete effectwidget;
190 effectwidget = NULL;
191 }
193 explain_label.set_label(str);
194 //button_remove.hide();
196 // fixme: do resizing of dialog ?
197 }
199 void
200 LivePathEffectEditor::set_sensitize_all(bool sensitive)
201 {
202 combo_effecttype.set_sensitive(sensitive);
203 button_apply.set_sensitive(sensitive);
204 button_remove.set_sensitive(sensitive);
205 effectlist_view.set_sensitive(sensitive);
206 button_up.set_sensitive(sensitive);
207 button_down.set_sensitive(sensitive);
208 }
211 void
212 LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
213 {
214 effectlist_store->clear();
215 current_lpeitem = NULL;
217 if ( sel && !sel->isEmpty() ) {
218 SPItem *item = sel->singleItem();
219 if ( item ) {
220 if ( SP_IS_LPE_ITEM(item) ) {
221 SPLPEItem *lpeitem = SP_LPE_ITEM(item);
223 effect_list_update(lpeitem);
225 current_lpeitem = lpeitem;
227 set_sensitize_all(true);
228 if ( sp_lpe_item_has_path_effect(lpeitem) ) {
229 Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(lpeitem);
230 if (lpe) {
231 showParams(lpe);
232 } else {
233 showText(_("Unknown effect is applied"));
234 }
235 } else {
236 showText(_("No effect applied"));
237 button_remove.set_sensitive(false);
238 }
239 }
240 else
241 {
242 showText(_("Item is not compound by paths"));
243 set_sensitize_all(false);
244 }
245 } else {
246 showText(_("Only one item can be selected"));
247 set_sensitize_all(false);
248 }
249 } else {
250 showText(_("Empty selection"));
251 set_sensitize_all(false);
252 }
253 }
255 void
256 LivePathEffectEditor::effect_list_update(SPLPEItem *lpeitem)
257 {
258 effectlist_store->clear();
260 PathEffectList effectlist = sp_lpe_item_get_effect_list(lpeitem);
261 PathEffectList::iterator it;
262 for( it = effectlist.begin() ; it!=effectlist.end(); it++ )
263 {
264 Gtk::TreeModel::Row row = *(effectlist_store->append());
265 row[columns.col_name] = (*it)->lpeobject->lpe->getName();
266 row[columns.lperef] = *it;
267 }
268 }
271 void
272 LivePathEffectEditor::setDesktop(SPDesktop *desktop)
273 {
274 Panel::setDesktop(desktop);
276 if ( desktop == current_desktop ) {
277 return;
278 }
280 if (current_desktop) {
281 selection_changed_connection.disconnect();
282 }
284 current_desktop = desktop;
285 if (desktop) {
286 Inkscape::Selection *selection = sp_desktop_selection(desktop);
287 selection_changed_connection = selection->connectChanged(
288 sigc::bind (sigc::ptr_fun(&lpeeditor_selection_changed), this ) );
290 onSelectionChanged(selection);
291 } else {
292 onSelectionChanged(NULL);
293 }
294 }
299 /*########################################################################
300 # BUTTON CLICK HANDLERS (callbacks)
301 ########################################################################*/
303 // TODO: factor out the effect applying code which can be called from anywhere. (selection-chemistry.cpp also needs it)
305 void
306 LivePathEffectEditor::onApply()
307 {
308 Inkscape::Selection *sel = _getSelection();
309 if ( sel && !sel->isEmpty() ) {
310 SPItem *item = sel->singleItem();
311 if ( item && SP_IS_LPE_ITEM(item) ) {
312 SPDocument *doc = current_desktop->doc();
314 const Util::EnumData<LivePathEffect::EffectType>* data = combo_effecttype.get_active_data();
315 if (!data) return;
317 // If item is a SPRect, convert it to path first:
318 if ( SP_IS_RECT(item) ) {
319 sp_selected_path_to_curves(false);
320 item = sel->singleItem(); // get new item
321 }
323 // Path effect definition
324 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
325 Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
326 repr->setAttribute("effect", data->key.c_str() );
328 SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
329 const gchar * repr_id = repr->attribute("id");
330 Inkscape::GC::release(repr);
332 gchar *href = g_strdup_printf("#%s", repr_id);
333 sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
334 g_free(href);
336 sp_document_done(doc, SP_VERB_DIALOG_LIVE_PATH_EFFECT,
337 _("Create and apply path effect"));
339 onSelectionChanged(sel);
340 }
341 }
342 }
344 void
345 LivePathEffectEditor::onRemove()
346 {
347 Inkscape::Selection *sel = _getSelection();
348 if ( sel && !sel->isEmpty() ) {
349 SPItem *item = sel->singleItem();
350 if ( item && SP_IS_LPE_ITEM(item) ) {
351 sp_lpe_item_remove_current_path_effect(SP_LPE_ITEM(item), false);
353 sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
354 _("Remove path effect") );
356 effect_list_update(SP_LPE_ITEM(item));
357 }
358 }
359 }
361 void LivePathEffectEditor::onUp()
362 {
363 Inkscape::Selection *sel = _getSelection();
364 if ( sel && !sel->isEmpty() ) {
365 SPItem *item = sel->singleItem();
366 if ( item && SP_IS_LPE_ITEM(item) ) {
368 sp_lpe_item_up_current_path_effect(SP_LPE_ITEM(item));
370 sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
371 _("Remove path effect") );
373 effect_list_update(SP_LPE_ITEM(item));
374 }
375 }
377 }
379 void LivePathEffectEditor::onDown()
380 {
381 Inkscape::Selection *sel = _getSelection();
382 if ( sel && !sel->isEmpty() ) {
383 SPItem *item = sel->singleItem();
384 if ( item && SP_IS_LPE_ITEM(item) ) {
386 sp_lpe_item_down_current_path_effect(SP_LPE_ITEM(item));
388 sp_document_done ( sp_desktop_document (current_desktop), SP_VERB_DIALOG_LIVE_PATH_EFFECT,
389 _("Remove path effect") );
391 effect_list_update(SP_LPE_ITEM(item));
392 }
393 }
394 }
396 void LivePathEffectEditor::on_effect_selection_changed()
397 {
398 Glib::RefPtr<Gtk::TreeSelection> sel = effectlist_view.get_selection();
399 if (sel->count_selected_rows () == 0)
400 return;
402 Gtk::TreeModel::iterator it = sel->get_selected();
403 LivePathEffect::LPEObjectReference * lperef = (*it)[columns.lperef];
405 if (lperef && current_lpeitem) {
406 sp_lpe_item_set_current_path_effect(current_lpeitem, lperef);
407 showParams(lperef->lpeobject->lpe);
408 }
409 }
412 } // namespace Dialog
413 } // namespace UI
414 } // namespace Inkscape
416 /*
417 Local Variables:
418 mode:c++
419 c-file-style:"stroustrup"
420 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
421 indent-tabs-mode:nil
422 fill-column:99
423 End:
424 */
425 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :