Code

4d13d37a258ffe840a9740e726f6ea8a9e7acadb
[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 <gtk/gtkstock.h>
17 #include "inkscape.h"
19 #include "layers-panel.h"
21 #include "layer-manager.h"
22 #include "verbs.h"
23 #include "helper/action.h"
25 #include "document.h"
26 #include "desktop.h"
27 #include "sp-object.h"
28 #include "sp-item.h"
29 #include "widgets/icon.h"
30 #include <gtkmm/widget.h>
32 //#define DUMP_LAYERS 1
34 namespace Inkscape {
35 namespace UI {
36 namespace Dialogs {
38 LayersPanel* LayersPanel::instance = 0;
40 LayersPanel& LayersPanel::getInstance()
41 {
42     if ( !instance ) {
43         instance = new LayersPanel();
44     }
46     return *instance;
47 }
49 enum {
50     COL_VISIBLE = 1,
51     COL_LOCKED
52 };
54 enum {
55     BUTTON_NEW = 0,
56     BUTTON_TOP,
57     BUTTON_BOTTOM,
58     BUTTON_UP,
59     BUTTON_DOWN,
60 //    BUTTON_DUPLICATE,
61     BUTTON_DELETE
62 };
64 void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback )
65 {
66     bool set = false;
68     if ( iconName ) {
69         GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName );
70         gtk_widget_show( child );
71         btn.add( *manage(Glib::wrap(child)) );
72         set = true;
73     }
75     if ( desktop ) {
76         Verb *verb = Verb::get( code );
77         if ( verb ) {
78             SPAction *action = verb->get_action(desktop);
79             if ( !set && action && action->image ) {
80                 GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image );
81                 gtk_widget_show( child );
82                 btn.add( *manage(Glib::wrap(child)) );
83                 set = true;
84             }
86             if ( action && action->tip ) {
87                 _tips.set_tip( btn, action->tip );
88             }
89         }
90     }
92     if ( !set && fallback ) {
93         btn.set_label( fallback );
94     }
95 }
97 void LayersPanel::_fireAction( unsigned int code )
98 {
99     if ( _desktop ) {
100         Verb *verb = Verb::get( code );
101         if ( verb ) {
102             SPAction *action = verb->get_action(_desktop);
103             if ( action ) {
104                 sp_action_perform( action, NULL );
105 //             } else {
106 //                 g_message("no action");
107             }
108 //         } else {
109 //             g_message("no verb for %u", code);
110         }
111 //     } else {
112 //         g_message("no active desktop");
113     }
116 //     SP_VERB_LAYER_NEXT,
117 //     SP_VERB_LAYER_PREV,
118 void LayersPanel::_takeAction( int val )
120     switch ( val ) {
121         case BUTTON_NEW:
122         {
123             _fireAction( SP_VERB_LAYER_NEW );
124         }
125         break;
126         case BUTTON_TOP:
127         {
128             _fireAction( SP_VERB_LAYER_TO_TOP );
129         }
130         break;
131         case BUTTON_BOTTOM:
132         {
133             _fireAction( SP_VERB_LAYER_TO_BOTTOM );
134         }
135         break;
136         case BUTTON_UP:
137         {
138             _fireAction( SP_VERB_LAYER_RAISE );
139         }
140         break;
141         case BUTTON_DOWN:
142         {
143             _fireAction( SP_VERB_LAYER_LOWER );
144         }
145         break;
146         case BUTTON_DELETE:
147         {
148             _fireAction( SP_VERB_LAYER_DELETE );
149         }
150         break;
151     }
153     if ( _desktop && _desktop->currentLayer() ) {
154         _selectLayer( _desktop->currentLayer() );
155     }
158 class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
160 public:
162     ModelColumns()
163     {
164         add(_colObject);
165         add(_colVisible);
166         add(_colLocked);
167         add(_colLabel);
168     }
169     virtual ~ModelColumns() {}
171     Gtk::TreeModelColumn<SPObject*> _colObject;
172     Gtk::TreeModelColumn<Glib::ustring> _colLabel;
173     Gtk::TreeModelColumn<bool> _colVisible;
174     Gtk::TreeModelColumn<bool> _colLocked;
175 };
178 static gboolean layers_panel_activated( GtkObject *object, GdkEvent * /*event*/, gpointer data )
180     if ( data )
181     {
182         LayersPanel* panel = reinterpret_cast<LayersPanel*>(data);
183         panel->setDesktop( SP_ACTIVE_DESKTOP );
184     }
186     return FALSE;
189 void LayersPanel::_selectLayer( SPObject *layer ) {
190     _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) );
193 bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer)
195     bool stopGoing = false;
197     Gtk::TreeModel::Row row = *iter;
198     Glib::ustring tmp = row[_model->_colLabel];
199     if ( layer == row[_model->_colObject] )
200     {
201         _tree.expand_to_path( path );
203         Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
204         select->select(iter);
206         stopGoing = true;
207     }
209     return stopGoing;
212 void LayersPanel::_layersChanged()
214 //    g_message("_layersChanged()");
215     SPDocument* document = _desktop->doc();
216     SPObject* root = document->root;
217     if ( root ) {
218         if ( _mgr && _mgr->includes( root ) ) {
219             _store->clear();
221 #if DUMP_LAYERS
222             g_message("root:%p  {%s}   [%s]", root, root->id, root->label() );
223 #endif // DUMP_LAYERS
224             unsigned int counter = _mgr->childCount(root);
225             for ( unsigned int i = 0; i < counter; i++ ) {
226                 SPObject *child = _mgr->nthChildOf(root, i);
227                 if ( child ) {
228 #if DUMP_LAYERS
229                     g_message("    layer:%p  {%s}   [%s]", child, child->id, child->label() );
230 #endif // DUMP_LAYERS
232                     Gtk::TreeModel::Row row = *(_store->prepend());
233                     row[_model->_colObject] = child;
234                     row[_model->_colLabel] = child->label() ? child->label() : SP_OBJECT_ID(child);
235                     row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false;
236                     row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false;
238                     // TODO - implement walking deeper, not hardcoded
240                     unsigned int counter2 = _mgr->childCount(child);
241                     for ( unsigned int i2 = 0; i2 < counter2; i2++ ) {
242                         SPObject *child2 = _mgr->nthChildOf(child, i2);
243                         if ( child2 ) {
244 #if DUMP_LAYERS
245                             g_message("        layer:%p  {%s}   [%s]", child, child->id, child->label() );
246 #endif // DUMP_LAYERS
247                             Gtk::TreeModel::Row row2 = *(_store->prepend(row.children()));
248                             row2[_model->_colObject] = child2;
249                             row2[_model->_colLabel] = child2->label() ? child2->label() : SP_OBJECT_ID(child2);
250                             row2[_model->_colVisible] = SP_IS_ITEM(child2) ? !SP_ITEM(child2)->isHidden() : false;
251                             row2[_model->_colLocked] = SP_IS_ITEM(child2) ? SP_ITEM(child2)->isLocked() : false;
252                         }
253                     }
255                 }
256             }
257         }
258     }
262 SPObject* LayersPanel::_selectedLayer()
264     SPObject* obj = 0;
266     Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
267     if ( iter ) {
268         Gtk::TreeModel::Row row = *iter;
269         obj = row[_model->_colObject];
270     }
272     return obj;
275 void LayersPanel::_checkTreeSelection()
277     bool sensitive = false;
278     if ( _tree.get_selection()->count_selected_rows() > 0 ) {
279         sensitive = true;
281         SPObject* inTree = _selectedLayer();
282         if ( inTree ) {
283             SPObject* curr = _desktop->currentLayer();
284             if ( curr != inTree ) {
285                 _layerChangedConnection.block();
286                 _desktop->setCurrentLayer(inTree);
287                 _layerChangedConnection.unblock();
288                 if ( _tree.get_selection()->count_selected_rows() < 1 ) {
289                     _selectLayer( inTree );
290                 }
291             }
292         }
293     } else {
294         sensitive = false;
295     }
297     for ( std::vector<Gtk::Button*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
298         (*it)->set_sensitive( sensitive );
299     }
302 void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
304     Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str);
305     Gtk::TreeModel::Row row = *iter;
307     Glib::ustring tmp = row[_model->_colLabel];
309     SPObject* obj = row[_model->_colObject];
310     SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0;
311     if ( item ) {
312         switch ( targetCol ) {
313             case COL_VISIBLE:
314             {
315                 bool newValue = !row[_model->_colVisible];
316                 row[_model->_colVisible] = newValue;
317                 item->setHidden( !newValue  );
318                 item->updateRepr();
319                 sp_document_done( _desktop->doc() );
320             }
321             break;
323             case COL_LOCKED:
324             {
325                 bool newValue = !row[_model->_colLocked];
326                 row[_model->_colLocked] = newValue;
327                 item->setLocked( newValue );
328                 item->updateRepr();
329                 sp_document_done( _desktop->doc() );
330             }
331             break;
332         }
333     }
337 /**
338  * Constructor
339  */
340 LayersPanel::LayersPanel() :
341     Inkscape::UI::Widget::Panel( "dialogs.layers" ),
342     _mgr(0),
343     _desktop(0),
344     _model(0)
346     ModelColumns *zoop = new ModelColumns();
347     _model = zoop;
349     _store = Gtk::TreeStore::create( *zoop );
351     Gtk::CellRendererToggle* cell = 0;
352     _tree.set_model( _store );
353     int visibleColNum = _tree.append_column("vis", _model->_colVisible) - 1;
354     int lockedColNum = _tree.append_column("lock", _model->_colLocked) - 1;
355     int nameColNum = _tree.append_column("Name", _model->_colLabel) - 1;
357     _tree.set_expander_column( *_tree.get_column(nameColNum) );
359     cell = dynamic_cast<Gtk::CellRendererToggle*>(_tree.get_column_cell_renderer(visibleColNum));
360     if ( cell ) {
361         cell->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) );
362         cell->property_activatable() = true;
363     }
365     cell = dynamic_cast<Gtk::CellRendererToggle*>(_tree.get_column_cell_renderer(lockedColNum));
366     if ( cell ) {
367         cell->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) );
368         cell->property_activatable() = true;
369     }
371     _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_checkTreeSelection) );
373     _getContents()->pack_start(_tree, Gtk::PACK_EXPAND_WIDGET);
376     _getContents()->pack_end(_buttonsRow, Gtk::PACK_SHRINK);
378     SPDesktop* targetDesktop = SP_ACTIVE_DESKTOP;
380     Gtk::Button* btn = manage( new Gtk::Button() );
381     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, "Ne" );
382     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) );
383     _buttonsRow.pack_start( *btn );
385     btn = manage( new Gtk::Button() );
386     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, "Top" );
387     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) );
388     _watching.push_back( btn );
389     _buttonsRow.pack_start( *btn );
391     btn = manage( new Gtk::Button() );
392     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up" );
393     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) );
394     _watching.push_back( btn );
395     _buttonsRow.pack_start( *btn );
397     btn = manage( new Gtk::Button() );
398     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Dn" );
399     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) );
400     _watching.push_back( btn );
401     _buttonsRow.pack_start( *btn );
403     btn = manage( new Gtk::Button() );
404     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, "Btm" );
405     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) );
406     _watching.push_back( btn );
407     _buttonsRow.pack_start( *btn );
409 //     btn = manage( new Gtk::Button("Dup") );
410 //     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) );
411 //     _buttonsRow.pack_start( *btn );
413     btn = manage( new Gtk::Button() );
414     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, "X" );
415     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) );
416     _watching.push_back( btn );
417     _buttonsRow.pack_start( *btn );
420     for ( std::vector<Gtk::Button*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
421         (*it)->set_sensitive( false );
422     }
424     g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this );
427     setDesktop( targetDesktop );
431     show_all_children();
433     restorePanelPrefs();
436 LayersPanel::~LayersPanel()
438     if ( _model )
439     {
440         delete _model;
441     }
445 void LayersPanel::setDesktop( SPDesktop* desktop )
447     if ( desktop != _desktop ) {
448         _layerChangedConnection.disconnect();
449         _changedConnection.disconnect();
450         if ( _mgr ) {
451             _mgr = 0;
452         }
453         if ( _desktop ) {
454             _desktop = 0;
455         }
457         _desktop = SP_ACTIVE_DESKTOP;
458         if ( _desktop ) {
459             _layerChangedConnection = _desktop->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) );
461             setLabel( _desktop->doc()->name );
463             _mgr = _desktop->layer_manager;
464             if ( _mgr ) {
465                 _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) );
466             }
468             _layersChanged();
469             _selectLayer( _desktop->currentLayer() );
470         }
471     }
472 /*
473     GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" );
474     g_message( "layers list starts at %p", layers );
475     for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
476         SPObject *layer=static_cast<SPObject *>(iter->data);
477         g_message("  {%s}   [%s]", layer->id, layer->label() );
478     }
479 */
484 } //namespace Dialogs
485 } //namespace UI
486 } //namespace Inkscape
489 /*
490   Local Variables:
491   mode:c++
492   c-file-style:"stroustrup"
493   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
494   indent-tabs-mode:nil
495   fill-column:99
496   End:
497 */
498 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :