summaryrefslogtreecommitdiffstats
path: root/src/layer-fns.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/layer-fns.cpp')
-rw-r--r--src/layer-fns.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/layer-fns.cpp b/src/layer-fns.cpp
new file mode 100644
index 0000000..81c722d
--- /dev/null
+++ b/src/layer-fns.cpp
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::SelectionDescriber - shows messages describing selection
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * 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 :