Code

LPE STACKING!
[inkscape.git] / src / ui / dialog / livepatheffect-editor.cpp
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);
112   
113   // Add toolbar
114   //add_toolbar(toolbar);
115   toolbar.show_all(); //Show the toolbar and all its child widgets.
117       
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();
151 LivePathEffectEditor::~LivePathEffectEditor() 
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     }
164 void
165 LivePathEffectEditor::showParams(LivePathEffect::Effect* effect)
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
184 void
185 LivePathEffectEditor::showText(Glib::ustring const &str)
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 ?
199 void
200 LivePathEffectEditor::set_sensitize_all(bool sensitive)
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);
211 void
212 LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel)
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;
226                 
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     }
255 void
256 LivePathEffectEditor::effect_list_update(SPLPEItem *lpeitem)
258     effectlist_store->clear();
259     
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     }
271 void 
272 LivePathEffectEditor::setDesktop(SPDesktop *desktop)
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     }
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()
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     }
344 void
345 LivePathEffectEditor::onRemove()
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);
352             
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     }
361 void LivePathEffectEditor::onUp()
363         Inkscape::Selection *sel = _getSelection();
364     if ( sel && !sel->isEmpty() ) {
365         SPItem *item = sel->singleItem();
366         if ( item && SP_IS_LPE_ITEM(item) ) {
367             
368                         sp_lpe_item_up_current_path_effect(SP_LPE_ITEM(item));
369             
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     }
376         
379 void LivePathEffectEditor::onDown()
381         Inkscape::Selection *sel = _getSelection();
382     if ( sel && !sel->isEmpty() ) {
383         SPItem *item = sel->singleItem();
384         if ( item && SP_IS_LPE_ITEM(item) ) {
385             
386                         sp_lpe_item_down_current_path_effect(SP_LPE_ITEM(item));
387             
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     }
396 void LivePathEffectEditor::on_effect_selection_changed()
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     }
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 :