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 "algorithms/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;
101 }
103 }
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 }
131 }
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;
157 }
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);
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));
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);
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 }
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);
197 if ( LPOS_BELOW == position ) {
198 SP_ITEM(document->getObjectByRepr(repr))->lowerOne();
199 }
200 }
202 return document->getObjectByRepr(repr);
203 }
205 }
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 :