1 /*
2 * A simple panel for layers
3 *
4 * Authors:
5 * Jon A. Cruz
6 * Abhishek Sharma
7 *
8 * Copyright (C) 2006,2010 Jon A. Cruz
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
16 #include <gtk/gtkstock.h>
17 #include <gtk/gtkmain.h>
18 #include <gtkmm/widget.h>
19 #include <gtkmm/icontheme.h>
20 #include <glibmm/i18n.h>
22 #include "desktop.h"
23 #include "desktop-style.h"
24 #include "document.h"
25 #include "helper/action.h"
26 #include "inkscape.h"
27 #include "layer-fns.h"
28 #include "layer-manager.h"
29 #include "preferences.h"
30 #include "sp-item.h"
31 #include "sp-object.h"
32 #include "svg/css-ostringstream.h"
33 #include "ui/icon-names.h"
34 #include "ui/widget/imagetoggler.h"
35 #include "verbs.h"
36 #include "widgets/icon.h"
37 #include "xml/repr.h"
39 #include "layers.h"
41 //#define DUMP_LAYERS 1
43 namespace Inkscape {
44 namespace UI {
45 namespace Dialog {
47 LayersPanel& LayersPanel::getInstance()
48 {
49 return *new LayersPanel();
50 }
52 enum {
53 COL_VISIBLE = 1,
54 COL_LOCKED
55 };
57 enum {
58 BUTTON_NEW = 0,
59 BUTTON_RENAME,
60 BUTTON_TOP,
61 BUTTON_BOTTOM,
62 BUTTON_UP,
63 BUTTON_DOWN,
64 BUTTON_DUPLICATE,
65 BUTTON_DELETE,
66 BUTTON_SOLO
67 };
69 class LayersPanel::InternalUIBounce
70 {
71 public:
72 int _actionCode;
73 SPObject* _target;
74 };
76 void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback )
77 {
78 bool set = false;
80 if ( iconName ) {
81 GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName );
82 gtk_widget_show( child );
83 btn.add( *manage(Glib::wrap(child)) );
84 set = true;
85 }
87 if ( desktop ) {
88 Verb *verb = Verb::get( code );
89 if ( verb ) {
90 SPAction *action = verb->get_action(desktop);
91 if ( !set && action && action->image ) {
92 GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image );
93 gtk_widget_show( child );
94 btn.add( *manage(Glib::wrap(child)) );
95 set = true;
96 }
98 if ( action && action->tip ) {
99 _tips.set_tip( btn, action->tip );
100 }
101 }
102 }
104 if ( !set && fallback ) {
105 btn.set_label( fallback );
106 }
107 }
110 Gtk::MenuItem& LayersPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id )
111 {
112 GtkWidget* iconWidget = 0;
113 const char* label = 0;
115 if ( iconName ) {
116 iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName );
117 }
119 if ( desktop ) {
120 Verb *verb = Verb::get( code );
121 if ( verb ) {
122 SPAction *action = verb->get_action(desktop);
123 if ( !iconWidget && action && action->image ) {
124 iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image );
125 }
127 if ( action ) {
128 label = action->name;
129 }
130 }
131 }
133 if ( !label && fallback ) {
134 label = fallback;
135 }
137 Gtk::Widget* wrapped = 0;
138 if ( iconWidget ) {
139 wrapped = manage(Glib::wrap(iconWidget));
140 wrapped->show();
141 }
145 Gtk::Menu::MenuList& menulist = _popupMenu.items();
147 if ( wrapped ) {
148 menulist.push_back( Gtk::Menu_Helpers::ImageMenuElem( label, *wrapped, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) );
149 } else {
150 menulist.push_back( Gtk::Menu_Helpers::MenuElem( label, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) );
151 }
152 return menulist.back();
153 }
155 void LayersPanel::_fireAction( unsigned int code )
156 {
157 if ( _desktop ) {
158 Verb *verb = Verb::get( code );
159 if ( verb ) {
160 SPAction *action = verb->get_action(_desktop);
161 if ( action ) {
162 sp_action_perform( action, NULL );
163 // } else {
164 // g_message("no action");
165 }
166 // } else {
167 // g_message("no verb for %u", code);
168 }
169 // } else {
170 // g_message("no active desktop");
171 }
172 }
174 // SP_VERB_LAYER_NEXT,
175 // SP_VERB_LAYER_PREV,
176 void LayersPanel::_takeAction( int val )
177 {
178 if ( !_pending ) {
179 _pending = new InternalUIBounce();
180 _pending->_actionCode = val;
181 _pending->_target = _selectedLayer();
182 Glib::signal_timeout().connect( sigc::mem_fun(*this, &LayersPanel::_executeAction), 0 );
183 }
184 }
186 bool LayersPanel::_executeAction()
187 {
188 // Make sure selected layer hasn't changed since the action was triggered
189 if ( _pending
190 && (
191 (_pending->_actionCode == BUTTON_NEW)
192 || !( (_desktop && _desktop->currentLayer())
193 && (_desktop->currentLayer() != _pending->_target)
194 )
195 )
196 ) {
197 int val = _pending->_actionCode;
198 // SPObject* target = _pending->_target;
200 switch ( val ) {
201 case BUTTON_NEW:
202 {
203 _fireAction( SP_VERB_LAYER_NEW );
204 }
205 break;
206 case BUTTON_RENAME:
207 {
208 _fireAction( SP_VERB_LAYER_RENAME );
209 }
210 break;
211 case BUTTON_TOP:
212 {
213 _fireAction( SP_VERB_LAYER_TO_TOP );
214 }
215 break;
216 case BUTTON_BOTTOM:
217 {
218 _fireAction( SP_VERB_LAYER_TO_BOTTOM );
219 }
220 break;
221 case BUTTON_UP:
222 {
223 _fireAction( SP_VERB_LAYER_RAISE );
224 }
225 break;
226 case BUTTON_DOWN:
227 {
228 _fireAction( SP_VERB_LAYER_LOWER );
229 }
230 break;
231 case BUTTON_DUPLICATE:
232 {
233 _fireAction( SP_VERB_LAYER_DUPLICATE );
234 }
235 break;
236 case BUTTON_DELETE:
237 {
238 _fireAction( SP_VERB_LAYER_DELETE );
239 }
240 break;
241 case BUTTON_SOLO:
242 {
243 _fireAction( SP_VERB_LAYER_SOLO );
244 }
245 break;
246 }
248 delete _pending;
249 _pending = 0;
250 }
252 return false;
253 }
255 class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
256 {
257 public:
259 ModelColumns()
260 {
261 add(_colObject);
262 add(_colVisible);
263 add(_colLocked);
264 add(_colLabel);
265 }
266 virtual ~ModelColumns() {}
268 Gtk::TreeModelColumn<SPObject*> _colObject;
269 Gtk::TreeModelColumn<Glib::ustring> _colLabel;
270 Gtk::TreeModelColumn<bool> _colVisible;
271 Gtk::TreeModelColumn<bool> _colLocked;
272 };
274 void LayersPanel::_updateLayer( SPObject *layer ) {
275 _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForUpdated), layer) );
276 }
278 bool LayersPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* layer)
279 {
280 bool stopGoing = false;
281 Gtk::TreeModel::Row row = *iter;
282 Glib::ustring tmp = row[_model->_colLabel];
283 if ( layer == row[_model->_colObject] )
284 {
285 row[_model->_colLabel] = layer->label() ? layer->label() : layer->getId();
286 row[_model->_colVisible] = SP_IS_ITEM(layer) ? !SP_ITEM(layer)->isHidden() : false;
287 row[_model->_colLocked] = SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false;
289 stopGoing = true;
290 }
292 return stopGoing;
293 }
295 void LayersPanel::_selectLayer( SPObject *layer ) {
296 if ( !layer || (_desktop && _desktop->doc() && (layer == _desktop->doc()->root)) ) {
297 if ( _tree.get_selection()->count_selected_rows() != 0 ) {
298 _tree.get_selection()->unselect_all();
299 }
300 } else {
301 _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) );
302 }
304 _checkTreeSelection();
305 }
307 bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer)
308 {
309 bool stopGoing = false;
311 Gtk::TreeModel::Row row = *iter;
312 if ( layer == row[_model->_colObject] )
313 {
314 _tree.expand_to_path( path );
316 Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
318 select->select(iter);
320 stopGoing = true;
321 }
323 return stopGoing;
324 }
326 void LayersPanel::_layersChanged()
327 {
328 // g_message("_layersChanged()");
329 if (_desktop) {
330 SPDocument* document = _desktop->doc();
331 SPObject* root = document->root;
332 if ( root ) {
333 _selectedConnection.block();
334 if ( _desktop->layer_manager && _desktop->layer_manager->includes( root ) ) {
335 SPObject* target = _desktop->currentLayer();
336 _store->clear();
338 #if DUMP_LAYERS
339 g_message("root:%p {%s} [%s]", root, root->id, root->label() );
340 #endif // DUMP_LAYERS
341 _addLayer( document, root, 0, target, 0 );
342 }
343 _selectedConnection.unblock();
344 }
345 }
346 }
348 void LayersPanel::_addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level )
349 {
350 if ( _desktop && _desktop->layer_manager && layer && (level < _maxNestDepth) ) {
351 unsigned int counter = _desktop->layer_manager->childCount(layer);
352 for ( unsigned int i = 0; i < counter; i++ ) {
353 SPObject *child = _desktop->layer_manager->nthChildOf(layer, i);
354 if ( child ) {
355 #if DUMP_LAYERS
356 g_message(" %3d layer:%p {%s} [%s]", level, child, child->id, child->label() );
357 #endif // DUMP_LAYERS
359 Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend();
360 Gtk::TreeModel::Row row = *iter;
361 row[_model->_colObject] = child;
362 row[_model->_colLabel] = child->label() ? child->label() : child->getId();
363 row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false;
364 row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false;
366 if ( target && child == target ) {
367 _tree.expand_to_path( _store->get_path(iter) );
369 Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
370 select->select(iter);
372 _checkTreeSelection();
373 }
375 _addLayer( doc, child, &row, target, level + 1 );
376 }
377 }
378 }
379 }
381 SPObject* LayersPanel::_selectedLayer()
382 {
383 SPObject* obj = 0;
385 Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
386 if ( iter ) {
387 Gtk::TreeModel::Row row = *iter;
388 obj = row[_model->_colObject];
389 }
391 return obj;
392 }
394 void LayersPanel::_pushTreeSelectionToCurrent()
395 {
396 // TODO hunt down the possible API abuse in getting NULL
397 if ( _desktop && _desktop->layer_manager && _desktop->currentRoot() ) {
398 SPObject* inTree = _selectedLayer();
399 if ( inTree ) {
400 SPObject* curr = _desktop->currentLayer();
401 if ( curr != inTree ) {
402 _desktop->layer_manager->setCurrentLayer( inTree );
403 }
404 } else {
405 _desktop->layer_manager->setCurrentLayer( _desktop->doc()->root );
406 }
407 }
408 }
410 void LayersPanel::_checkTreeSelection()
411 {
412 bool sensitive = false;
413 bool sensitiveNonTop = false;
414 bool sensitiveNonBottom = false;
415 if ( _tree.get_selection()->count_selected_rows() > 0 ) {
416 sensitive = true;
418 SPObject* inTree = _selectedLayer();
419 if ( inTree ) {
421 sensitiveNonTop = (Inkscape::next_layer(inTree->parent, inTree) != 0);
422 sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0);
424 }
425 }
428 for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
429 (*it)->set_sensitive( sensitive );
430 }
431 for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
432 (*it)->set_sensitive( sensitiveNonTop );
433 }
434 for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
435 (*it)->set_sensitive( sensitiveNonBottom );
436 }
437 }
439 void LayersPanel::_preToggle( GdkEvent const *event )
440 {
442 if ( _toggleEvent ) {
443 gdk_event_free(_toggleEvent);
444 _toggleEvent = 0;
445 }
447 if ( event && (event->type == GDK_BUTTON_PRESS) ) {
448 // Make a copy so we can keep it around.
449 _toggleEvent = gdk_event_copy(const_cast<GdkEvent*>(event));
450 }
451 }
453 void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
454 {
455 g_return_if_fail(_desktop != NULL);
457 Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str);
458 Gtk::TreeModel::Row row = *iter;
460 Glib::ustring tmp = row[_model->_colLabel];
462 SPObject* obj = row[_model->_colObject];
463 SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0;
464 if ( item ) {
465 switch ( targetCol ) {
466 case COL_VISIBLE:
467 {
468 bool newValue = !row[_model->_colVisible];
469 row[_model->_colVisible] = newValue;
470 item->setHidden( !newValue );
471 item->updateRepr();
472 DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_LAYERS,
473 newValue? _("Unhide layer") : _("Hide layer"));
474 }
475 break;
477 case COL_LOCKED:
478 {
479 bool newValue = !row[_model->_colLocked];
480 row[_model->_colLocked] = newValue;
481 item->setLocked( newValue );
482 item->updateRepr();
483 DocumentUndo::done( _desktop->doc() , SP_VERB_DIALOG_LAYERS,
484 newValue? _("Lock layer") : _("Unlock layer"));
485 }
486 break;
487 }
488 }
489 }
491 void LayersPanel::_handleButtonEvent(GdkEventButton* evt)
492 {
493 // TODO - fix to a better is-popup function
494 if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) {
497 {
498 Gtk::TreeModel::Path path;
499 Gtk::TreeViewColumn* col = 0;
500 int x = static_cast<int>(evt->x);
501 int y = static_cast<int>(evt->y);
502 int x2 = 0;
503 int y2 = 0;
504 if ( _tree.get_path_at_pos( x, y,
505 path, col,
506 x2, y2 ) ) {
507 _checkTreeSelection();
508 _popupMenu.popup(evt->button, evt->time);
509 }
510 }
512 }
513 }
515 void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter )
516 {
517 Gtk::TreeModel::Row row = *iter;
518 if ( row && _desktop && _desktop->layer_manager) {
519 SPObject* obj = row[_model->_colObject];
520 if ( obj ) {
521 gchar const* oldLabel = obj->label();
522 Glib::ustring tmp = row[_model->_colLabel];
523 if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) {
524 _desktop->layer_manager->renameLayer( obj, tmp.c_str(), FALSE );
525 row[_model->_colLabel] = obj->label();
526 }
527 }
528 }
529 }
531 bool LayersPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected )
532 {
533 bool val = true;
534 if ( !currentlySelected && _toggleEvent )
535 {
536 GdkEvent* event = gtk_get_current_event();
537 if ( event ) {
538 // (keep these checks separate, so we know when to call gdk_event_free()
539 if ( event->type == GDK_BUTTON_PRESS ) {
540 GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent);
541 GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event);
543 if ( (evtb->window == target->window)
544 && (evtb->send_event == target->send_event)
545 && (evtb->time == target->time)
546 && (evtb->state == target->state)
547 )
548 {
549 // Ooooh! It's a magic one
550 val = false;
551 }
552 }
553 gdk_event_free(event);
554 }
555 }
556 return val;
557 }
559 /**
560 * Constructor
561 */
562 LayersPanel::LayersPanel() :
563 UI::Widget::Panel("", "/dialogs/layers", SP_VERB_DIALOG_LAYERS),
564 deskTrack(),
565 _maxNestDepth(20),
566 _desktop(0),
567 _model(0),
568 _pending(0),
569 _toggleEvent(0),
570 _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", UI::Widget::SimpleFilterModifier::BLEND),
571 desktopChangeConn()
572 {
573 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
574 _maxNestDepth = prefs->getIntLimited("/dialogs/layers/maxDepth", 20, 1, 1000);
576 ModelColumns *zoop = new ModelColumns();
577 _model = zoop;
579 _store = Gtk::TreeStore::create( *zoop );
581 _tree.set_model( _store );
582 _tree.set_headers_visible(false);
584 Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler(
585 INKSCAPE_ICON_OBJECT_VISIBLE, INKSCAPE_ICON_OBJECT_HIDDEN) );
586 int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1;
587 eyeRenderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) );
588 eyeRenderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) );
589 eyeRenderer->property_activatable() = true;
590 Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum);
591 if ( col ) {
592 col->add_attribute( eyeRenderer->property_active(), _model->_colVisible );
593 }
595 Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler(
596 INKSCAPE_ICON_OBJECT_LOCKED, INKSCAPE_ICON_OBJECT_UNLOCKED) );
597 int lockedColNum = _tree.append_column("lock", *renderer) - 1;
598 renderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) );
599 renderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) );
600 renderer->property_activatable() = true;
601 col = _tree.get_column(lockedColNum);
602 if ( col ) {
603 col->add_attribute( renderer->property_active(), _model->_colLocked );
604 }
606 int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1;
608 _tree.set_expander_column( *_tree.get_column(nameColNum) );
610 _compositeSettings.setSubject(&_subject);
612 _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) );
613 _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) );
615 _tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) );
616 _tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) );
618 _scroller.add( _tree );
619 _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
620 _scroller.set_shadow_type(Gtk::SHADOW_IN);
622 _watching.push_back( &_compositeSettings );
624 _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET );
625 _layersPage.pack_end(_compositeSettings, Gtk::PACK_SHRINK);
626 _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK);
628 _getContents()->pack_start(_layersPage, Gtk::PACK_EXPAND_WIDGET);
630 SPDesktop* targetDesktop = getDesktop();
632 _buttonsRow.set_child_min_width( 16 );
634 Gtk::Button* btn = manage( new Gtk::Button() );
635 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, C_("Layers", "New") );
636 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) );
637 _buttonsRow.add( *btn );
639 btn = manage( new Gtk::Button() );
640 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, C_("Layers", "Top") );
641 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) );
642 _watchingNonTop.push_back( btn );
643 _buttonsRow.add( *btn );
645 btn = manage( new Gtk::Button() );
646 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, C_("Layers", "Up") );
647 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) );
648 _watchingNonTop.push_back( btn );
649 _buttonsRow.add( *btn );
651 btn = manage( new Gtk::Button() );
652 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, C_("Layers", "Dn") );
653 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) );
654 _watchingNonBottom.push_back( btn );
655 _buttonsRow.add( *btn );
657 btn = manage( new Gtk::Button() );
658 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, C_("Layers", "Bot") );
659 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) );
660 _watchingNonBottom.push_back( btn );
661 _buttonsRow.add( *btn );
663 // btn = manage( new Gtk::Button("Dup") );
664 // btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) );
665 // _buttonsRow.add( *btn );
667 btn = manage( new Gtk::Button() );
668 _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("X") );
669 btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) );
670 _watching.push_back( btn );
671 _buttonsRow.add( *btn );
676 // -------------------------------------------------------
677 {
678 _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) );
679 _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) );
680 _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) );
681 _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) );
683 _popupMenu.items().push_back( Gtk::Menu_Helpers::SeparatorElem() );
685 _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) );
686 _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) );
688 _popupMenu.show_all_children();
689 }
690 // -------------------------------------------------------
694 for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
695 (*it)->set_sensitive( false );
696 }
697 for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
698 (*it)->set_sensitive( false );
699 }
700 for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
701 (*it)->set_sensitive( false );
702 }
704 setDesktop( targetDesktop );
706 show_all_children();
708 // restorePanelPrefs();
710 // Connect this up last
711 desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &LayersPanel::setDesktop) );
712 deskTrack.connect(GTK_WIDGET(gobj()));
713 }
715 LayersPanel::~LayersPanel()
716 {
717 setDesktop(NULL);
719 _compositeSettings.setSubject(NULL);
721 if ( _model )
722 {
723 delete _model;
724 _model = 0;
725 }
727 if (_pending) {
728 delete _pending;
729 _pending = 0;
730 }
732 if ( _toggleEvent )
733 {
734 gdk_event_free( _toggleEvent );
735 _toggleEvent = 0;
736 }
738 desktopChangeConn.disconnect();
739 deskTrack.disconnect();
740 }
743 void LayersPanel::setDesktop( SPDesktop* desktop )
744 {
745 Panel::setDesktop(desktop);
747 if ( desktop != _desktop ) {
748 _layerChangedConnection.disconnect();
749 _layerUpdatedConnection.disconnect();
750 _changedConnection.disconnect();
751 if ( _desktop ) {
752 _desktop = 0;
753 }
755 _desktop = Panel::getDesktop();
756 if ( _desktop ) {
757 //setLabel( _desktop->doc()->name );
759 LayerManager *mgr = _desktop->layer_manager;
760 if ( mgr ) {
761 _layerChangedConnection = mgr->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) );
762 _layerUpdatedConnection = mgr->connectLayerDetailsChanged( sigc::mem_fun(*this, &LayersPanel::_updateLayer) );
763 _changedConnection = mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) );
764 }
766 _layersChanged();
767 }
768 }
769 /*
770 GSList const *layers = _desktop->doc()->getResourceList( "layer" );
771 g_message( "layers list starts at %p", layers );
772 for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
773 SPObject *layer=static_cast<SPObject *>(iter->data);
774 g_message(" {%s} [%s]", layer->id, layer->label() );
775 }
776 */
777 deskTrack.setBase(desktop);
778 }
782 } //namespace Dialogs
783 } //namespace UI
784 } //namespace Inkscape
787 /*
788 Local Variables:
789 mode:c++
790 c-file-style:"stroustrup"
791 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
792 indent-tabs-mode:nil
793 fill-column:99
794 End:
795 */
796 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :