// SPDX-License-Identifier: GPL-2.0-or-later /* * Editable view implementation * * Authors: * Lauris Kaplinski * MenTaLguY * bulia byak * Ralf Stephan * John Bintz * Johan Engelen * Jon A. Cruz * Abhishek Sharma * * Copyright (C) 2007 Jon A. Cruz * Copyright (C) 2006-2008 Johan Engelen * Copyright (C) 2006 John Bintz * Copyright (C) 2004 MenTaLguY * Copyright (C) 1999-2002 Lauris Kaplinski * Copyright (C) 2000-2001 Ximian, Inc. * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "layer-model.h" #include "document.h" #include "layer-fns.h" #include "object-hierarchy.h" #include "object/sp-defs.h" #include "object/sp-item.h" #include "object/sp-item-group.h" #include "object/sp-root.h" // Callbacks static void _layer_activated(SPObject *layer, Inkscape::LayerModel *layer_model); static void _layer_deactivated(SPObject *layer, Inkscape::LayerModel *layer_model); static void _layer_changed(SPObject *top, SPObject *bottom, Inkscape::LayerModel *layer_model); namespace Inkscape { LayerModel::LayerModel() : _doc( nullptr ) , _layer_hierarchy( nullptr ) , _display_key( 0 ) { } LayerModel::~LayerModel() { if (_layer_hierarchy) { delete _layer_hierarchy; // _layer_hierarchy = NULL; //this should be here, but commented to find other bug somewhere else. } } void LayerModel::setDocument(SPDocument *doc) { _doc = doc; if (_layer_hierarchy) { _layer_hierarchy->clear(); delete _layer_hierarchy; } _layer_hierarchy = new Inkscape::ObjectHierarchy(nullptr); _layer_hierarchy->connectAdded(sigc::bind(sigc::ptr_fun(_layer_activated), this)); _layer_hierarchy->connectRemoved(sigc::bind(sigc::ptr_fun(_layer_deactivated), this)); _layer_hierarchy->connectChanged(sigc::bind(sigc::ptr_fun(_layer_changed), this)); _layer_hierarchy->setTop(doc->getRoot()); } void LayerModel::setDisplayKey(unsigned int display_key) { _display_key = display_key; } SPDocument *LayerModel::getDocument() { return _doc; } /** * Returns current root (=bottom) layer. */ SPObject *LayerModel::currentRoot() const { return _layer_hierarchy ? _layer_hierarchy->top() : nullptr; } /** * Returns current top layer. */ SPObject *LayerModel::currentLayer() const { return _layer_hierarchy ? _layer_hierarchy->bottom() : nullptr; } /** * Resets the bottom layer to the current root */ void LayerModel::reset() { if (_layer_hierarchy) { _layer_hierarchy->setBottom(currentRoot()); } } /** * Sets the current layer of the desktop. * * Make \a object the top layer. */ void LayerModel::setCurrentLayer(SPObject *object) { g_return_if_fail(SP_IS_GROUP(object)); g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) ); // printf("Set Layer to ID: %s\n", object->getId()); _layer_hierarchy->setBottom(object); } void LayerModel::toggleHideAllLayers(bool hide) { for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), currentRoot()); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) { SP_ITEM(obj)->setHidden(hide); } } void LayerModel::toggleLockAllLayers(bool lock) { for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), currentRoot()); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) { SP_ITEM(obj)->setLocked(lock); } } void LayerModel::toggleLockOtherLayers(SPObject *object) { g_return_if_fail(SP_IS_GROUP(object)); g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) ); bool othersLocked = false; std::vector layers; for ( SPObject* obj = Inkscape::next_layer(currentRoot(), object); obj; obj = Inkscape::next_layer(currentRoot(), obj) ) { // Don't lock any ancestors, since that would in turn lock the layer as well if (!obj->isAncestorOf(object)) { layers.push_back(obj); othersLocked |= !SP_ITEM(obj)->isLocked(); } } for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), object); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) { if (!obj->isAncestorOf(object)) { layers.push_back(obj); othersLocked |= !SP_ITEM(obj)->isLocked(); } } SPItem *item = SP_ITEM(object); if ( item->isLocked() ) { item->setLocked(false); } for (auto & layer : layers) { SP_ITEM(layer)->setLocked(othersLocked); } } void LayerModel::toggleLayerSolo(SPObject *object) { g_return_if_fail(SP_IS_GROUP(object)); g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) ); bool othersShowing = false; std::vector layers; for ( SPObject* obj = Inkscape::next_layer(currentRoot(), object); obj; obj = Inkscape::next_layer(currentRoot(), obj) ) { // Don't hide ancestors, since that would in turn hide the layer as well if (!obj->isAncestorOf(object)) { layers.push_back(obj); othersShowing |= !SP_ITEM(obj)->isHidden(); } } for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), object); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) { if (!obj->isAncestorOf(object)) { layers.push_back(obj); othersShowing |= !SP_ITEM(obj)->isHidden(); } } SPItem *item = SP_ITEM(object); if ( item->isHidden() ) { item->setHidden(false); } for (auto & layer : layers) { SP_ITEM(layer)->setHidden(othersShowing); } } /** * Return layer that contains \a object. */ SPObject *LayerModel::layerForObject(SPObject *object) { g_return_val_if_fail(object != nullptr, NULL); SPObject *root=currentRoot(); object = object->parent; while ( object && object != root && !isLayer(object) ) { // Objects in defs have no layer and are NOT in the root layer if(SP_IS_DEFS(object)) return nullptr; object = object->parent; } return object; } /** * True if object is a layer. */ bool LayerModel::isLayer(SPObject *object) const { return ( SP_IS_GROUP(object) && ( SP_GROUP(object)->effectiveLayerMode(_display_key) == SPGroup::LAYER ) ); } } // namespace Inkscape /// Callback static void _layer_activated(SPObject *layer, Inkscape::LayerModel *layer_model) { g_return_if_fail(SP_IS_GROUP(layer)); layer_model->_layer_activated_signal.emit(layer); } /// Callback static void _layer_deactivated(SPObject *layer, Inkscape::LayerModel *layer_model) { g_return_if_fail(SP_IS_GROUP(layer)); layer_model->_layer_deactivated_signal.emit(layer); } /// Callback static void _layer_changed(SPObject *top, SPObject *bottom, Inkscape::LayerModel *layer_model) { layer_model->_layer_changed_signal.emit (top, bottom); } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :