Code

Cleanup of device internal handling and API.
[inkscape.git] / src / ui / dialog / layers.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>
16 #include <gtk/gtkmain.h>
17 #include <gtkmm/widget.h>
18 #include <gtkmm/icontheme.h>
19 #include <glibmm/i18n.h>
21 #include "desktop.h"
22 #include "desktop-style.h"
23 #include "document.h"
24 #include "helper/action.h"
25 #include "inkscape.h"
26 #include "layer-fns.h"
27 #include "layer-manager.h"
28 #include "preferences.h"
29 #include "sp-item.h"
30 #include "sp-object.h"
31 #include "svg/css-ostringstream.h"
32 #include "ui/icon-names.h"
33 #include "ui/widget/imagetoggler.h"
34 #include "verbs.h"
35 #include "widgets/icon.h"
36 #include "xml/repr.h"
38 #include "layers.h"
40 //#define DUMP_LAYERS 1
42 namespace Inkscape {
43 namespace UI {
44 namespace Dialogs {
46 LayersPanel&
47 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 static gboolean layers_panel_activated(Inkscape::Application * /*inkscape*/, SPDesktop *desktop, gpointer data )
77 {
78     if ( data )
79     {
80         LayersPanel* panel = reinterpret_cast<LayersPanel*>(data);
81         panel->setDesktop(desktop);
82     }
84     return FALSE;
85 }
87 static gboolean layers_panel_deactivated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data )
88 {
89     if ( data )
90     {
91         LayersPanel* panel = reinterpret_cast<LayersPanel*>(data);
92         panel->setDesktop(NULL);
93     }
95     return FALSE;
96 }
98 void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback )
99 {
100     bool set = false;
102     if ( iconName ) {
103         GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName );
104         gtk_widget_show( child );
105         btn.add( *manage(Glib::wrap(child)) );
106         set = true;
107     }
109     if ( desktop ) {
110         Verb *verb = Verb::get( code );
111         if ( verb ) {
112             SPAction *action = verb->get_action(desktop);
113             if ( !set && action && action->image ) {
114                 GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image );
115                 gtk_widget_show( child );
116                 btn.add( *manage(Glib::wrap(child)) );
117                 set = true;
118             }
120             if ( action && action->tip ) {
121                 _tips.set_tip( btn, action->tip );
122             }
123         }
124     }
126     if ( !set && fallback ) {
127         btn.set_label( fallback );
128     }
132 Gtk::MenuItem& LayersPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id )
134     GtkWidget* iconWidget = 0;
135     const char* label = 0;
137     if ( iconName ) {
138         iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName );
139     }
141     if ( desktop ) {
142         Verb *verb = Verb::get( code );
143         if ( verb ) {
144             SPAction *action = verb->get_action(desktop);
145             if ( !iconWidget && action && action->image ) {
146                 iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image );
147             }
149             if ( action ) {
150                 label = action->name;
151             }
152         }
153     }
155     if ( !label && fallback ) {
156         label = fallback;
157     }
159     Gtk::Widget* wrapped = 0;
160     if ( iconWidget ) {
161         wrapped = manage(Glib::wrap(iconWidget));
162         wrapped->show();
163     }
167     Gtk::Menu::MenuList& menulist = _popupMenu.items();
169     if ( wrapped ) {
170         menulist.push_back( Gtk::Menu_Helpers::ImageMenuElem( label, *wrapped, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) );
171     } else {
172         menulist.push_back( Gtk::Menu_Helpers::MenuElem( label, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) );
173     }
174     return menulist.back();
177 void LayersPanel::_fireAction( unsigned int code )
179     if ( _desktop ) {
180         Verb *verb = Verb::get( code );
181         if ( verb ) {
182             SPAction *action = verb->get_action(_desktop);
183             if ( action ) {
184                 sp_action_perform( action, NULL );
185 //             } else {
186 //                 g_message("no action");
187             }
188 //         } else {
189 //             g_message("no verb for %u", code);
190         }
191 //     } else {
192 //         g_message("no active desktop");
193     }
196 //     SP_VERB_LAYER_NEXT,
197 //     SP_VERB_LAYER_PREV,
198 void LayersPanel::_takeAction( int val )
200     if ( !_pending ) {
201         _pending = new InternalUIBounce();
202         _pending->_actionCode = val;
203         _pending->_target = _selectedLayer();
204         Glib::signal_timeout().connect( sigc::mem_fun(*this, &LayersPanel::_executeAction), 0 );
205     }
208 bool LayersPanel::_executeAction()
210     // Make sure selected layer hasn't changed since the action was triggered
211     if ( _pending
212          && (
213              (_pending->_actionCode == BUTTON_NEW)
214              || !( (_desktop && _desktop->currentLayer())
215                    && (_desktop->currentLayer() != _pending->_target)
216                  )
217              )
218         ) {
219         int val = _pending->_actionCode;
220 //        SPObject* target = _pending->_target;
222         switch ( val ) {
223             case BUTTON_NEW:
224             {
225                 _fireAction( SP_VERB_LAYER_NEW );
226             }
227             break;
228             case BUTTON_RENAME:
229             {
230                 _fireAction( SP_VERB_LAYER_RENAME );
231             }
232             break;
233             case BUTTON_TOP:
234             {
235                 _fireAction( SP_VERB_LAYER_TO_TOP );
236             }
237             break;
238             case BUTTON_BOTTOM:
239             {
240                 _fireAction( SP_VERB_LAYER_TO_BOTTOM );
241             }
242             break;
243             case BUTTON_UP:
244             {
245                 _fireAction( SP_VERB_LAYER_RAISE );
246             }
247             break;
248             case BUTTON_DOWN:
249             {
250                 _fireAction( SP_VERB_LAYER_LOWER );
251             }
252             break;
253             case BUTTON_DUPLICATE:
254             {
255                 _fireAction( SP_VERB_LAYER_DUPLICATE );
256             }
257             break;
258             case BUTTON_DELETE:
259             {
260                 _fireAction( SP_VERB_LAYER_DELETE );
261             }
262             break;
263             case BUTTON_SOLO:
264             {
265                 _fireAction( SP_VERB_LAYER_SOLO );
266             }
267             break;
268         }
270         delete _pending;
271         _pending = 0;
272     }
274     return false;
277 class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord
279 public:
281     ModelColumns()
282     {
283         add(_colObject);
284         add(_colVisible);
285         add(_colLocked);
286         add(_colLabel);
287     }
288     virtual ~ModelColumns() {}
290     Gtk::TreeModelColumn<SPObject*> _colObject;
291     Gtk::TreeModelColumn<Glib::ustring> _colLabel;
292     Gtk::TreeModelColumn<bool> _colVisible;
293     Gtk::TreeModelColumn<bool> _colLocked;
294 };
296 void LayersPanel::_updateLayer( SPObject *layer ) {
297     _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForUpdated), layer) );
300 bool LayersPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* layer)
302     bool stopGoing = false;
303     Gtk::TreeModel::Row row = *iter;
304     Glib::ustring tmp = row[_model->_colLabel];
305     if ( layer == row[_model->_colObject] )
306     {
307         row[_model->_colLabel] = layer->label() ? layer->label() : layer->getId();
308         row[_model->_colVisible] = SP_IS_ITEM(layer) ? !SP_ITEM(layer)->isHidden() : false;
309         row[_model->_colLocked] = SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false;
311         stopGoing = true;
312     }
314     return stopGoing;
317 void LayersPanel::_selectLayer( SPObject *layer ) {
318     if ( !layer || (_desktop && _desktop->doc() && (layer == _desktop->doc()->root)) ) {
319         if ( _tree.get_selection()->count_selected_rows() != 0 ) {
320             _tree.get_selection()->unselect_all();
321         }
322     } else {
323         _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) );
324     }
326     _checkTreeSelection();
329 bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer)
331     bool stopGoing = false;
333     Gtk::TreeModel::Row row = *iter;
334     if ( layer == row[_model->_colObject] )
335     {
336         _tree.expand_to_path( path );
338         Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
340         select->select(iter);
342         stopGoing = true;
343     }
345     return stopGoing;
348 void LayersPanel::_layersChanged()
350 //    g_message("_layersChanged()");
351     if(_desktop) {
352         SPDocument* document = _desktop->doc();
353         SPObject* root = document->root;
354         if ( root ) {
355             _selectedConnection.block();
356             if ( _mgr && _mgr->includes( root ) ) {
357                 SPObject* target = _desktop->currentLayer();
358                 _store->clear();
360     #if DUMP_LAYERS
361                 g_message("root:%p  {%s}   [%s]", root, root->id, root->label() );
362     #endif // DUMP_LAYERS
363                 _addLayer( document, root, 0, target, 0 );
364             }
365             _selectedConnection.unblock();
366         }
367     }
370 void LayersPanel::_addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level )
372     if ( layer && (level < _maxNestDepth) ) {
373         unsigned int counter = _mgr->childCount(layer);
374         for ( unsigned int i = 0; i < counter; i++ ) {
375             SPObject *child = _mgr->nthChildOf(layer, i);
376             if ( child ) {
377 #if DUMP_LAYERS
378                 g_message(" %3d    layer:%p  {%s}   [%s]", level, child, child->id, child->label() );
379 #endif // DUMP_LAYERS
381                 Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend();
382                 Gtk::TreeModel::Row row = *iter;
383                 row[_model->_colObject] = child;
384                 row[_model->_colLabel] = child->label() ? child->label() : child->getId();
385                 row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false;
386                 row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false;
388                 if ( target && child == target ) {
389                     _tree.expand_to_path( _store->get_path(iter) );
391                     Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection();
392                     select->select(iter);
394                     _checkTreeSelection();
395                 }
397                 _addLayer( doc, child, &row, target, level + 1 );
398             }
399         }
400     }
403 SPObject* LayersPanel::_selectedLayer()
405     SPObject* obj = 0;
407     Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected();
408     if ( iter ) {
409         Gtk::TreeModel::Row row = *iter;
410         obj = row[_model->_colObject];
411     }
413     return obj;
416 void LayersPanel::_pushTreeSelectionToCurrent()
418     // TODO hunt down the possible API abuse in getting NULL
419     if ( _desktop && _desktop->currentRoot() ) {
420         SPObject* inTree = _selectedLayer();
421         if ( inTree ) {
422             SPObject* curr = _desktop->currentLayer();
423             if ( curr != inTree ) {
424                 _mgr->setCurrentLayer( inTree );
425             }
426         } else {
427             _mgr->setCurrentLayer( _desktop->doc()->root );
428         }
429     }
432 void LayersPanel::_checkTreeSelection()
434     bool sensitive = false;
435     bool sensitiveNonTop = false;
436     bool sensitiveNonBottom = false;
437     if ( _tree.get_selection()->count_selected_rows() > 0 ) {
438         sensitive = true;
440         SPObject* inTree = _selectedLayer();
441         if ( inTree ) {
443             sensitiveNonTop = (Inkscape::next_layer(inTree->parent, inTree) != 0);
444             sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0);
446         }
447     }
450     for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
451         (*it)->set_sensitive( sensitive );
452     }
453     for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
454         (*it)->set_sensitive( sensitiveNonTop );
455     }
456     for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
457         (*it)->set_sensitive( sensitiveNonBottom );
458     }
461 void LayersPanel::_preToggle( GdkEvent const *event )
464     if ( _toggleEvent ) {
465         gdk_event_free(_toggleEvent);
466         _toggleEvent = 0;
467     }
469     if ( event && (event->type == GDK_BUTTON_PRESS) ) {
470         // Make a copy so we can keep it around.
471         _toggleEvent = gdk_event_copy(const_cast<GdkEvent*>(event));
472     }
475 void LayersPanel::_toggled( Glib::ustring const& str, int targetCol )
477     g_return_if_fail(_desktop != NULL);
479     Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str);
480     Gtk::TreeModel::Row row = *iter;
482     Glib::ustring tmp = row[_model->_colLabel];
484     SPObject* obj = row[_model->_colObject];
485     SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0;
486     if ( item ) {
487         switch ( targetCol ) {
488             case COL_VISIBLE:
489             {
490                 bool newValue = !row[_model->_colVisible];
491                 row[_model->_colVisible] = newValue;
492                 item->setHidden( !newValue  );
493                 item->updateRepr();
494                 sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS,
495                                   newValue? _("Unhide layer") : _("Hide layer"));
496             }
497             break;
499             case COL_LOCKED:
500             {
501                 bool newValue = !row[_model->_colLocked];
502                 row[_model->_colLocked] = newValue;
503                 item->setLocked( newValue );
504                 item->updateRepr();
505                 sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS,
506                                   newValue? _("Lock layer") : _("Unlock layer"));
507             }
508             break;
509         }
510     }
513 void LayersPanel::_handleButtonEvent(GdkEventButton* evt)
515     // TODO - fix to a better is-popup function
516     if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) {
519         {
520             Gtk::TreeModel::Path path;
521             Gtk::TreeViewColumn* col = 0;
522             int x = static_cast<int>(evt->x);
523             int y = static_cast<int>(evt->y);
524             int x2 = 0;
525             int y2 = 0;
526             if ( _tree.get_path_at_pos( x, y,
527                                         path, col,
528                                         x2, y2 ) ) {
529                 _checkTreeSelection();
530                 _popupMenu.popup(evt->button, evt->time);
531             }
532         }
534     }
537 void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter )
539     Gtk::TreeModel::Row row = *iter;
540     if ( row ) {
541         SPObject* obj = row[_model->_colObject];
542         if ( obj ) {
543             gchar const* oldLabel = obj->label();
544             Glib::ustring tmp = row[_model->_colLabel];
545             if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) {
546                 _mgr->renameLayer( obj, tmp.c_str(), FALSE );
547                 row[_model->_colLabel] = obj->label();
548             }
549         }
550     }
553 bool LayersPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected )
555     bool val = true;
556     if ( !currentlySelected && _toggleEvent )
557     {
558         GdkEvent* event = gtk_get_current_event();
559         if ( event ) {
560             // (keep these checks separate, so we know when to call gdk_event_free()
561             if ( event->type == GDK_BUTTON_PRESS ) {
562                 GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent);
563                 GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event);
565                 if ( (evtb->window == target->window)
566                      && (evtb->send_event == target->send_event)
567                      && (evtb->time == target->time)
568                      && (evtb->state == target->state)
569                     )
570                 {
571                     // Ooooh! It's a magic one
572                     val = false;
573                 }
574             }
575             gdk_event_free(event);
576         }
577     }
578     return val;
581 /**
582  * Constructor
583  */
584 LayersPanel::LayersPanel() :
585     UI::Widget::Panel("", "/dialogs/layers", SP_VERB_DIALOG_LAYERS),
586     _maxNestDepth(20),
587     _mgr(0),
588     _desktop(0),
589     _model(0),
590     _pending(0),
591     _toggleEvent(0),
592     _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", UI::Widget::SimpleFilterModifier::BLEND)
594     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
595     _maxNestDepth = prefs->getIntLimited("/dialogs/layers/maxDepth", 20, 1, 1000);
597     ModelColumns *zoop = new ModelColumns();
598     _model = zoop;
600     _store = Gtk::TreeStore::create( *zoop );
602     _tree.set_model( _store );
603     _tree.set_headers_visible(false);
605     Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler(
606         INKSCAPE_ICON_OBJECT_VISIBLE, INKSCAPE_ICON_OBJECT_HIDDEN) );
607     int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1;
608     eyeRenderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) );
609     eyeRenderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) );
610     eyeRenderer->property_activatable() = true;
611     Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum);
612     if ( col ) {
613         col->add_attribute( eyeRenderer->property_active(), _model->_colVisible );
614     }
616     Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler(
617         INKSCAPE_ICON_OBJECT_LOCKED, INKSCAPE_ICON_OBJECT_UNLOCKED) );
618     int lockedColNum = _tree.append_column("lock", *renderer) - 1;
619     renderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) );
620     renderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) );
621     renderer->property_activatable() = true;
622     col = _tree.get_column(lockedColNum);
623     if ( col ) {
624         col->add_attribute( renderer->property_active(), _model->_colLocked );
625     }
627     int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1;
629     _tree.set_expander_column( *_tree.get_column(nameColNum) );
631     _compositeSettings.setSubject(&_subject);
633     _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) );
634     _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) );
636     _tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) );
637     _tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) );
639     _scroller.add( _tree );
640     _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
641     _scroller.set_shadow_type(Gtk::SHADOW_IN);
643     _watching.push_back( &_compositeSettings );
645     _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET );
646     _layersPage.pack_end(_compositeSettings, Gtk::PACK_SHRINK);
647     _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK);
649     _getContents()->pack_start(_layersPage, Gtk::PACK_EXPAND_WIDGET);
651     SPDesktop* targetDesktop = getDesktop();
653     _buttonsRow.set_child_min_width( 16 );
655     Gtk::Button* btn = manage( new Gtk::Button() );
656     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("New") );
657     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) );
658     _buttonsRow.add( *btn );
660     btn = manage( new Gtk::Button() );
661     //TRANSLATORS: only translate "string" in "context|string".
662     // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
663     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, Q_("layers|Top") );
664     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) );
665     _watchingNonTop.push_back( btn );
666     _buttonsRow.add( *btn );
668     btn = manage( new Gtk::Button() );
669     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, _("Up") );
670     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) );
671     _watchingNonTop.push_back( btn );
672     _buttonsRow.add( *btn );
674     btn = manage( new Gtk::Button() );
675     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, _("Dn") );
676     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) );
677     _watchingNonBottom.push_back( btn );
678     _buttonsRow.add( *btn );
680     btn = manage( new Gtk::Button() );
681     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, _("Bot") );
682     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) );
683     _watchingNonBottom.push_back( btn );
684     _buttonsRow.add( *btn );
686 //     btn = manage( new Gtk::Button("Dup") );
687 //     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) );
688 //     _buttonsRow.add( *btn );
690     btn = manage( new Gtk::Button() );
691     _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("X") );
692     btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) );
693     _watching.push_back( btn );
694     _buttonsRow.add( *btn );
699     // -------------------------------------------------------
700     {
701         _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) );
702         _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) );
703         _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) );
704         _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) );
706          _popupMenu.items().push_back( Gtk::Menu_Helpers::SeparatorElem() );
708         _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) );
709         _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) );
711         _popupMenu.show_all_children();
712     }
713     // -------------------------------------------------------
717     for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) {
718         (*it)->set_sensitive( false );
719     }
720     for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) {
721         (*it)->set_sensitive( false );
722     }
723     for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) {
724         (*it)->set_sensitive( false );
725     }
727     g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this );
728     g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", G_CALLBACK( layers_panel_deactivated ), this );
730     setDesktop( targetDesktop );
732     show_all_children();
734     // restorePanelPrefs();
737 LayersPanel::~LayersPanel()
739     setDesktop(NULL);
741     _compositeSettings.setSubject(NULL);
743     if ( _model )
744     {
745         delete _model;
746     }
748     if ( _toggleEvent )
749     {
750         gdk_event_free( _toggleEvent );
751         _toggleEvent = 0;
752     }
756 void LayersPanel::setDesktop( SPDesktop* desktop )
758     Panel::setDesktop(desktop);
760     if ( desktop != _desktop ) {
761         _layerChangedConnection.disconnect();
762         _layerUpdatedConnection.disconnect();
763         _changedConnection.disconnect();
764         if ( _mgr ) {
765             _mgr = 0;
766         }
767         if ( _desktop ) {
768             _desktop = 0;
769         }
771         _desktop = Panel::getDesktop();
772         if ( _desktop ) {
773             //setLabel( _desktop->doc()->name );
775             _mgr = _desktop->layer_manager;
776             if ( _mgr ) {
777                 _layerChangedConnection = _mgr->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) );
778                 _layerUpdatedConnection = _mgr->connectLayerDetailsChanged( sigc::mem_fun(*this, &LayersPanel::_updateLayer) );
779                 _changedConnection = _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) );
780             }
782             _layersChanged();
783         }
784     }
785 /*
786     GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" );
787     g_message( "layers list starts at %p", layers );
788     for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
789         SPObject *layer=static_cast<SPObject *>(iter->data);
790         g_message("  {%s}   [%s]", layer->id, layer->label() );
791     }
792 */
797 } //namespace Dialogs
798 } //namespace UI
799 } //namespace Inkscape
802 /*
803   Local Variables:
804   mode:c++
805   c-file-style:"stroustrup"
806   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
807   indent-tabs-mode:nil
808   fill-column:99
809   End:
810 */
811 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :