4d13d37a258ffe840a9740e726f6ea8a9e7acadb
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 }
114 }
116 // SP_VERB_LAYER_NEXT,
117 // SP_VERB_LAYER_PREV,
118 void LayersPanel::_takeAction( int val )
119 {
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 }
156 }
158 class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
159 {
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 )
179 {
180 if ( data )
181 {
182 LayersPanel* panel = reinterpret_cast<LayersPanel*>(data);
183 panel->setDesktop( SP_ACTIVE_DESKTOP );
184 }
186 return FALSE;
187 }
189 void LayersPanel::_selectLayer( SPObject *layer ) {
190 _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) );
191 }
193 bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer)
194 {
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;
210 }
212 void LayersPanel::_layersChanged()
213 {
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 }
260 }
262 SPObject* LayersPanel::_selectedLayer()
263 {
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;
273 }
275 void LayersPanel::_checkTreeSelection()
276 {
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 }
300 }
302 void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
303 {
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 }
334 }
337 /**
338 * Constructor
339 */
340 LayersPanel::LayersPanel() :
341 Inkscape::UI::Widget::Panel( "dialogs.layers" ),
342 _mgr(0),
343 _desktop(0),
344 _model(0)
345 {
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();
434 }
436 LayersPanel::~LayersPanel()
437 {
438 if ( _model )
439 {
440 delete _model;
441 }
442 }
445 void LayersPanel::setDesktop( SPDesktop* desktop )
446 {
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 */
480 }
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 :