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"
21 namespace Inkscape {
23 /**
24 * Creates a new layer. Advances to the next layer id indicated
25 * by the string "layerNN", then creates a new group object of
26 * that id with attribute inkscape:groupmode='layer', and finally
27 * appends the new group object to \a root after object \a layer.
28 *
29 * \pre \a root should be either \a layer or an ancestor of it
30 */
31 SPObject *create_layer(SPObject *root, SPObject *layer) {
32 SPDocument *document=SP_OBJECT_DOCUMENT(root);
34 static int layer_suffix=1;
35 gchar *id=NULL;
36 do {
37 g_free(id);
38 id = g_strdup_printf("layer%d", layer_suffix++);
39 } while (document->getObjectById(id));
41 Inkscape::XML::Node *repr=sp_repr_new("svg:g");
42 repr->setAttribute("inkscape:groupmode", "layer");
43 repr->setAttribute("id", id);
44 g_free(id);
46 if ( root == layer ) {
47 SP_OBJECT_REPR(root)->appendChild(repr);
48 } else {
49 Inkscape::XML::Node *layer_repr=SP_OBJECT_REPR(layer);
50 sp_repr_parent(layer_repr)->addChild(repr, layer_repr);
51 }
53 return document->getObjectByRepr(repr);
54 }
56 namespace {
58 bool is_layer(SPObject &object) {
59 return SP_IS_GROUP(&object) &&
60 SP_GROUP(&object)->layerMode() == SPGroup::LAYER;
61 }
63 SPObject *next_sibling_layer(SPObject *layer) {
64 using std::find_if;
66 return find_if<SPObject::SiblingIterator>(
67 SP_OBJECT_NEXT(layer), NULL, &is_layer
68 );
69 }
71 SPObject *previous_sibling_layer(SPObject *layer) {
72 using Inkscape::Algorithms::find_last_if;
74 SPObject *sibling(find_last_if<SPObject::SiblingIterator>(
75 SP_OBJECT_PARENT(layer)->firstChild(), layer, &is_layer
76 ));
78 return ( sibling != layer ) ? sibling : NULL;
79 }
81 SPObject *first_descendant_layer(SPObject *layer) {
82 using std::find_if;
84 SPObject *first_descendant=NULL;
85 while (layer) {
86 layer = find_if<SPObject::SiblingIterator>(
87 layer->firstChild(), NULL, &is_layer
88 );
89 if (layer) {
90 first_descendant = layer;
91 }
92 }
94 return first_descendant;
95 }
97 SPObject *last_child_layer(SPObject *layer) {
98 using Inkscape::Algorithms::find_last_if;
100 return find_last_if<SPObject::SiblingIterator>(
101 layer->firstChild(), NULL, &is_layer
102 );
103 }
105 SPObject *last_elder_layer(SPObject *root, SPObject *layer) {
106 using Inkscape::Algorithms::find_last_if;
108 while ( layer != root ) {
109 SPObject *sibling(previous_sibling_layer(layer));
110 if (sibling) {
111 return sibling;
112 }
113 layer = SP_OBJECT_PARENT(layer);
114 }
116 return NULL;
117 }
119 }
121 /** Finds the next layer under \a root, relative to \a layer in
122 * depth-first order.
123 *
124 * @returns NULL if there are no further layers under \a root
125 */
126 SPObject *next_layer(SPObject *root, SPObject *layer) {
127 using std::find_if;
129 g_return_val_if_fail(layer != NULL, NULL);
131 SPObject *sibling(next_sibling_layer(layer));
132 if (sibling) {
133 SPObject *descendant(first_descendant_layer(sibling));
134 if (descendant) {
135 return descendant;
136 } else {
137 return sibling;
138 }
139 } else {
140 SPObject *parent=SP_OBJECT_PARENT(layer);
141 if ( parent != root ) {
142 return parent;
143 } else {
144 return NULL;
145 }
146 }
147 }
150 /** Finds the previous layer under \a root, relative to \a layer in
151 * depth-first order.
152 *
153 * @returns NULL if there are no prior layers under \a root.
154 */
155 SPObject *previous_layer(SPObject *root, SPObject *layer) {
156 using Inkscape::Algorithms::find_last_if;
158 g_return_val_if_fail(layer != NULL, NULL);
160 SPObject *child(last_child_layer(layer));
161 if (child) {
162 return child;
163 } else if ( layer != root ) {
164 SPObject *sibling(previous_sibling_layer(layer));
165 if (sibling) {
166 return sibling;
167 } else {
168 return last_elder_layer(root, SP_OBJECT_PARENT(layer));
169 }
170 }
172 return NULL;
173 }
175 }
177 /*
178 Local Variables:
179 mode:c++
180 c-file-style:"stroustrup"
181 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
182 indent-tabs-mode:nil
183 fill-column:99
184 End:
185 */
186 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :