1 /*
2 * Inkscape::SelectionDescriber - shows messages describing selection
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 * Jon A. Cruz <jon@joncruz.org>
7 *
8 * Copyright (C) 2004 MenTaLguY
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
17 #include "document.h"
18 #include "sp-item-group.h"
19 #include "xml/repr.h"
20 #include "util/find-last-if.h"
21 #include "layer-fns.h"
23 // TODO move the documentation comments into the .h file
25 namespace Inkscape {
27 namespace {
29 bool is_layer(SPObject &object) {
30 return SP_IS_GROUP(&object) &&
31 SP_GROUP(&object)->layerMode() == SPGroup::LAYER;
32 }
34 /** Finds the next sibling layer for a \a layer
35 *
36 * @returns NULL if there are no further layers under a parent
37 */
38 SPObject *next_sibling_layer(SPObject *layer) {
39 using std::find_if;
41 return find_if<SPObject::SiblingIterator>(
42 layer->getNext(), NULL, &is_layer
43 );
44 }
46 /** Finds the previous sibling layer for a \a layer
47 *
48 * @returns NULL if there are no further layers under a parent
49 */
50 SPObject *previous_sibling_layer(SPObject *layer) {
51 using Inkscape::Algorithms::find_last_if;
53 SPObject *sibling(find_last_if<SPObject::SiblingIterator>(
54 SP_OBJECT_PARENT(layer)->firstChild(), layer, &is_layer
55 ));
57 return ( sibling != layer ) ? sibling : NULL;
58 }
60 /** Finds the first child of a \a layer
61 *
62 * @returns NULL if layer has no sublayers
63 */
64 SPObject *first_descendant_layer(SPObject *layer) {
65 using std::find_if;
67 SPObject *first_descendant=NULL;
68 while (layer) {
69 layer = find_if<SPObject::SiblingIterator>(
70 layer->firstChild(), NULL, &is_layer
71 );
72 if (layer) {
73 first_descendant = layer;
74 }
75 }
77 return first_descendant;
78 }
80 /** Finds the last (topmost) child of a \a layer
81 *
82 * @returns NULL if layer has no sublayers
83 */
84 SPObject *last_child_layer(SPObject *layer) {
85 using Inkscape::Algorithms::find_last_if;
87 return find_last_if<SPObject::SiblingIterator>(
88 layer->firstChild(), NULL, &is_layer
89 );
90 }
92 SPObject *last_elder_layer(SPObject *root, SPObject *layer) {
93 using Inkscape::Algorithms::find_last_if;
95 while ( layer != root ) {
96 SPObject *sibling(previous_sibling_layer(layer));
97 if (sibling) {
98 return sibling;
99 }
100 layer = SP_OBJECT_PARENT(layer);
101 }
103 return NULL;
104 }
106 }
108 /** Finds the next layer under \a root, relative to \a layer in
109 * depth-first order.
110 *
111 * @returns NULL if there are no further layers under \a root
112 */
113 SPObject *next_layer(SPObject *root, SPObject *layer) {
114 using std::find_if;
116 g_return_val_if_fail(layer != NULL, NULL);
118 SPObject *sibling(next_sibling_layer(layer));
119 if (sibling) {
120 SPObject *descendant(first_descendant_layer(sibling));
121 if (descendant) {
122 return descendant;
123 } else {
124 return sibling;
125 }
126 } else {
127 SPObject *parent=SP_OBJECT_PARENT(layer);
128 if ( parent != root ) {
129 return parent;
130 } else {
131 return NULL;
132 }
133 }
134 }
137 /** Finds the previous layer under \a root, relative to \a layer in
138 * depth-first order.
139 *
140 * @returns NULL if there are no prior layers under \a root.
141 */
142 SPObject *previous_layer(SPObject *root, SPObject *layer) {
143 using Inkscape::Algorithms::find_last_if;
145 g_return_val_if_fail(layer != NULL, NULL);
147 SPObject *child(last_child_layer(layer));
148 if (child) {
149 return child;
150 } else if ( layer != root ) {
151 SPObject *sibling(previous_sibling_layer(layer));
152 if (sibling) {
153 return sibling;
154 } else {
155 return last_elder_layer(root, SP_OBJECT_PARENT(layer));
156 }
157 }
159 return NULL;
160 }
162 /**
163 * Creates a new layer. Advances to the next layer id indicated
164 * by the string "layerNN", then creates a new group object of
165 * that id with attribute inkscape:groupmode='layer', and finally
166 * appends the new group object to \a root after object \a layer.
167 *
168 * \pre \a root should be either \a layer or an ancestor of it
169 */
170 SPObject *create_layer(SPObject *root, SPObject *layer, LayerRelativePosition position) {
171 SPDocument *document=SP_OBJECT_DOCUMENT(root);
173 static int layer_suffix=1;
174 gchar *id=NULL;
175 do {
176 g_free(id);
177 id = g_strdup_printf("layer%d", layer_suffix++);
178 } while (document->getObjectById(id));
180 Inkscape::XML::Document *xml_doc = document->getReprDoc();
181 Inkscape::XML::Node *repr = xml_doc->createElement("svg:g");
182 repr->setAttribute("inkscape:groupmode", "layer");
183 repr->setAttribute("id", id);
184 g_free(id);
186 if ( LPOS_CHILD == position ) {
187 root = layer;
188 SPObject *child_layer = Inkscape::last_child_layer(layer);
189 if ( NULL != child_layer ) {
190 layer = child_layer;
191 }
192 }
194 if ( root == layer ) {
195 SP_OBJECT_REPR(root)->appendChild(repr);
196 } else {
197 Inkscape::XML::Node *layer_repr=SP_OBJECT_REPR(layer);
198 sp_repr_parent(layer_repr)->addChild(repr, layer_repr);
200 if ( LPOS_BELOW == position ) {
201 SP_ITEM(document->getObjectByRepr(repr))->lowerOne();
202 }
203 }
205 return document->getObjectByRepr(repr);
206 }
208 }
210 /*
211 Local Variables:
212 mode:c++
213 c-file-style:"stroustrup"
214 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
215 indent-tabs-mode:nil
216 fill-column:99
217 End:
218 */
219 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :