Code

A simple layout document as to what, why and how is cppification.
[inkscape.git] / src / layer-fns.cpp
1 /*
2  * Inkscape::SelectionDescriber - shows messages describing selection
3  *
4  * Authors:
5  *   MenTaLguY <mental@rydia.net>
6  *
7  * Copyright (C) 2004 MenTaLguY
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include "document.h"
17 #include "sp-item-group.h"
18 #include "xml/repr.h"
19 #include "util/find-last-if.h"
20 #include "layer-fns.h"
22 namespace Inkscape {
24 namespace {
26 bool is_layer(SPObject &object) {
27     return SP_IS_GROUP(&object) &&
28            SP_GROUP(&object)->layerMode() == SPGroup::LAYER;
29 }
31 /** Finds the next sibling layer for a \a layer
32  *
33  *  @returns NULL if there are no further layers under a parent
34  */
35 SPObject *next_sibling_layer(SPObject *layer) {
36     using std::find_if;
38     return find_if<SPObject::SiblingIterator>(
39         SP_OBJECT_NEXT(layer), NULL, &is_layer
40     );
41 }
43 /** Finds the previous sibling layer for a \a layer
44  *
45  *  @returns NULL if there are no further layers under a parent
46  */
47 SPObject *previous_sibling_layer(SPObject *layer) {
48     using Inkscape::Algorithms::find_last_if;
50     SPObject *sibling(find_last_if<SPObject::SiblingIterator>(
51         SP_OBJECT_PARENT(layer)->firstChild(), layer, &is_layer
52     ));
54     return ( sibling != layer ) ? sibling : NULL;
55 }
57 /** Finds the first child of a \a layer
58  *
59  *  @returns NULL if layer has no sublayers
60  */
61 SPObject *first_descendant_layer(SPObject *layer) {
62     using std::find_if;
64     SPObject *first_descendant=NULL;
65     while (layer) {
66         layer = find_if<SPObject::SiblingIterator>(
67             layer->firstChild(), NULL, &is_layer
68         );
69         if (layer) {
70             first_descendant = layer;
71         }
72     }
74     return first_descendant;
75 }
77 /** Finds the last (topmost) child of a \a layer
78  *
79  *  @returns NULL if layer has no sublayers
80  */
81 SPObject *last_child_layer(SPObject *layer) {
82     using Inkscape::Algorithms::find_last_if;
84     return find_last_if<SPObject::SiblingIterator>(
85         layer->firstChild(), NULL, &is_layer
86     );
87 }
89 SPObject *last_elder_layer(SPObject *root, SPObject *layer) {
90     using Inkscape::Algorithms::find_last_if;
92     while ( layer != root ) {
93         SPObject *sibling(previous_sibling_layer(layer));
94         if (sibling) {
95             return sibling;
96         }
97         layer = SP_OBJECT_PARENT(layer);
98     }
100     return NULL;
105 /** Finds the next layer under \a root, relative to \a layer in
106  *  depth-first order.
107  *
108  *  @returns NULL if there are no further layers under \a root
109  */
110 SPObject *next_layer(SPObject *root, SPObject *layer) {
111     using std::find_if;
113     g_return_val_if_fail(layer != NULL, NULL);
115     SPObject *sibling(next_sibling_layer(layer));
116     if (sibling) {
117         SPObject *descendant(first_descendant_layer(sibling));
118         if (descendant) {
119             return descendant;
120         } else {
121             return sibling;
122         }
123     } else {
124         SPObject *parent=SP_OBJECT_PARENT(layer);
125         if ( parent != root ) {
126             return parent;
127         } else {
128             return NULL;
129         }
130     }
134 /** Finds the previous layer under \a root, relative to \a layer in
135  *  depth-first order.
136  *
137  *  @returns NULL if there are no prior layers under \a root.
138  */
139 SPObject *previous_layer(SPObject *root, SPObject *layer) {
140     using Inkscape::Algorithms::find_last_if;
142     g_return_val_if_fail(layer != NULL, NULL);
144     SPObject *child(last_child_layer(layer));
145     if (child) {
146         return child;
147     } else if ( layer != root ) {
148         SPObject *sibling(previous_sibling_layer(layer));
149         if (sibling) {
150             return sibling;
151         } else {
152             return last_elder_layer(root, SP_OBJECT_PARENT(layer));
153         }
154     }
156     return NULL;
159 /**
160 *  Creates a new layer.  Advances to the next layer id indicated
161  *  by the string "layerNN", then creates a new group object of
162  *  that id with attribute inkscape:groupmode='layer', and finally
163  *  appends the new group object to \a root after object \a layer.
164  *
165  *  \pre \a root should be either \a layer or an ancestor of it
166  */
167 SPObject *create_layer(SPObject *root, SPObject *layer, LayerRelativePosition position) {
168     SPDocument *document=SP_OBJECT_DOCUMENT(root);
169     
170     static int layer_suffix=1;
171     gchar *id=NULL;
172     do {
173         g_free(id);
174         id = g_strdup_printf("layer%d", layer_suffix++);
175     } while (document->getObjectById(id));
176     
177     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
178     Inkscape::XML::Node *repr = xml_doc->createElement("svg:g");
179     repr->setAttribute("inkscape:groupmode", "layer");
180     repr->setAttribute("id", id);
181     g_free(id);
182     
183     if ( LPOS_CHILD == position ) {
184         root = layer;
185         SPObject *child_layer = Inkscape::last_child_layer(layer);
186         if ( NULL != child_layer ) {
187             layer = child_layer;
188         }
189     }
190     
191     if ( root == layer ) {
192         SP_OBJECT_REPR(root)->appendChild(repr);
193     } else {
194         Inkscape::XML::Node *layer_repr=SP_OBJECT_REPR(layer);
195         sp_repr_parent(layer_repr)->addChild(repr, layer_repr);
196         
197         if ( LPOS_BELOW == position ) {
198             SP_ITEM(document->getObjectByRepr(repr))->lowerOne();
199         }
200     }
201     
202     return document->getObjectByRepr(repr);
207 /*
208   Local Variables:
209   mode:c++
210   c-file-style:"stroustrup"
211   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
212   indent-tabs-mode:nil
213   fill-column:99
214   End:
215 */
216 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :