Code

moving trunk for module inkscape
[inkscape.git] / src / sp-namedview.cpp
1 #define __SP_NAMEDVIEW_C__
3 /*
4  * <sodipodi:namedview> implementation
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 1999-2005 Authors
11  * Copyright (C) 2000-2001 Ximian, Inc.
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #include "config.h"
21 #include "display/canvas-grid.h"
22 #include "helper/units.h"
23 #include "svg/svg.h"
24 #include "xml/repr.h"
25 #include "attributes.h"
26 #include "document.h"
27 #include "desktop-events.h"
28 #include "desktop-handles.h"
29 #include "sp-guide.h"
30 #include "sp-item-group.h"
31 #include "sp-namedview.h"
32 #include "prefs-utils.h"
33 #include "desktop.h"
35 #include "isnan.h" //temp fox for isnan().  include last
37 #define DEFAULTTOLERANCE 0.4
38 #define DEFAULTGRIDCOLOR 0x3f3fff25
39 #define DEFAULTGRIDEMPCOLOR 0x3f3fff60
40 #define DEFAULTGRIDEMPSPACING 5
41 #define DEFAULTGUIDECOLOR 0x0000ff7f
42 #define DEFAULTGUIDEHICOLOR 0xff00007f
43 #define DEFAULTBORDERCOLOR 0x000000ff
44 #define DEFAULTPAGECOLOR 0xffffff00
46 static void sp_namedview_class_init(SPNamedViewClass *klass);
47 static void sp_namedview_init(SPNamedView *namedview);
49 static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
50 static void sp_namedview_release(SPObject *object);
51 static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *value);
52 static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
53 static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *child);
54 static Inkscape::XML::Node *sp_namedview_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
56 static void sp_namedview_setup_guides(SPNamedView * nv);
58 static void sp_namedview_setup_grid(SPNamedView * nv);
59 static void sp_namedview_setup_grid_item(SPNamedView * nv, SPCanvasItem * item);
61 static gboolean sp_str_to_bool(const gchar *str);
62 static gboolean sp_nv_read_length(const gchar *str, guint base, gdouble *val, const SPUnit **unit);
63 static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color);
65 static SPObjectGroupClass * parent_class;
67 GType
68 sp_namedview_get_type()
69 {
70     static GType namedview_type = 0;
71     if (!namedview_type) {
72         GTypeInfo namedview_info = {
73             sizeof(SPNamedViewClass),
74             NULL,       /* base_init */
75             NULL,       /* base_finalize */
76             (GClassInitFunc) sp_namedview_class_init,
77             NULL,       /* class_finalize */
78             NULL,       /* class_data */
79             sizeof(SPNamedView),
80             16, /* n_preallocs */
81             (GInstanceInitFunc) sp_namedview_init,
82             NULL,       /* value_table */
83         };
84         namedview_type = g_type_register_static(SP_TYPE_OBJECTGROUP, "SPNamedView", &namedview_info, (GTypeFlags)0);
85     }
86     return namedview_type;
87 }
89 static void sp_namedview_class_init(SPNamedViewClass * klass)
90 {
91     GObjectClass * gobject_class;
92     SPObjectClass * sp_object_class;
93     
94     gobject_class = (GObjectClass *) klass;
95     sp_object_class = (SPObjectClass *) klass;
96     
97     parent_class = (SPObjectGroupClass*) g_type_class_ref(SP_TYPE_OBJECTGROUP);
98     
99     sp_object_class->build = sp_namedview_build;
100     sp_object_class->release = sp_namedview_release;
101     sp_object_class->set = sp_namedview_set;
102     sp_object_class->child_added = sp_namedview_child_added;
103     sp_object_class->remove_child = sp_namedview_remove_child;
104     sp_object_class->write = sp_namedview_write;
107 static void sp_namedview_init(SPNamedView *nv)
109     nv->editable = TRUE;
110     nv->showgrid = FALSE;
111     nv->showguides = TRUE;
112     nv->showborder = TRUE;
113     nv->showpageshadow = TRUE;
114     
115     nv->guides = NULL;
116     nv->viewcount = 0;
117     
118     nv->default_layer_id = 0;
119     
120     new (&nv->grid_snapper) Inkscape::GridSnapper(nv, 0);
121     new (&nv->guide_snapper) Inkscape::GuideSnapper(nv, 0);
122     new (&nv->object_snapper) Inkscape::ObjectSnapper(nv, 0);
125 static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
127     SPNamedView *nv = (SPNamedView *) object;
128     SPObjectGroup *og = (SPObjectGroup *) object;
129     
130     if (((SPObjectClass *) (parent_class))->build) {
131         (* ((SPObjectClass *) (parent_class))->build)(object, document, repr);
132     }
133     
134     sp_object_read_attr(object, "inkscape:document-units");
135     sp_object_read_attr(object, "viewonly");
136     sp_object_read_attr(object, "showgrid");
137     sp_object_read_attr(object, "showguides");
138     sp_object_read_attr(object, "gridtolerance");
139     sp_object_read_attr(object, "guidetolerance");
140     sp_object_read_attr(object, "objecttolerance");
141     sp_object_read_attr(object, "inkscape:has_abs_tolerance");
142     sp_object_read_attr(object, "gridoriginx");
143     sp_object_read_attr(object, "gridoriginy");
144     sp_object_read_attr(object, "gridspacingx");
145     sp_object_read_attr(object, "gridspacingy");
146     sp_object_read_attr(object, "gridempspacing");
147     sp_object_read_attr(object, "gridcolor");
148     sp_object_read_attr(object, "gridempcolor");
149     sp_object_read_attr(object, "gridopacity");
150     sp_object_read_attr(object, "gridempopacity");
151     sp_object_read_attr(object, "guidecolor");
152     sp_object_read_attr(object, "guideopacity");
153     sp_object_read_attr(object, "guidehicolor");
154     sp_object_read_attr(object, "guidehiopacity");
155     sp_object_read_attr(object, "showborder");
156     sp_object_read_attr(object, "inkscape:showpageshadow");
157     sp_object_read_attr(object, "borderlayer");
158     sp_object_read_attr(object, "bordercolor");
159     sp_object_read_attr(object, "borderopacity");
160     sp_object_read_attr(object, "pagecolor");
161     sp_object_read_attr(object, "inkscape:pageopacity");
162     sp_object_read_attr(object, "inkscape:pageshadow");
163     sp_object_read_attr(object, "inkscape:zoom");
164     sp_object_read_attr(object, "inkscape:cx");
165     sp_object_read_attr(object, "inkscape:cy");
166     sp_object_read_attr(object, "inkscape:window-width");
167     sp_object_read_attr(object, "inkscape:window-height");
168     sp_object_read_attr(object, "inkscape:window-x");
169     sp_object_read_attr(object, "inkscape:window-y");
170     sp_object_read_attr(object, "inkscape:grid-bbox");
171     sp_object_read_attr(object, "inkscape:guide-bbox");
172     sp_object_read_attr(object, "inkscape:object-bbox");
173     sp_object_read_attr(object, "inkscape:grid-points");
174     sp_object_read_attr(object, "inkscape:guide-points");
175     sp_object_read_attr(object, "inkscape:object-points");
176     sp_object_read_attr(object, "inkscape:object-paths");
177     sp_object_read_attr(object, "inkscape:object-nodes");
178     sp_object_read_attr(object, "inkscape:current-layer");
179     
180     /* Construct guideline list */
181     
182     for (SPObject *o = sp_object_first_child(SP_OBJECT(og)) ; o != NULL; o = SP_OBJECT_NEXT(o) ) {
183         if (SP_IS_GUIDE(o)) {
184             SPGuide * g = SP_GUIDE(o);
185             nv->guides = g_slist_prepend(nv->guides, g);
186             g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL);
187         }
188     }
191 static void sp_namedview_release(SPObject *object)
193     SPNamedView *namedview = (SPNamedView *) object;
194     
195     if (namedview->guides) {
196         g_slist_free(namedview->guides);
197         namedview->guides = NULL;
198     }
199     
200     while (namedview->gridviews) {
201         gtk_object_unref(GTK_OBJECT(namedview->gridviews->data));
202         namedview->gridviews = g_slist_remove(namedview->gridviews, namedview->gridviews->data);
203     }
204     
205     namedview->grid_snapper.~GridSnapper();
206     namedview->guide_snapper.~GuideSnapper();
207     namedview->object_snapper.~ObjectSnapper();
208     
209     if (((SPObjectClass *) parent_class)->release) {
210         ((SPObjectClass *) parent_class)->release(object);
211     }
214 static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *value)
216     SPNamedView *nv = SP_NAMEDVIEW(object);
217     SPUnit const &px = sp_unit_get_by_id(SP_UNIT_PX);
219     switch (key) {
220         case SP_ATTR_VIEWONLY:
221             nv->editable = (!value);
222             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
223             break;
224         case SP_ATTR_SHOWGRID:
225             nv->showgrid = sp_str_to_bool(value);
226             sp_namedview_setup_grid(nv);
227             if (!nv->showgrid) { // grid goes off, disable snaps even if they are turned on
228                 nv->grid_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, false);
229                 nv->grid_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, false);
230             } else { // grid goes on, enable snaps if they are turned on
231                 nv->grid_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, nv->snap_grid_bbox);
232                 nv->grid_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, nv->snap_grid_point);
233             }
234             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
235             break;
236         case SP_ATTR_SHOWGUIDES:
237             if (!value) { // show guides if not specified, for backwards compatibility
238                 nv->showguides = TRUE;
239             } else {
240                 nv->showguides = sp_str_to_bool(value);
241             }
242             if (!nv->showguides) { // guides go off, disable snaps even if they are turned on
243                 nv->guide_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, false);
244                 nv->guide_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, false);
245             } else { // guides go on, enable snaps if they are turned on
246                 nv->guide_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, nv->snap_guide_bbox);
247                 nv->guide_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, nv->snap_guide_point);
248             }
249             sp_namedview_setup_guides(nv);
250             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
251             break;
252         case SP_ATTR_GRIDTOLERANCE:
253             nv->gridtoleranceunit = &px;
254             nv->gridtolerance = DEFAULTTOLERANCE;
255             if (value) {
256                 sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &nv->gridtolerance, &nv->gridtoleranceunit);
257             }
258             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
259             break;
260         case SP_ATTR_GUIDETOLERANCE:
261             nv->guidetoleranceunit = &px;
262             nv->guidetolerance = DEFAULTTOLERANCE;
263             if (value) {
264                 sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &nv->guidetolerance, &nv->guidetoleranceunit);
265             }
266             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
267             break;
268         case SP_ATTR_OBJECTTOLERANCE:
269             nv->objecttoleranceunit = &px;
270             nv->objecttolerance = DEFAULTTOLERANCE;
271             if (value) {
272                 sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &nv->objecttolerance, &nv->objecttoleranceunit);
273             }
274             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
275             break;
276         case SP_ATTR_ABS_TOLERANCE:
277              if (!value)
278                  nv->has_abs_tolerance = true;
279              else
280                  nv->has_abs_tolerance = (sp_str_to_bool (value) == TRUE);
281              object->requestModified(SP_OBJECT_MODIFIED_FLAG);
282              break;
283         case SP_ATTR_GRIDORIGINX:
284         case SP_ATTR_GRIDORIGINY:
285         {
286             unsigned const d = (key == SP_ATTR_GRIDORIGINY);
287             nv->gridunit = nv->doc_units;
288             nv->gridorigin[d] = 0.0;
289             if (value) {
290                 sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &nv->gridorigin[d], &nv->gridunit);
291             }
292             nv->gridorigin[d] = sp_units_get_pixels(nv->gridorigin[d], *(nv->gridunit));
293             sp_namedview_setup_grid(nv);
294             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
295             break;
296         }
297         case SP_ATTR_GRIDSPACINGX:
298         case SP_ATTR_GRIDSPACINGY:
299         {
300             unsigned const d = (key == SP_ATTR_GRIDSPACINGY);
301             nv->gridunit = nv->doc_units;
302             nv->gridspacing[d] = 1.0;
303             if (value) {
304                 sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &nv->gridspacing[d], &nv->gridunit);
305             }
306             nv->gridspacing[d] = sp_units_get_pixels(nv->gridspacing[d], *(nv->gridunit));
307             sp_namedview_setup_grid(nv);
308             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
309             break;
310         }
311         case SP_ATTR_GRIDCOLOR:
312             nv->gridcolor = (nv->gridcolor & 0xff) | (DEFAULTGRIDCOLOR & 0xffffff00);
313             if (value) {
314                 nv->gridcolor = (nv->gridcolor & 0xff) | sp_svg_read_color(value, nv->gridcolor);
315             }
316             sp_namedview_setup_grid(nv);
317             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
318             break;
319         case SP_ATTR_GRIDEMPCOLOR:
320             nv->gridempcolor = (nv->gridempcolor & 0xff) | (DEFAULTGRIDEMPCOLOR & 0xffffff00);
321             if (value) {
322                 nv->gridempcolor = (nv->gridempcolor & 0xff) | sp_svg_read_color(value, nv->gridempcolor);
323             }
324             sp_namedview_setup_grid(nv);
325             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
326             break;
327         case SP_ATTR_GRIDOPACITY:
328             nv->gridcolor = (nv->gridcolor & 0xffffff00) | (DEFAULTGRIDCOLOR & 0xff);
329             sp_nv_read_opacity(value, &nv->gridcolor);
330             sp_namedview_setup_grid(nv);
331             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
332             break;
333         case SP_ATTR_GRIDEMPOPACITY:
334             nv->gridempcolor = (nv->gridempcolor & 0xffffff00) | (DEFAULTGRIDEMPCOLOR & 0xff);
335             sp_nv_read_opacity(value, &nv->gridempcolor);
336             sp_namedview_setup_grid(nv);
337             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
338             break;
339         case SP_ATTR_GRIDEMPSPACING:
340             nv->gridempspacing = DEFAULTGRIDEMPSPACING;
341             if (value != NULL)
342                 nv->gridempspacing = atoi(value);
343             sp_namedview_setup_grid(nv);
344             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
345             break;
346         case SP_ATTR_GUIDECOLOR:
347             nv->guidecolor = (nv->guidecolor & 0xff) | (DEFAULTGUIDECOLOR & 0xffffff00);
348             if (value) {
349                 nv->guidecolor = (nv->guidecolor & 0xff) | sp_svg_read_color(value, nv->guidecolor);
350             }
351             for (GSList *l = nv->guides; l != NULL; l = l->next) {
352                 g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL);
353             }
354             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
355             break;
356         case SP_ATTR_GUIDEOPACITY:
357             nv->guidecolor = (nv->guidecolor & 0xffffff00) | (DEFAULTGUIDECOLOR & 0xff);
358             sp_nv_read_opacity(value, &nv->guidecolor);
359             for (GSList *l = nv->guides; l != NULL; l = l->next) {
360                 g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL);
361             }
362             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
363             break;
364         case SP_ATTR_GUIDEHICOLOR:
365             nv->guidehicolor = (nv->guidehicolor & 0xff) | (DEFAULTGUIDEHICOLOR & 0xffffff00);
366             if (value) {
367                 nv->guidehicolor = (nv->guidehicolor & 0xff) | sp_svg_read_color(value, nv->guidehicolor);
368             }
369             for (GSList *l = nv->guides; l != NULL; l = l->next) {
370                 g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL);
371             }
372             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
373             break;
374         case SP_ATTR_GUIDEHIOPACITY:
375             nv->guidehicolor = (nv->guidehicolor & 0xffffff00) | (DEFAULTGUIDEHICOLOR & 0xff);
376             sp_nv_read_opacity(value, &nv->guidehicolor);
377             for (GSList *l = nv->guides; l != NULL; l = l->next) {
378                 g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL);
379             }
380             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
381             break;
382         case SP_ATTR_SHOWBORDER:
383             nv->showborder = (value) ? sp_str_to_bool (value) : TRUE;
384             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
385             break;
386         case SP_ATTR_BORDERLAYER:
387             nv->borderlayer = SP_BORDER_LAYER_BOTTOM;
388             if (value && !strcasecmp(value, "true")) nv->borderlayer = SP_BORDER_LAYER_TOP;
389             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
390             break;
391         case SP_ATTR_BORDERCOLOR:
392             nv->bordercolor = (nv->bordercolor & 0xff) | (DEFAULTBORDERCOLOR & 0xffffff00);
393             if (value) {
394                 nv->bordercolor = (nv->bordercolor & 0xff) | sp_svg_read_color (value, nv->bordercolor);
395             }
396             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
397             break;
398         case SP_ATTR_BORDEROPACITY:
399             nv->bordercolor = (nv->bordercolor & 0xffffff00) | (DEFAULTBORDERCOLOR & 0xff);
400             sp_nv_read_opacity(value, &nv->bordercolor);
401             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
402             break;
403         case SP_ATTR_PAGECOLOR:
404             nv->pagecolor = (nv->pagecolor & 0xff) | (DEFAULTPAGECOLOR & 0xffffff00);
405             if (value) {
406                 nv->pagecolor = (nv->pagecolor & 0xff) | sp_svg_read_color(value, nv->pagecolor);
407             }
408             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
409             break;
410         case SP_ATTR_INKSCAPE_PAGEOPACITY:
411             nv->pagecolor = (nv->pagecolor & 0xffffff00) | (DEFAULTPAGECOLOR & 0xff);
412             sp_nv_read_opacity(value, &nv->pagecolor);
413             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
414             break;
415         case SP_ATTR_INKSCAPE_PAGESHADOW:
416             nv->pageshadow = value? atoi(value) : 2; // 2 is the default
417             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
418             break;
419         case SP_ATTR_SHOWPAGESHADOW:
420             nv->showpageshadow = (value) ? sp_str_to_bool(value) : TRUE;
421             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
422             break;
423         case SP_ATTR_INKSCAPE_ZOOM:
424             nv->zoom = value ? g_ascii_strtod(value, NULL) : 0; // zero means not set
425             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
426             break;
427         case SP_ATTR_INKSCAPE_CX:
428             nv->cx = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set
429             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
430             break;
431         case SP_ATTR_INKSCAPE_CY:
432             nv->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set
433             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
434             break;
435         case SP_ATTR_INKSCAPE_WINDOW_WIDTH:
436             nv->window_width = value? atoi(value) : -1; // -1 means not set
437             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
438             break;
439         case SP_ATTR_INKSCAPE_WINDOW_HEIGHT:
440             nv->window_height = value ? atoi(value) : -1; // -1 means not set
441             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
442             break;
443         case SP_ATTR_INKSCAPE_WINDOW_X:
444             nv->window_x = value ? atoi(value) : -1; // -1 means not set
445             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
446             break;
447         case SP_ATTR_INKSCAPE_WINDOW_Y:
448             nv->window_y = value ? atoi(value) : -1; // -1 means not set
449             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
450             break;
451         case SP_ATTR_INKSCAPE_GRID_BBOX:
452             nv->snap_grid_bbox = (value) ? sp_str_to_bool(value) : TRUE;
453             nv->grid_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, nv->showgrid && nv->snap_grid_bbox);
454             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
455             break;
456         case SP_ATTR_INKSCAPE_GRID_POINTS:
457             nv->snap_grid_point = (value) ? sp_str_to_bool(value) : FALSE;
458             nv->grid_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, nv->showgrid && nv->snap_grid_point);
459             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
460             break;
461         case SP_ATTR_INKSCAPE_GUIDE_BBOX:
462             nv->snap_guide_bbox = (value) ? sp_str_to_bool(value) : TRUE;
463             nv->guide_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, nv->showguides && nv->snap_guide_bbox);
464             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
465             break;
466         case SP_ATTR_INKSCAPE_GUIDE_POINTS:
467             nv->snap_guide_point = (value) ? sp_str_to_bool(value) : FALSE;
468             nv->guide_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, nv->showguides && nv->snap_guide_point);
469             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
470             break;
471         case SP_ATTR_INKSCAPE_OBJECT_BBOX:
472             nv->snap_object_bbox = (value) ? sp_str_to_bool(value) : FALSE;
473             nv->object_snapper.setSnapTo(Inkscape::Snapper::BBOX_POINT, nv->snap_object_bbox);
474             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
475             break;
476         case SP_ATTR_INKSCAPE_OBJECT_POINTS:
477             nv->snap_object_point = (value) ? sp_str_to_bool(value) : FALSE;
478             nv->object_snapper.setSnapTo(Inkscape::Snapper::SNAP_POINT, nv->snap_object_point);
479             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
480             break;
481         case SP_ATTR_INKSCAPE_OBJECT_PATHS:
482             nv->snap_object_paths = (value) ? sp_str_to_bool(value) : TRUE;
483             nv->object_snapper.setSnapToPaths(nv->snap_object_paths);
484             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
485             break;
486         case SP_ATTR_INKSCAPE_OBJECT_NODES:
487             nv->snap_object_nodes = (value) ? sp_str_to_bool(value) : TRUE;
488             nv->object_snapper.setSnapToNodes(nv->snap_object_nodes);
489             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
490             break;
491         case SP_ATTR_INKSCAPE_CURRENT_LAYER:
492             nv->default_layer_id = value ? g_quark_from_string(value) : 0;
493             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
494             break;
495         case SP_ATTR_INKSCAPE_DOCUMENT_UNITS: {
496             /* The default unit if the document doesn't override this: e.g. for files saved as
497              * `plain SVG', or non-inkscape files, or files created by an inkscape 0.40 &
498              * earlier.
499              *
500              * Here we choose `px': useful for screen-destined SVGs, and fewer bug reports
501              * about "not the same numbers as what's in the SVG file" (at least for documents
502              * without a viewBox attribute on the root <svg> element).  Similarly, it's also
503              * the most reliable unit (i.e. least likely to be wrong in different viewing
504              * conditions) for viewBox-less SVG files given that it's the unit that inkscape
505              * uses for all coordinates.
506              *
507              * For documents that do have a viewBox attribute on the root <svg> element, it
508              * might be better if we used either viewBox coordinates or if we used the unit of
509              * say the width attribute of the root <svg> element.  However, these pose problems
510              * in that they aren't in general absolute units as currently required by
511              * doc_units.
512              */
513             SPUnit const *new_unit = &sp_unit_get_by_id(SP_UNIT_PX);
514             
515             if (value) {
516                 SPUnit const *const req_unit = sp_unit_get_by_abbreviation(value);
517                 if ( req_unit == NULL ) {
518                     g_warning("Unrecognized unit `%s'", value);
519                     /* fixme: Document errors should be reported in the status bar or
520                      * the like (e.g. as per
521                      * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing); g_log
522                      * should be only for programmer errors. */
523                 } else if ( req_unit->base == SP_UNIT_ABSOLUTE ||
524                             req_unit->base == SP_UNIT_DEVICE     ) {
525                     new_unit = req_unit;
526                 } else {
527                     g_warning("Document units must be absolute like `mm', `pt' or `px', but found `%s'",
528                               value);
529                     /* fixme: Don't use g_log (see above). */
530                 }
531             }
532             nv->doc_units = new_unit;
533             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
534             break;
535         }
536         default:
537             if (((SPObjectClass *) (parent_class))->set) {
538                 ((SPObjectClass *) (parent_class))->set(object, key, value);
539             }
540             break;
541     }
544 static void sp_namedview_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
546     SPNamedView *nv = (SPNamedView *) object;
547     
548     if (((SPObjectClass *) (parent_class))->child_added) {
549         (* ((SPObjectClass *) (parent_class))->child_added)(object, child, ref);
550     }
551     
552     const gchar *id = child->attribute("id");
553     SPObject *no = object->document->getObjectById(id);
554     g_assert(SP_IS_OBJECT(no));
555     
556     if (SP_IS_GUIDE(no)) {
557         SPGuide *g = (SPGuide *) no;
558         nv->guides = g_slist_prepend(nv->guides, g);
559         g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL);
560         if (nv->editable) {
561             for (GSList *l = nv->views; l != NULL; l = l->next) {
562                 sp_guide_show(g, static_cast<SPDesktop*>(l->data)->guides, (GCallback) sp_dt_guide_event);
563                 if (static_cast<SPDesktop*>(l->data)->guides_active) 
564                     sp_guide_sensitize(g, 
565                                        SP_DT_CANVAS(static_cast<SPDesktop*> (l->data)), 
566                                        TRUE);
567                 if (nv->showguides) {
568                     for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
569                         sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
570                     }
571                 } else {
572                     for (GSList *v = SP_GUIDE(g)->views; v != NULL; v = v->next) {
573                         sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
574                     }
575                 }
576             }
577         }
578     }
581 static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *child)
583     SPNamedView *nv = (SPNamedView *) object;
584     
585     GSList **ref = &nv->guides;
586     for ( GSList *iter = nv->guides ; iter ; iter = iter->next ) {
587         if ( SP_OBJECT_REPR((SPObject *)iter->data) == child ) {
588             *ref = iter->next;
589             iter->next = NULL;
590             g_slist_free_1(iter);
591             break;
592         }
593         ref = &iter->next;
594     }
595     
596     if (((SPObjectClass *) (parent_class))->remove_child) {
597         (* ((SPObjectClass *) (parent_class))->remove_child)(object, child);
598     }
601 static Inkscape::XML::Node *sp_namedview_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
603     if ( ( flags & SP_OBJECT_WRITE_EXT ) &&
604          repr != SP_OBJECT_REPR(object) )
605     {
606         if (repr) {
607             repr->mergeFrom(SP_OBJECT_REPR(object), "id");
608         } else {
609             repr = SP_OBJECT_REPR(object)->duplicate();
610         }
611     }
612     
613     return repr;
616 void SPNamedView::show(SPDesktop *desktop)
618     for (GSList *l = guides; l != NULL; l = l->next) {
619         sp_guide_show(SP_GUIDE(l->data), desktop->guides, (GCallback) sp_dt_guide_event);
620         if (desktop->guides_active) {
621             sp_guide_sensitize(SP_GUIDE(l->data), SP_DT_CANVAS(desktop), TRUE);
622         }
623         if (showguides) {
624             for (GSList *v = SP_GUIDE(l->data)->views; v != NULL; v = v->next) {
625                 sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
626             }
627         } else {
628             for (GSList *v = SP_GUIDE(l->data)->views; v != NULL; v = v->next) {
629                 sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
630             }
631         }
632     }
633     
634     views = g_slist_prepend(views, desktop);
635     
636     SPCanvasItem *item = sp_canvas_item_new(SP_DT_GRID(desktop), SP_TYPE_CGRID, NULL);
637     // since we're keeping a copy, we need to bump up the ref count
638     gtk_object_ref(GTK_OBJECT(item));
639     gridviews = g_slist_prepend(gridviews, item);
640     sp_namedview_setup_grid_item(this, item);
643 /*
644  * Restores window geometry from the document settings
645  */
646 void sp_namedview_window_from_document(SPDesktop *desktop)
648     SPNamedView *nv = desktop->namedview;
649     gint save_geometry = prefs_get_int_attribute("options.savewindowgeometry", "value", 0);
650     
651     // restore window size and position
652     if (save_geometry) {
653         if (nv->window_width != -1 && nv->window_height != -1)
654             desktop->setWindowSize(nv->window_width, nv->window_height);
655         if (nv->window_x != -1 && nv->window_y != -1)
656             desktop->setWindowPosition(NR::Point(nv->window_x, nv->window_y));
657     }
658     
659     // restore zoom and view
660     if (nv->zoom != 0 && nv->zoom != HUGE_VAL && !isNaN(nv->zoom)
661         && nv->cx != HUGE_VAL && !isNaN(nv->cx) 
662         && nv->cy != HUGE_VAL && !isNaN(nv->cy)) {
663         desktop->zoom_absolute(nv->cx, nv->cy, nv->zoom);
664     } else if (SP_DT_DOCUMENT(desktop)) { // document without saved zoom, zoom to its page
665         desktop->zoom_page();
666     }
667     
668     // cancel any history of zooms up to this point
669     if (desktop->zooms_past) {
670         g_list_free(desktop->zooms_past);
671         desktop->zooms_past = NULL;
672     }
673     
674     SPObject *layer = NULL;
675     SPDocument *document = desktop->doc();
676     if ( nv->default_layer_id != 0 ) {
677         layer = document->getObjectById(g_quark_to_string(nv->default_layer_id));
678     }
679     // don't use that object if it's not at least group
680     if ( !layer || !SP_IS_GROUP(layer) ) {
681         layer = NULL;
682     }
683     // if that didn't work out, look for the topmost layer
684     if (!layer) {
685         SPObject *iter = sp_object_first_child(SP_DOCUMENT_ROOT(document));
686         for ( ; iter ; iter = SP_OBJECT_NEXT(iter) ) {
687             if (desktop->isLayer(iter)) {
688                 layer = iter;
689             }
690         }
691     }
692     if (layer) {
693         desktop->setCurrentLayer(layer);
694     }
697 void sp_namedview_document_from_window(SPDesktop *desktop)
699     gint save_geometry = prefs_get_int_attribute("options.savewindowgeometry", "value", 0);
700     Inkscape::XML::Node *view = SP_OBJECT_REPR(desktop->namedview);
701     NR::Rect const r = desktop->get_display_area();
702     
703     // saving window geometry is not undoable
704     gboolean saved = sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop));
705     sp_document_set_undo_sensitive(SP_DT_DOCUMENT(desktop), FALSE);
706     
707     sp_repr_set_svg_double(view, "inkscape:zoom", desktop->current_zoom());
708     sp_repr_set_svg_double(view, "inkscape:cx", r.midpoint()[NR::X]);
709     sp_repr_set_svg_double(view, "inkscape:cy", r.midpoint()[NR::Y]);
710     
711     if (save_geometry) {
712         gint w, h, x, y;
713         desktop->getWindowGeometry(x, y, w, h);
714         sp_repr_set_int(view, "inkscape:window-width", w);
715         sp_repr_set_int(view, "inkscape:window-height", h);
716         sp_repr_set_int(view, "inkscape:window-x", x);
717         sp_repr_set_int(view, "inkscape:window-y", y);
718     }
719     
720     view->setAttribute("inkscape:current-layer", SP_OBJECT_ID(desktop->currentLayer()));
721     
722     // restore undoability
723     sp_document_set_undo_sensitive(SP_DT_DOCUMENT(desktop), saved);
726 void SPNamedView::hide(SPDesktop const *desktop)
728     g_assert(desktop != NULL);
729     g_assert(g_slist_find(views, desktop));
730     
731     for (GSList *l = guides; l != NULL; l = l->next) {
732         sp_guide_hide(SP_GUIDE(l->data), SP_DT_CANVAS(desktop));
733     }
734     
735     views = g_slist_remove(views, desktop);
737     GSList *l;
738     for (l = gridviews; l != NULL; l = l->next) {
739         if (SP_CANVAS_ITEM(l->data)->canvas == SP_DT_CANVAS(desktop)) {
740             break;
741         }
742     }
744     g_assert(l);
745     
746     sp_canvas_item_hide(SP_CANVAS_ITEM(l->data));
747     gtk_object_unref(GTK_OBJECT(l->data));
748     gridviews = g_slist_remove(gridviews, l->data);
751 void SPNamedView::activateGuides(gpointer desktop, gboolean active)
753     g_assert(desktop != NULL);
754     g_assert(g_slist_find(views, desktop));
755     
756     SPDesktop *dt = static_cast<SPDesktop*>(desktop);
757     
758     for (GSList *l = guides; l != NULL; l = l->next) {
759         sp_guide_sensitize(SP_GUIDE(l->data), SP_DT_CANVAS(dt), active);
760     }
763 static void sp_namedview_setup_guides(SPNamedView *nv)
765     for (GSList *l = nv->guides; l != NULL; l = l->next) {
766         if (nv->showguides) {
767             for (GSList *v = SP_GUIDE(l->data)->views; v != NULL; v = v->next) {
768                 sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
769             }
770         } else {
771             for (GSList *v = SP_GUIDE(l->data)->views; v != NULL; v = v->next) {
772                 sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
773             }
774         }
775     }
778 void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr)
780     unsigned int v;
781     unsigned int set = sp_repr_get_boolean(repr, "showguides", &v);
782     if (!set) { // hide guides if not specified, for backwards compatibility
783         v = FALSE;
784     } else {
785         v = !v;
786     }
787     
788     gboolean saved = sp_document_get_undo_sensitive(doc);
789     sp_document_set_undo_sensitive(doc, FALSE);
790     
791     sp_repr_set_boolean(repr, "showguides", v);
792     
793     doc->rroot->setAttribute("sodipodi:modified", "true");
794     sp_document_set_undo_sensitive(doc, saved);
797 void sp_namedview_toggle_grid(SPDocument *doc, Inkscape::XML::Node *repr)
799     unsigned int v;
800     sp_repr_get_boolean(repr, "showgrid", &v);
801     v = !v;
802     
803     gboolean saved = sp_document_get_undo_sensitive(doc);
804     sp_document_set_undo_sensitive(doc, FALSE);
805     
806     sp_repr_set_boolean(repr, "showgrid", v);
807     
808     doc->rroot->setAttribute("sodipodi:modified", "true");
809     sp_document_set_undo_sensitive(doc, saved);
812 static void sp_namedview_setup_grid(SPNamedView *nv)
814     for (GSList *l = nv->gridviews; l != NULL; l = l->next) {
815         sp_namedview_setup_grid_item(nv, SP_CANVAS_ITEM(l->data));
816     }
819 static void sp_namedview_setup_grid_item(SPNamedView *nv, SPCanvasItem *item)
821     if (nv->showgrid) {
822         sp_canvas_item_show(item);
823     } else {
824         sp_canvas_item_hide(item);
825     }
826     
827     sp_canvas_item_set((GtkObject *) item,
828                        "color", nv->gridcolor,
829                        "originx", nv->gridorigin[NR::X],
830                        "originy", nv->gridorigin[NR::Y],
831                        "spacingx", nv->gridspacing[NR::X],
832                        "spacingy", nv->gridspacing[NR::Y],
833                        "empcolor", nv->gridempcolor,
834                        "empspacing", nv->gridempspacing,
835                        NULL);
838 gchar const *SPNamedView::getName() const
840     SPException ex;
841     SP_EXCEPTION_INIT(&ex);
842     return sp_object_getAttribute(SP_OBJECT(this), "id", &ex);
845 guint SPNamedView::getViewCount()
847     return ++viewcount;
850 GSList const *SPNamedView::getViewList() const
852     return views;
855 /* This should be moved somewhere */
857 static gboolean sp_str_to_bool(const gchar *str)
859     if (str) {
860         if (!g_strcasecmp(str, "true") ||
861             !g_strcasecmp(str, "yes") ||
862             !g_strcasecmp(str, "y") ||
863             (atoi(str) != 0)) {
864             return TRUE;
865         }
866     }
867     
868     return FALSE;
871 /* fixme: Collect all these length parsing methods and think common sane API */
873 static gboolean sp_nv_read_length(const gchar *str, guint base, gdouble *val, const SPUnit **unit)
875     if (!str) {
876         return FALSE;
877     }
879     gchar *u;
880     gdouble v = g_ascii_strtod(str, &u);
881     if (!u) {
882         return FALSE;
883     }
884     while (isspace(*u)) {
885         u += 1;
886     }
887     
888     if (!*u) {
889         /* No unit specified - keep default */
890         *val = v;
891         return TRUE;
892     }
893     
894     if (base & SP_UNIT_DEVICE) {
895         if (u[0] && u[1] && !isalnum(u[2]) && !strncmp(u, "px", 2)) {
896             *unit = &sp_unit_get_by_id(SP_UNIT_PX);
897             *val = v;
898             return TRUE;
899         }
900     }
901     
902     if (base & SP_UNIT_ABSOLUTE) {
903         if (!strncmp(u, "pt", 2)) {
904             *unit = &sp_unit_get_by_id(SP_UNIT_PT);
905         } else if (!strncmp(u, "mm", 2)) {
906             *unit = &sp_unit_get_by_id(SP_UNIT_MM);
907         } else if (!strncmp(u, "cm", 2)) {
908             *unit = &sp_unit_get_by_id(SP_UNIT_CM);
909         } else if (!strncmp(u, "m", 1)) {
910             *unit = &sp_unit_get_by_id(SP_UNIT_M);
911         } else if (!strncmp(u, "in", 2)) {
912             *unit = &sp_unit_get_by_id(SP_UNIT_IN);
913         } else {
914             return FALSE;
915         }
916         *val = v;
917         return TRUE;
918     }
919     
920     return FALSE;
923 static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color)
925     if (!str) {
926         return FALSE;
927     }
929     gchar *u;
930     gdouble v = strtod(str, &u);
931     if (!u) {
932         return FALSE;
933     }
934     v = CLAMP(v, 0.0, 1.0);
935     
936     *color = (*color & 0xffffff00) | (guint32) floor(v * 255.9999);
937     
938     return TRUE;
941 SPNamedView *sp_document_namedview(SPDocument *document, const gchar *id)
943     g_return_val_if_fail(document != NULL, NULL);
944     
945     SPObject *nv = sp_item_group_get_child_by_name((SPGroup *) document->root, NULL, "sodipodi:namedview");
946     g_assert(nv != NULL);
947     
948     if (id == NULL) {
949         return (SPNamedView *) nv;
950     }
951     
952     while (nv && strcmp(nv->id, id)) {
953         nv = sp_item_group_get_child_by_name((SPGroup *) document->root, nv, "sodipodi:namedview");
954     }
955     
956     return (SPNamedView *) nv;
959 /**
960  * Returns namedview's default metric.
961  */
962 SPMetric SPNamedView::getDefaultMetric() const
964     if (doc_units) {
965         return sp_unit_get_metric(doc_units);
966     } else {
967         return SP_PT;
968     }
971 SPNamedView::SnapperList SPNamedView::getSnappers() const
973     SnapperList s;
974     s.push_back(&grid_snapper);
975     s.push_back(&guide_snapper);
976     s.push_back(&object_snapper);
977     return s;
980 /*
981   Local Variables:
982   mode:c++
983   c-file-style:"stroustrup"
984   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
985   indent-tabs-mode:nil
986   fill-column:99
987   End:
988 */
989 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :