Code

5404672efe1d2451993c6e120c1d21760eefc65a
[inkscape.git] / src / dialogs / layers-panel.cpp
1 /*
2  * A simple panel for layers
3  *
4  * Authors:
5  *   Jon A. Cruz
6  *
7  * Copyright (C) 2006 Jon A. Cruz
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
15 #include "inkscape.h"
17 #include "layers-panel.h"
19 #include "layer-manager.h"
20 #include "verbs.h"
21 #include "helper/action.h"
23 #include "document.h"
24 #include "desktop.h"
25 #include "sp-object.h"
26 #include "sp-item.h"
27 #include "widgets/icon.h"
28 #include <gtkmm/widget.h>
30 //#define DUMP_LAYERS 1
32 namespace Inkscape {
33 namespace UI {
34 namespace Dialogs {
36 LayersPanel* LayersPanel::instance = 0;
38 LayersPanel& LayersPanel::getInstance()
39 {
40     if ( !instance ) {
41         instance = new LayersPanel();
42     }
44     return *instance;
45 }
47 enum {
48     COL_VISIBLE = 1,
49     COL_LOCKED
50 };
52 enum {
53     BUTTON_NEW = 0,
54     BUTTON_TOP,
55     BUTTON_BOTTOM,
56     BUTTON_UP,
57     BUTTON_DOWN,
58 //    BUTTON_DUPLICATE,
59     BUTTON_DELETE
60 };
62 void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* fallback )
63 {
64     bool set = false;
65     if ( desktop ) {
66         Verb *verb = Verb::get( code );
67         if ( verb ) {
68             SPAction *action = verb->get_action(desktop);
69             if ( action && action->image ) {
70                 GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image );
71                 gtk_widget_show( child );
72                 btn.add( *manage(Glib::wrap(child)) );
73                 set = true;
74             }
76             if ( action && action->tip ) {
77                 _tips.set_tip( btn, action->tip );
78             }
79         }
80     }
81     if ( !set && fallback ) {
82         btn.set_label( fallback );
83     }
84 }
86 void LayersPanel::_fireAction( unsigned int code )
87 {
88     if ( _desktop ) {
89         Verb *verb = Verb::get( code );
90         if ( verb ) {
91             SPAction *action = verb->get_action(_desktop);
92             if ( action ) {
93                 sp_action_perform( action, NULL );
94 //             } else {
95 //                 g_message("no action");
96             }
97 //         } else {
98 //             g_message("no verb for %u", code);
99         }
100 //     } else {
101 //         g_message("no active desktop");
102     }
105 //     SP_VERB_LAYER_NEXT,
106 //     SP_VERB_LAYER_PREV,
107 void LayersPanel::_takeAction( int val )
109     switch ( val ) {
110         case BUTTON_NEW:
111         {
112             _fireAction( SP_VERB_LAYER_NEW );
113         }
114         break;
115         case BUTTON_TOP:
116         {
117             _fireAction( SP_VERB_LAYER_TO_TOP );
118         }
119         break;
120         case BUTTON_BOTTOM:
121         {
122             _fireAction( SP_VERB_LAYER_TO_BOTTOM );
123         }
124         break;
125         case BUTTON_UP:
126         {
127             _fireAction( SP_VERB_LAYER_RAISE );
128         }
129         break;
130         case BUTTON_DOWN:
131         {
132             _fireAction( SP_VERB_LAYER_LOWER );
133         }
134         break;
135         case BUTTON_DELETE:
136         {
137             _fireAction( SP_VERB_LAYER_DELETE );
138         }
139         break;
140     }
142     if ( _desktop && _desktop->currentLayer() ) {
143         _selectLayer( _desktop->currentLayer() );
144     }
147 class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
149 public:
151     ModelColumns()
152     {
153         add(_colObject);
154         add(_colVisible);
155         add(_colLocked);
156         add(_colLabel);
157     }
158     virtual ~ModelColumns() {}
160     Gtk::TreeModelColumn<SPObject*> _colObject;
161     Gtk::TreeModelColumn<Glib::ustring> _colLabel;
162     Gtk::TreeModelColumn<bool> _colVisible;
163     Gtk::TreeModelColumn<bool> _colLocked;
164 };
167 static gboolean layers_panel_activated( GtkObject *object, GdkEvent * /*event*/, gpointer data )
169     if ( data )
170     {
171         LayersPanel* panel = reinterpret_cast<LayersPanel*>(data);
172         panel->setDesktop( SP_ACTIVE_DESKTOP );
173     }
175     return FALSE;
178 void LayersPanel::_selectLayer( SPObject *layer ) {
179     _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) );
182 bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer)
184     bool stopGoing = false;
186     Gtk::TreeModel::Row row = *iter;
187     Glib::ustring tmp = row[_model->_colLabel];
188     if ( layer == row[_model->_colObject] )
189     {
190         _tree.expand_to_path( path );
192         Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
193         select->select(iter);
195         stopGoing = true;
196     }
198     return stopGoing;
201 void LayersPanel::_layersChanged()
203 //    g_message("_layersChanged()");
204     SPDocument* document = _desktop->doc();
205     SPObject* root = document->root;
206     if ( root ) {
207         if ( _mgr && _mgr->includes( root ) ) {
208             _store->clear();
210 #if DUMP_LAYERS
211             g_message("root:%p  {%s}   [%s]", root, root->id, root->label() );
212 #endif // DUMP_LAYERS
213             unsigned int counter = _mgr->childCount(root);
214             for ( unsigned int i = 0; i < counter; i++ ) {
215                 SPObject *child = _mgr->nthChildOf(root, i);
216                 if ( child ) {
217 #if DUMP_LAYERS
218                     g_message("    layer:%p  {%s}   [%s]", child, child->id, child->label() );
219 #endif // DUMP_LAYERS
221                     Gtk::TreeModel::Row row = *(_store->append());
222                     row[_model->_colObject] = child;
223                     row[_model->_colLabel] = child->label() ? child->label() : SP_OBJECT_ID(child);
224                     row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false;
225                     row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false;
227                     // TODO - implement walking deeper, not hardcoded
229                     unsigned int counter2 = _mgr->childCount(child);
230                     for ( unsigned int i2 = 0; i2 < counter2; i2++ ) {
231                         SPObject *child2 = _mgr->nthChildOf(child, i2);
232                         if ( child2 ) {
233 #if DUMP_LAYERS
234                             g_message("        layer:%p  {%s}   [%s]", child, child->id, child->label() );
235 #endif // DUMP_LAYERS
236                             Gtk::TreeModel::Row row2 = *(_store->append(row.children()));
237                             row2[_model->_colObject] = child2;
238                             row2[_model->_colLabel] = child2->label() ? child2->label() : SP_OBJECT_ID(child2);
239                             row2[_model->_colVisible] = SP_IS_ITEM(child2) ? !SP_ITEM(child2)->isHidden() : false;
240                             row2[_model->_colLocked] = SP_IS_ITEM(child2) ? SP_ITEM(child2)->isLocked() : false;
241                         }
242                     }
244                 }
245             }
246         }
247     }
251 SPObject* LayersPanel::_selectedLayer()
253     SPObject* obj = 0;
255     Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
256     if ( iter ) {
257         Gtk::TreeModel::Row row = *iter;
258         obj = row[_model->_colObject];
259     }
261     return obj;
264 void LayersPanel::_checkTreeSelection()
266     bool sensitive = false;
267     if ( _tree.get_selection()->count_selected_rows() > 0 ) {
268         sensitive = true;
270         SPObject* inTree = _selectedLayer();
271         if ( inTree ) {
272             SPObject* curr = _desktop->currentLayer();
273             if ( curr != inTree ) {
274                 _layerChangedConnection.block();
275                 _desktop->setCurrentLayer(inTree);
276                 _layerChangedConnection.unblock();
277                 if ( _tree.get_selection()->count_selected_rows() < 1 ) {
278                     _selectLayer( inTree );
279                 }
280             }
281         }
282     } else {
283         sensitive = false;
284     }
286     for ( std::vector<Gtk::Button*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
287         (*it)->set_sensitive( sensitive );
288     }
291 void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
293     Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str);
294     Gtk::TreeModel::Row row = *iter;
296     Glib::ustring tmp = row[_model->_colLabel];
298     SPObject* obj = row[_model->_colObject];
299     SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0;
300     if ( item ) {
301         switch ( targetCol ) {
302             case COL_VISIBLE:
303             {
304                 bool newValue = !row[_model->_colVisible];
305                 row[_model->_colVisible] = newValue;
306                 item->setHidden( !newValue  );
307                 item->updateRepr();
308                 sp_document_done( _desktop->doc() );
309             }
310             break;
312             case COL_LOCKED:
313             {
314                 bool newValue = !row[_model->_colLocked];
315                 row[_model->_colLocked] = newValue;
316                 item->setLocked( newValue );
317                 item->updateRepr();
318                 sp_document_done( _desktop->doc() );
319             }
320             break;
321         }
322     }
326 /**
327  * Constructor
328  */
329 LayersPanel::LayersPanel() :
330     Inkscape::UI::Widget::Panel( "dialogs.layers" ),
331     _mgr(0),
332     _desktop(0),
333     _model(0)
335     ModelColumns *zoop = new ModelColumns();
336     _model = zoop;
338     _store = Gtk::TreeStore::create( *zoop );
340     Gtk::CellRendererToggle* cell = 0;
341     _tree.set_model( _store );
342     int visibleColNum = _tree.append_column("vis", _model->_colVisible) - 1;
343     int lockedColNum = _tree.append_column("lock", _model->_colLocked) - 1;
344     int nameColNum = _tree.append_column("Name", _model->_colLabel) - 1;
346     _tree.set_expander_column( *_tree.get_column(nameColNum) );
348     cell = dynamic_cast<Gtk::CellRendererToggle*>(_tree.get_column_cell_renderer(visibleColNum));
349     if ( cell ) {
350         cell->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) );
351         cell->property_activatable() = true;
352     }
354     cell = dynamic_cast<Gtk::CellRendererToggle*>(_tree.get_column_cell_renderer(lockedColNum));
355     if ( cell ) {
356         cell->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) );
357         cell->property_activatable() = true;
358     }
360     _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_checkTreeSelection) );
362     _getContents()->pack_start(_tree, Gtk::PACK_EXPAND_WIDGET);
365     _getContents()->pack_end(_buttonsRow, Gtk::PACK_SHRINK);
367     SPDesktop* targetDesktop = SP_ACTIVE_DESKTOP;
369     Gtk::Button* btn = manage( new Gtk::Button() );
370     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, "Ne" );
371     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) );
372     _buttonsRow.pack_start( *btn );
374     btn = manage( new Gtk::Button() );
375     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, "Top" );
376     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) );
377     _watching.push_back( btn );
378     _buttonsRow.pack_start( *btn );
380     btn = manage( new Gtk::Button() );
381     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, "Up" );
382     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) );
383     _watching.push_back( btn );
384     _buttonsRow.pack_start( *btn );
386     btn = manage( new Gtk::Button() );
387     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, "Dn" );
388     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) );
389     _watching.push_back( btn );
390     _buttonsRow.pack_start( *btn );
392     btn = manage( new Gtk::Button() );
393     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, "Btm" );
394     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) );
395     _watching.push_back( btn );
396     _buttonsRow.pack_start( *btn );
398 //     btn = manage( new Gtk::Button("Dup") );
399 //     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) );
400 //     _buttonsRow.pack_start( *btn );
402     btn = manage( new Gtk::Button() );
403     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, "X" );
404     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) );
405     _watching.push_back( btn );
406     _buttonsRow.pack_start( *btn );
409     for ( std::vector<Gtk::Button*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
410         (*it)->set_sensitive( false );
411     }
413     g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this );
416     setDesktop( targetDesktop );
420     show_all_children();
422     restorePanelPrefs();
425 LayersPanel::~LayersPanel()
427     if ( _model )
428     {
429         delete _model;
430     }
434 void LayersPanel::setDesktop( SPDesktop* desktop )
436     if ( desktop != _desktop ) {
437         _layerChangedConnection.disconnect();
438         _changedConnection.disconnect();
439         if ( _mgr ) {
440             _mgr = 0;
441         }
442         if ( _desktop ) {
443             _desktop = 0;
444         }
446         _desktop = SP_ACTIVE_DESKTOP;
447         if ( _desktop ) {
448             _layerChangedConnection = _desktop->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) );
450             setLabel( _desktop->doc()->name );
452             _mgr = _desktop->layer_manager;
453             if ( _mgr ) {
454                 _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) );
455             }
457             _layersChanged();
458             _selectLayer( _desktop->currentLayer() );
459         }
460     }
461 /*
462     GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" );
463     g_message( "layers list starts at %p", layers );
464     for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
465         SPObject *layer=static_cast<SPObject *>(iter->data);
466         g_message("  {%s}   [%s]", layer->id, layer->label() );
467     }
468 */
473 } //namespace Dialogs
474 } //namespace UI
475 } //namespace Inkscape
478 /*
479   Local Variables:
480   mode:c++
481   c-file-style:"stroustrup"
482   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
483   indent-tabs-mode:nil
484   fill-column:99
485   End:
486 */
487 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :