// SPDX-License-Identifier: GPL-2.0-or-later /* * Inkscape::SelectionDescriber - shows messages describing selection * * Authors: * MenTaLguY * Jon A. Cruz * * Copyright (C) 2004 MenTaLguY * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "document.h" #include "layer-fns.h" #include "object/sp-item-group.h" #include "util/find-last-if.h" #include "xml/repr.h" // TODO move the documentation comments into the .h file namespace Inkscape { namespace { static bool is_layer(SPObject &object) { return SP_IS_GROUP(&object) && SP_GROUP(&object)->layerMode() == SPGroup::LAYER; } /** Finds the next sibling layer for a \a layer * * @returns NULL if there are no further layers under a parent */ static SPObject *next_sibling_layer(SPObject *layer) { if (layer->parent == nullptr) { return nullptr; } SPObject::ChildrenList &list = layer->parent->children; auto l = std::find_if(++list.iterator_to(*layer), list.end(), &is_layer); return l != list.end() ? &*l : nullptr; } /** Finds the previous sibling layer for a \a layer * * @returns NULL if there are no further layers under a parent */ static SPObject *previous_sibling_layer(SPObject *layer) { using Inkscape::Algorithms::find_last_if; SPObject::ChildrenList &list = layer->parent->children; auto l = find_last_if(list.begin(), list.iterator_to(*layer), &is_layer); return l != list.iterator_to(*layer) ? &*(l) : nullptr; } /** Finds the first child of a \a layer * * @returns the layer itself if layer has no sublayers */ static SPObject *first_descendant_layer(SPObject *layer) { while (true) { auto first_descendant = std::find_if(layer->children.begin(), layer->children.end(), &is_layer); if (first_descendant == layer->children.end()) { break; } layer = &*first_descendant; } return layer; } /** Finds the last (topmost) child of a \a layer * * @returns NULL if layer has no sublayers */ static SPObject *last_child_layer(SPObject *layer) { using Inkscape::Algorithms::find_last_if; auto l = find_last_if(layer->children.begin(), layer->children.end(), &is_layer); return l != layer->children.end() ? &*l : nullptr; } static SPObject *last_elder_layer(SPObject *root, SPObject *layer) { using Inkscape::Algorithms::find_last_if; SPObject *result = nullptr; while ( layer != root ) { SPObject *sibling(previous_sibling_layer(layer)); if (sibling) { result = sibling; break; } layer = layer->parent; } return result; } } /** Finds the next layer under \a root, relative to \a layer in * depth-first order. * * @returns NULL if there are no further layers under \a root */ SPObject *next_layer(SPObject *root, SPObject *layer) { g_return_val_if_fail(layer != nullptr, NULL); SPObject *result = nullptr; SPObject *sibling = next_sibling_layer(layer); if (sibling) { result = first_descendant_layer(sibling); } else if ( layer->parent != root ) { result = layer->parent; } return result; } /** Finds the previous layer under \a root, relative to \a layer in * depth-first order. * * @returns NULL if there are no prior layers under \a root. */ SPObject *previous_layer(SPObject *root, SPObject *layer) { using Inkscape::Algorithms::find_last_if; g_return_val_if_fail(layer != nullptr, NULL); SPObject *result = nullptr; SPObject *child = last_child_layer(layer); if (child) { result = child; } else if ( layer != root ) { SPObject *sibling = previous_sibling_layer(layer); if (sibling) { result = sibling; } else { result = last_elder_layer(root, layer->parent); } } return result; } /** * Creates a new layer. Advances to the next layer id indicated * by the string "layerNN", then creates a new group object of * that id with attribute inkscape:groupmode='layer', and finally * appends the new group object to \a root after object \a layer. * * \pre \a root should be either \a layer or an ancestor of it */ SPObject *create_layer(SPObject *root, SPObject *layer, LayerRelativePosition position) { SPDocument *document = root->document; static int layer_suffix=1; gchar *id=nullptr; do { g_free(id); id = g_strdup_printf("layer%d", layer_suffix++); } while (document->getObjectById(id)); Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:g"); repr->setAttribute("inkscape:groupmode", "layer"); repr->setAttribute("id", id); g_free(id); if ( LPOS_CHILD == position ) { root = layer; SPObject *child_layer = Inkscape::last_child_layer(layer); if ( nullptr != child_layer ) { layer = child_layer; } } if ( root == layer ) { root->getRepr()->appendChild(repr); } else { Inkscape::XML::Node *layer_repr = layer->getRepr(); layer_repr->parent()->addChild(repr, layer_repr); if ( LPOS_BELOW == position ) { SP_ITEM(document->getObjectByRepr(repr))->lowerOne(); } } return document->getObjectByRepr(repr); } } /* 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 :