Code

Mnemonics in "Input devices", and LPE dialogs (Bug 170765)
[inkscape.git] / src / layer-fns.cpp
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;
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     }
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;
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);
172     
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));
179     
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);
185     
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     }
193     
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);
199         
200         if ( LPOS_BELOW == position ) {
201             SP_ITEM(document->getObjectByRepr(repr))->lowerOne();
202         }
203     }
204     
205     return document->getObjectByRepr(repr);
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 :