Code

Keeping up with trunk
authorTed Gould <ted@gould.cx>
Fri, 1 Jan 2010 04:39:28 +0000 (22:39 -0600)
committerTed Gould <ted@gould.cx>
Fri, 1 Jan 2010 04:39:28 +0000 (22:39 -0600)
71 files changed:
AUTHORS
po/POTFILES.in
po/fr.po
po/inkscape.pot
share/extensions/Barcode/EAN5.py [new file with mode: 0644]
share/extensions/Barcode/Makefile.am
share/extensions/Barcode/__init__.py
share/extensions/Makefile.am
share/extensions/render_barcode.inx
share/extensions/render_barcode_datamatrix.inx [new file with mode: 0644]
share/extensions/render_barcode_datamatrix.py [new file with mode: 0644]
share/extensions/wireframe_sphere.inx [new file with mode: 0644]
share/extensions/wireframe_sphere.py [new file with mode: 0644]
src/Makefile.am
src/box3d-context.cpp
src/box3d.cpp
src/box3d.h
src/conn-avoid-ref.cpp
src/connector-context.cpp
src/display/canvas-axonomgrid.cpp
src/display/canvas-axonomgrid.h
src/display/canvas-grid.cpp
src/display/canvas-grid.h
src/display/snap-indicator.cpp
src/document.cpp
src/document.h
src/event-context.cpp
src/gradient-drag.cpp
src/guide-snapper.cpp
src/guide-snapper.h
src/libnr/nr-compose.cpp
src/libnrtype/FontFactory.cpp
src/libnrtype/FontFactory.h
src/libnrtype/FontInstance.cpp
src/libnrtype/Layout-TNG-OutIter.cpp
src/libnrtype/font-instance.h
src/line-snapper.cpp
src/line-snapper.h
src/live_effects/lpe-perspective_path.cpp
src/nodepath.cpp
src/object-snapper.cpp
src/object-snapper.h
src/path-chemistry.cpp
src/persp3d-reference.h
src/persp3d.cpp
src/persp3d.h
src/selection-chemistry.cpp
src/selection.cpp
src/selection.h
src/snap.cpp
src/snap.h
src/snapped-curve.cpp
src/snapped-curve.h
src/snapped-line.cpp
src/snapped-line.h
src/snapped-point.cpp
src/snapped-point.h
src/snapper.h
src/sp-conn-end.cpp
src/sp-flowtext.cpp
src/sp-item-group.cpp
src/sp-item.cpp
src/spray-context.cpp
src/spray-context.h
src/svg/svg-color.cpp
src/transf_mat_3x4.cpp
src/ui/dialog/align-and-distribute.cpp
src/ui/dialog/document-properties.cpp
src/vanishing-point.cpp
src/widgets/sp-color-notebook.cpp
src/widgets/toolbox.cpp

diff --git a/AUTHORS b/AUTHORS
index d498ff98a7977d9c289f27cf6b43623a9e88bc46..7abce1c56d157a695ae9a9db9a844545d846f9f4 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,6 +3,7 @@ Josh Andler
 Pierre Barbry-Blot
 Jean-François Barraud
 Bill Baxter
+John Beard
 John Bintz
 Arpad Biro
 Nicholas Bishop
index a619ccfa1d4357e64d1d003d19e8934a0812a369..14af5cfa7207207182d33b3a3e63fded688d9be2 100644 (file)
@@ -379,6 +379,7 @@ share/extensions/web-transmit-att.py
 [type: gettext/xml] share/extensions/radiusrand.inx
 [type: gettext/xml] share/extensions/render_alphabetsoup.inx
 [type: gettext/xml] share/extensions/render_barcode.inx
+[type: gettext/xml] share/extensions/render_barcode_datamatrix.inx
 [type: gettext/xml] share/extensions/restack.inx
 [type: gettext/xml] share/extensions/rtree.inx
 [type: gettext/xml] share/extensions/rubberstretch.inx
@@ -405,6 +406,7 @@ share/extensions/web-transmit-att.py
 [type: gettext/xml] share/extensions/web-set-att.inx
 [type: gettext/xml] share/extensions/web-transmit-att.inx
 [type: gettext/xml] share/extensions/whirl.inx
+[type: gettext/xml] share/extensions/wireframe_sphere.inx
 [type: gettext/xml] share/extensions/wmf_input.inx
 [type: gettext/xml] share/extensions/wmf_output.inx
 [type: gettext/xml] share/extensions/xaml2svg.inx
index 835bc824e7ad2d0a894a2b506eb91d15eb827f5f..4c37b24eb8842aa071474a42d88e41d932c4962c 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -17,8 +17,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: inkscape\n"
 "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2009-12-08 06:25+0100\n"
-"PO-Revision-Date: 2009-12-09 17:46+0100\n"
+"POT-Creation-Date: 2009-12-27 08:18+0100\n"
+"PO-Revision-Date: 2009-12-27 20:16+0100\n"
 "Last-Translator: Nicolas Dufour <nicoduf@yahoo.fr>\n"
 "Language-Team:  <fr@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -401,7 +401,7 @@ msgstr "Détecte les bords de couleur verticaux dans les objets"
 #. Pencil
 #: ../share/filters/filters.svg.h:29
 #: ../src/ui/dialog/inkscape-preferences.cpp:492
-#: ../src/verbs.cpp:2528
+#: ../src/verbs.cpp:2534
 msgid "Pencil"
 msgstr "Crayon"
 
@@ -1629,7 +1629,7 @@ msgstr "Bosselage spéculaire extrêmement flexible avec transparence"
 
 #: ../share/filters/filters.svg.h:162
 #: ../src/ui/dialog/align-and-distribute.cpp:920
-#: ../src/widgets/desktop-widget.cpp:1576
+#: ../src/widgets/desktop-widget.cpp:1584
 msgid "Drawing"
 msgstr "Dessin"
 
@@ -2276,25 +2276,25 @@ msgstr "<b>Ellipse</b> : %s &#215; %s; <b>Ctrl</b> pour dessiner des cercles ou
 msgid "Create ellipse"
 msgstr "Créer une ellipse"
 
-#: ../src/box3d-context.cpp:429
-#: ../src/box3d-context.cpp:436
-#: ../src/box3d-context.cpp:443
-#: ../src/box3d-context.cpp:450
-#: ../src/box3d-context.cpp:457
-#: ../src/box3d-context.cpp:464
+#: ../src/box3d-context.cpp:435
+#: ../src/box3d-context.cpp:442
+#: ../src/box3d-context.cpp:449
+#: ../src/box3d-context.cpp:456
+#: ../src/box3d-context.cpp:463
+#: ../src/box3d-context.cpp:470
 msgid "Change perspective (angle of PLs)"
 msgstr "Changer la perspective (angle des LP)"
 
 #. status text
-#: ../src/box3d-context.cpp:622
+#: ../src/box3d-context.cpp:638
 msgid "<b>3D Box</b>; with <b>Shift</b> to extrude along the Z axis"
 msgstr "<b>Boîte 3D</b>. Utiliser <b>Maj</b> pour extruder suivant Z"
 
-#: ../src/box3d-context.cpp:650
+#: ../src/box3d-context.cpp:666
 msgid "Create 3D box"
 msgstr "Créer une boîte 3D"
 
-#: ../src/box3d.cpp:315
+#: ../src/box3d.cpp:327
 msgid "<b>3D Box</b>"
 msgstr "<b>Boîte 3D</b>"
 
@@ -2331,12 +2331,12 @@ msgid "Select <b>at least one non-connector object</b>."
 msgstr "Sélectionner <b>au moins un objet non connecteur</b>."
 
 #: ../src/connector-context.cpp:1930
-#: ../src/widgets/toolbox.cpp:7377
+#: ../src/widgets/toolbox.cpp:7457
 msgid "Make connectors avoid selected objects"
 msgstr "Faire que les connecteurs évitent les objets sélectionnés"
 
 #: ../src/connector-context.cpp:1931
-#: ../src/widgets/toolbox.cpp:7387
+#: ../src/widgets/toolbox.cpp:7467
 msgid "Make connectors ignore selected objects"
 msgstr "Faire que les connecteurs ignorent les objets sélectionnés"
 
@@ -2350,11 +2350,11 @@ msgstr "<b>Le calque courant est caché</b>. Le rendre visible pour pouvoir y de
 msgid "<b>Current layer is locked</b>. Unlock it to be able to draw on it."
 msgstr "<b>Le calque courant est verrouillé</b>. Le déverrouiller pour pouvoir y dessiner."
 
-#: ../src/desktop.cpp:830
+#: ../src/desktop.cpp:833
 msgid "No previous zoom."
 msgstr "Plus de zoom précédent."
 
-#: ../src/desktop.cpp:855
+#: ../src/desktop.cpp:858
 msgid "No next zoom."
 msgstr "Plus de zoom suivant."
 
@@ -2411,7 +2411,7 @@ msgid "Delete tiled clones"
 msgstr "Supprimer les clones de pavage"
 
 #: ../src/dialogs/clonetiler.cpp:1097
-#: ../src/selection-chemistry.cpp:1883
+#: ../src/selection-chemistry.cpp:1906
 msgid "Select an <b>object</b> to clone."
 msgstr "Sélectionner un <b>objet</b> à cloner."
 
@@ -2889,7 +2889,7 @@ msgstr "Capturer la couleur et l'opacité visibles"
 #: ../src/dialogs/clonetiler.cpp:2764
 #: ../src/extension/internal/bitmap/opacity.cpp:37
 #: ../src/extension/internal/bitmap/opacity.cpp:39
-#: ../src/widgets/toolbox.cpp:4353
+#: ../src/widgets/toolbox.cpp:4354
 #: ../share/extensions/interp_att_g.inx.h:12
 msgid "Opacity"
 msgstr "Opacité"
@@ -3090,17 +3090,17 @@ msgid "Reset all shifts, scales, rotates, opacity and color changes in the dialo
 msgstr "Remise à zéro de tous les décalages, redimensionnements, rotation et opacités dans la boîte de dialogue"
 
 #: ../src/dialogs/export.cpp:146
-#: ../src/verbs.cpp:2637
+#: ../src/verbs.cpp:2645
 msgid "_Page"
 msgstr "_Page"
 
 #: ../src/dialogs/export.cpp:146
-#: ../src/verbs.cpp:2641
+#: ../src/verbs.cpp:2649
 msgid "_Drawing"
 msgstr "_Dessin"
 
 #: ../src/dialogs/export.cpp:146
-#: ../src/verbs.cpp:2643
+#: ../src/verbs.cpp:2651
 msgid "_Selection"
 msgstr "_Sélection"
 
@@ -3521,8 +3521,8 @@ msgstr "L'attribut id= (seuls les chiffres, lettres, et les caractères .-_: son
 
 #. Button for setting the object's id, label, title and description.
 #: ../src/dialogs/item-properties.cpp:143
-#: ../src/verbs.cpp:2496
 #: ../src/verbs.cpp:2502
+#: ../src/verbs.cpp:2508
 msgid "_Set"
 msgstr "_Définir"
 
@@ -3683,10 +3683,10 @@ msgstr "Y :"
 
 #: ../src/dialogs/object-attributes.cpp:53
 #: ../src/dialogs/object-attributes.cpp:61
-#: ../src/widgets/toolbox.cpp:4151
-#: ../src/widgets/toolbox.cpp:4475
-#: ../src/widgets/toolbox.cpp:4934
-#: ../src/widgets/toolbox.cpp:5953
+#: ../src/widgets/toolbox.cpp:4152
+#: ../src/widgets/toolbox.cpp:4478
+#: ../src/widgets/toolbox.cpp:4937
+#: ../src/widgets/toolbox.cpp:5956
 msgid "Width:"
 msgstr "Épaisseur :"
 
@@ -3802,12 +3802,12 @@ msgid "Justify lines"
 msgstr "Justifier les lignes"
 
 #: ../src/dialogs/text-edit.cpp:300
-#: ../src/widgets/toolbox.cpp:7031
+#: ../src/widgets/toolbox.cpp:7111
 msgid "Horizontal text"
 msgstr "Texte horizontal"
 
 #: ../src/dialogs/text-edit.cpp:314
-#: ../src/widgets/toolbox.cpp:7043
+#: ../src/widgets/toolbox.cpp:7123
 msgid "Vertical text"
 msgstr "Texte vertical"
 
@@ -3819,9 +3819,10 @@ msgstr "Espacement entre les lignes :"
 #: ../src/dialogs/text-edit.cpp:375
 #: ../src/selection-describer.cpp:69
 #: ../src/ui/dialog/inkscape-preferences.cpp:528
-#: ../src/verbs.cpp:2534
+#: ../src/verbs.cpp:2540
 #: ../share/extensions/lorem_ipsum.inx.h:5
 #: ../share/extensions/render_alphabetsoup.inx.h:5
+#: ../share/extensions/render_barcode_datamatrix.inx.h:6
 #: ../share/extensions/text_braille.inx.h:2
 #: ../share/extensions/text_flipcase.inx.h:1
 #: ../share/extensions/text_lowercase.inx.h:1
@@ -3838,7 +3839,7 @@ msgid "Set as default"
 msgstr "Enregistrer comme valeur par défaut"
 
 #: ../src/dialogs/text-edit.cpp:665
-#: ../src/text-context.cpp:1493
+#: ../src/text-context.cpp:1500
 msgid "Set text style"
 msgstr "Appliquer un style à un texte"
 
@@ -3997,7 +3998,7 @@ msgstr "Longueur de base de l'axe z"
 
 #: ../src/display/canvas-axonomgrid.cpp:404
 #: ../src/ui/dialog/inkscape-preferences.cpp:1021
-#: ../src/widgets/toolbox.cpp:3449
+#: ../src/widgets/toolbox.cpp:3452
 msgid "Angle X:"
 msgstr "Angle X :"
 
@@ -4008,7 +4009,7 @@ msgstr "Angle de l'axe x"
 
 #: ../src/display/canvas-axonomgrid.cpp:406
 #: ../src/ui/dialog/inkscape-preferences.cpp:1022
-#: ../src/widgets/toolbox.cpp:3528
+#: ../src/widgets/toolbox.cpp:3531
 msgid "Angle Z:"
 msgstr "Angle Z :"
 
@@ -4284,7 +4285,7 @@ msgid "Quadrant point"
 msgstr "Point de quadrant"
 
 #: ../src/display/snap-indicator.cpp:196
-#: ../src/widgets/toolbox.cpp:6961
+#: ../src/widgets/toolbox.cpp:7041
 msgid "Center"
 msgstr "Centre"
 
@@ -4300,17 +4301,17 @@ msgstr "Ligne de base de texte"
 msgid " to "
 msgstr " à "
 
-#: ../src/document.cpp:457
+#: ../src/document.cpp:478
 #, c-format
 msgid "New document %d"
 msgstr "Nouveau document %d"
 
-#: ../src/document.cpp:489
+#: ../src/document.cpp:510
 #, c-format
 msgid "Memory document %d"
 msgstr "Document d'information %d"
 
-#: ../src/document.cpp:644
+#: ../src/document.cpp:665
 #, c-format
 msgid "Unnamed document %d"
 msgstr "Document sans nom %d"
@@ -4339,33 +4340,33 @@ msgstr "Créer un point isolé"
 
 #. alpha of color under cursor, to show in the statusbar
 #. locale-sensitive printf is OK, since this goes to the UI, not into SVG
-#: ../src/dropper-context.cpp:310
+#: ../src/dropper-context.cpp:312
 #, c-format
 msgid " alpha %.3g"
 msgstr " alpha %.3g"
 
 #. where the color is picked, to show in the statusbar
-#: ../src/dropper-context.cpp:312
+#: ../src/dropper-context.cpp:314
 #, c-format
 msgid ", averaged with radius %d"
 msgstr ", valeur moyenne dans un rayon de %d"
 
-#: ../src/dropper-context.cpp:312
+#: ../src/dropper-context.cpp:314
 #, c-format
 msgid " under cursor"
 msgstr " sous le curseur"
 
 #. message, to show in the statusbar
-#: ../src/dropper-context.cpp:314
+#: ../src/dropper-context.cpp:316
 msgid "<b>Release mouse</b> to set color."
 msgstr "<b>Relâcher la souris</b> pour appliquer la couleur."
 
-#: ../src/dropper-context.cpp:314
+#: ../src/dropper-context.cpp:316
 #: ../src/tools-switch.cpp:216
 msgid "<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard"
 msgstr "<b>Cliquer</b> pour appliquer au remplissage, <b>Maj+clic</b> pour appliquer au contour; <b>cliquer-déplacer</b> pour capturer la couleur moyenne sur une zone; à combiner avec <b>Alt</b> pour capturer la couleur inverse; <b>Ctrl+C</b> pour copier la couleur sous le curseur de la souris vers le presse-papiers "
 
-#: ../src/dropper-context.cpp:352
+#: ../src/dropper-context.cpp:354
 msgid "Set picked color"
 msgstr "Appliquer la couleur capturée"
 
@@ -4412,13 +4413,13 @@ msgstr "[Inchangé]"
 #. Edit
 #: ../src/event-log.cpp:264
 #: ../src/event-log.cpp:267
-#: ../src/verbs.cpp:2286
+#: ../src/verbs.cpp:2292
 msgid "_Undo"
 msgstr "Ann_uler"
 
 #: ../src/event-log.cpp:274
 #: ../src/event-log.cpp:278
-#: ../src/verbs.cpp:2288
+#: ../src/verbs.cpp:2294
 msgid "_Redo"
 msgstr "Réta_blir"
 
@@ -4561,8 +4562,8 @@ msgstr "Seuil adaptatif"
 #: ../src/live_effects/lpe-bendpath.cpp:56
 #: ../src/live_effects/lpe-patternalongpath.cpp:64
 #: ../src/widgets/toolbox.cpp:3122
-#: ../src/widgets/toolbox.cpp:4151
-#: ../src/widgets/toolbox.cpp:4475
+#: ../src/widgets/toolbox.cpp:4152
+#: ../src/widgets/toolbox.cpp:4478
 #: ../share/extensions/foldablebox.inx.h:9
 #: ../share/extensions/interp_att_g.inx.h:26
 msgid "Width"
@@ -4899,7 +4900,7 @@ msgstr "Ajuster TSV"
 #: ../src/widgets/sp-color-icc-selector.cpp:237
 #: ../src/widgets/sp-color-scales.cpp:438
 #: ../src/widgets/sp-color-scales.cpp:439
-#: ../src/widgets/toolbox.cpp:4308
+#: ../src/widgets/toolbox.cpp:4309
 #: ../share/extensions/color_randomize.inx.h:2
 msgid "Hue"
 msgstr "Teinte"
@@ -4911,7 +4912,7 @@ msgstr "Teinte"
 #: ../src/widgets/sp-color-icc-selector.cpp:237
 #: ../src/widgets/sp-color-scales.cpp:441
 #: ../src/widgets/sp-color-scales.cpp:442
-#: ../src/widgets/toolbox.cpp:4323
+#: ../src/widgets/toolbox.cpp:4324
 #: ../share/extensions/color_randomize.inx.h:5
 msgid "Saturation"
 msgstr "Saturation"
@@ -5119,7 +5120,7 @@ msgstr "PostScript niveau 2"
 #: ../src/extension/internal/cairo-ps-out.cpp:282
 #: ../src/extension/internal/cairo-ps-out.cpp:319
 #: ../src/extension/internal/cairo-renderer-pdf-out.cpp:219
-#: ../src/extension/internal/emf-win32-inout.cpp:2430
+#: ../src/extension/internal/emf-win32-inout.cpp:2431
 msgid "Convert texts to paths"
 msgstr "Convertir les textes en chemins"
 
@@ -5184,39 +5185,39 @@ msgstr "Restreindre à la version de PDF"
 msgid "PDF 1.4"
 msgstr "PDF 1.4"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2400
+#: ../src/extension/internal/emf-win32-inout.cpp:2401
 msgid "EMF Input"
 msgstr "Entrée EMF"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2405
+#: ../src/extension/internal/emf-win32-inout.cpp:2406
 msgid "Enhanced Metafiles (*.emf)"
 msgstr "Métafichier amélioré (*.emf)"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2406
+#: ../src/extension/internal/emf-win32-inout.cpp:2407
 msgid "Enhanced Metafiles"
 msgstr "Métafichier amélioré"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2414
+#: ../src/extension/internal/emf-win32-inout.cpp:2415
 msgid "WMF Input"
 msgstr "Entrée WMF"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2419
+#: ../src/extension/internal/emf-win32-inout.cpp:2420
 msgid "Windows Metafiles (*.wmf)"
 msgstr "Métafichier Windows (*.wmf)"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2420
+#: ../src/extension/internal/emf-win32-inout.cpp:2421
 msgid "Windows Metafiles"
 msgstr "Métafichier Windows"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2428
+#: ../src/extension/internal/emf-win32-inout.cpp:2429
 msgid "EMF Output"
 msgstr "Sortie EMF"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2434
+#: ../src/extension/internal/emf-win32-inout.cpp:2435
 msgid "Enhanced Metafile (*.emf)"
 msgstr "Métafichier amélioré (*.emf)"
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2435
+#: ../src/extension/internal/emf-win32-inout.cpp:2436
 msgid "Enhanced Metafile"
 msgstr "Métafichier amélioré"
 
@@ -5350,10 +5351,12 @@ msgstr "Décalage vertical"
 #: ../share/extensions/printing-marks.inx.h:14
 #: ../share/extensions/render_alphabetsoup.inx.h:3
 #: ../share/extensions/render_barcode.inx.h:5
+#: ../share/extensions/render_barcode_datamatrix.inx.h:3
 #: ../share/extensions/rtree.inx.h:4
 #: ../share/extensions/spirograph.inx.h:6
 #: ../share/extensions/svgcalendar.inx.h:22
 #: ../share/extensions/triangle.inx.h:10
+#: ../share/extensions/wireframe_sphere.inx.h:5
 msgid "Render"
 msgstr "Rendu"
 
@@ -5495,27 +5498,27 @@ msgstr "fin"
 msgid "very fine"
 msgstr "très fin"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:753
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:754
 msgid "PDF Input"
 msgstr "Entrée PDF"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:758
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:759
 msgid "Adobe PDF (*.pdf)"
 msgstr "Adobe PDF (*.pdf)"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:759
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:760
 msgid "Adobe Portable Document Format"
 msgstr "Adobe Portable Document Format"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:766
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:767
 msgid "AI Input"
 msgstr "Entrée AI"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:771
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:772
 msgid "Adobe Illustrator 9.0 and above (*.ai)"
 msgstr "Adobe Illustrator 9.0 et supérieur (*.ai)"
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:772
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:773
 msgid "Open files saved in Adobe Illustrator 9.0 and newer versions"
 msgstr "Ouvrir des fichiers créés avec Adobe Illustrator version 9.0 et les versions plus récentes"
 
@@ -5748,7 +5751,7 @@ msgid "Select file to export to"
 msgstr "Sélectionner un fichier vers lequel exporter"
 
 #: ../src/file.cpp:1473
-#: ../src/verbs.cpp:2275
+#: ../src/verbs.cpp:2281
 msgid "Import From Open Clip Art Library"
 msgstr "Importer depuis la bibliothèque Open Clip Art"
 
@@ -5870,7 +5873,7 @@ msgstr "Luminance vers opacité"
 
 #. File
 #: ../src/filter-enums.cpp:72
-#: ../src/verbs.cpp:2252
+#: ../src/verbs.cpp:2258
 msgid "Default"
 msgstr "Défaut"
 
@@ -5919,7 +5922,7 @@ msgid "Gamma"
 msgstr "Gamma"
 
 #: ../src/filter-enums.cpp:94
-#: ../src/selection-chemistry.cpp:316
+#: ../src/selection-chemistry.cpp:317
 #: ../src/widgets/gradient-selector.cpp:139
 msgid "Duplicate"
 msgstr "Dupliquer"
@@ -5938,9 +5941,9 @@ msgstr "Retour à la ligne"
 #: ../src/ui/dialog/inkscape-preferences.cpp:565
 #: ../src/ui/dialog/inkscape-preferences.cpp:1167
 #: ../src/ui/dialog/inkscape-preferences.cpp:1232
-#: ../src/verbs.cpp:2249
+#: ../src/verbs.cpp:2255
 #: ../src/widgets/stroke-style.cpp:765
-#: ../src/widgets/toolbox.cpp:3914
+#: ../src/widgets/toolbox.cpp:3917
 #: ../share/extensions/grid_polar.inx.h:16
 #: ../share/extensions/guides_creator.inx.h:15
 #: ../share/extensions/scour.inx.h:7
@@ -6008,7 +6011,7 @@ msgstr "Couleurs visibles"
 #: ../src/widgets/sp-color-icc-selector.cpp:237
 #: ../src/widgets/sp-color-scales.cpp:444
 #: ../src/widgets/sp-color-scales.cpp:445
-#: ../src/widgets/toolbox.cpp:4338
+#: ../src/widgets/toolbox.cpp:4339
 #: ../share/extensions/color_randomize.inx.h:3
 msgid "Lightness"
 msgstr "Luminosité"
@@ -6251,7 +6254,7 @@ msgid "Delete gradient stop(s)"
 msgstr "Supprimer un stop de dégradé"
 
 #: ../src/helper/units.cpp:37
-#: ../src/live_effects/lpe-ruler.cpp:43
+#: ../src/live_effects/lpe-ruler.cpp:44
 #: ../share/extensions/foldablebox.inx.h:8
 #: ../share/extensions/interp_att_g.inx.h:24
 #: ../share/extensions/printing-marks.inx.h:19
@@ -6263,8 +6266,8 @@ msgstr "Unité"
 #: ../src/widgets/select-toolbar.cpp:504
 #: ../src/widgets/toolbox.cpp:1530
 #: ../src/widgets/toolbox.cpp:3183
-#: ../src/widgets/toolbox.cpp:5879
-#: ../src/widgets/toolbox.cpp:7635
+#: ../src/widgets/toolbox.cpp:5882
+#: ../src/widgets/toolbox.cpp:7715
 msgid "Units"
 msgstr "Unités"
 
@@ -6463,98 +6466,98 @@ msgstr "Les enregistrements automatiques des documents suivants ont échoué :\
 
 #. sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
 #. checkitem_toggled, checkitem_update, 0);
-#: ../src/interface.cpp:868
+#: ../src/interface.cpp:870
 msgid "Commands Bar"
 msgstr "Barre des commandes"
 
-#: ../src/interface.cpp:868
+#: ../src/interface.cpp:870
 msgid "Show or hide the Commands bar (under the menu)"
 msgstr "Afficher ou non la barre des commandes (sous le menu)"
 
-#: ../src/interface.cpp:870
+#: ../src/interface.cpp:872
 msgid "Snap Controls Bar"
 msgstr "Barre des contrôles du magnétisme"
 
-#: ../src/interface.cpp:870
+#: ../src/interface.cpp:872
 msgid "Show or hide the snapping controls"
 msgstr "Afficher ou non la barre des contrôles du magnétisme"
 
-#: ../src/interface.cpp:872
+#: ../src/interface.cpp:874
 msgid "Tool Controls Bar"
 msgstr "Barre des contrôles des outils"
 
-#: ../src/interface.cpp:872
+#: ../src/interface.cpp:874
 msgid "Show or hide the Tool Controls bar"
 msgstr "Afficher ou non la barre des contrôles des outils"
 
-#: ../src/interface.cpp:874
+#: ../src/interface.cpp:876
 msgid "_Toolbox"
 msgstr "Boîte à _outils"
 
-#: ../src/interface.cpp:874
+#: ../src/interface.cpp:876
 msgid "Show or hide the main toolbox (on the left)"
 msgstr "Afficher ou non la boîte à outils principale (à gauche)"
 
-#: ../src/interface.cpp:880
+#: ../src/interface.cpp:882
 msgid "_Palette"
 msgstr "_Palette"
 
-#: ../src/interface.cpp:880
+#: ../src/interface.cpp:882
 msgid "Show or hide the color palette"
 msgstr "Afficher ou non la palette de couleurs"
 
-#: ../src/interface.cpp:882
+#: ../src/interface.cpp:884
 msgid "_Statusbar"
 msgstr "Barre d'_état"
 
-#: ../src/interface.cpp:882
+#: ../src/interface.cpp:884
 msgid "Show or hide the statusbar (at the bottom of the window)"
 msgstr "Afficher ou non la barre d'état (en bas de la fenêtre)"
 
-#: ../src/interface.cpp:956
+#: ../src/interface.cpp:958
 #, c-format
 msgid "Verb \"%s\" Unknown"
 msgstr "Verbe « %s » inconnu"
 
-#: ../src/interface.cpp:998
+#: ../src/interface.cpp:1000
 msgid "Open _Recent"
 msgstr "Documents _récents"
 
 #. TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number.
-#: ../src/interface.cpp:1099
+#: ../src/interface.cpp:1101
 #, c-format
 msgid "Enter group #%s"
 msgstr "Entrer dans le groupe #%s"
 
-#: ../src/interface.cpp:1110
+#: ../src/interface.cpp:1112
 msgid "Go to parent"
 msgstr "Sélectionner le parent"
 
-#: ../src/interface.cpp:1201
-#: ../src/interface.cpp:1287
-#: ../src/interface.cpp:1390
+#: ../src/interface.cpp:1203
+#: ../src/interface.cpp:1289
+#: ../src/interface.cpp:1392
 #: ../src/ui/widget/selected-style.cpp:468
 msgid "Drop color"
 msgstr "Déposer la couleur"
 
-#: ../src/interface.cpp:1240
-#: ../src/interface.cpp:1350
+#: ../src/interface.cpp:1242
+#: ../src/interface.cpp:1352
 msgid "Drop color on gradient"
 msgstr "Déposer la couleur dans le dégradé"
 
-#: ../src/interface.cpp:1403
+#: ../src/interface.cpp:1405
 msgid "Could not parse SVG data"
 msgstr "Impossible de parcourir les données SVG"
 
-#: ../src/interface.cpp:1442
+#: ../src/interface.cpp:1444
 msgid "Drop SVG"
 msgstr "Déposer un SVG"
 
-#: ../src/interface.cpp:1498
+#: ../src/interface.cpp:1500
 msgid "Drop bitmap image"
 msgstr "Déposer une image bitmap"
 
-#: ../src/interface.cpp:1590
+#: ../src/interface.cpp:1592
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do you want to replace it?</span>\n"
@@ -6566,7 +6569,7 @@ msgstr ""
 "\n"
 "Le fichier existe déjà dans « %s ». Le remplacer écrase son contenu."
 
-#: ../src/interface.cpp:1597
+#: ../src/interface.cpp:1599
 #: ../share/extensions/web-set-att.inx.h:5
 #: ../share/extensions/web-transmit-att.inx.h:5
 msgid "Replace"
@@ -6862,7 +6865,7 @@ msgstr "Le nouveau contrôleur d'attache %p est automatique. Seuls les ojbets d'
 #: ../src/ui/dialog/align-and-distribute.cpp:919
 #: ../src/ui/dialog/document-properties.cpp:118
 #: ../src/ui/dialog/filedialogimpl-gtkmm.cpp:1410
-#: ../src/widgets/desktop-widget.cpp:1572
+#: ../src/widgets/desktop-widget.cpp:1580
 msgid "Page"
 msgstr "Page"
 
@@ -7013,7 +7016,7 @@ msgstr "Quelque chose de bizarre est arrivé en essayant d'obtenir le placement
 msgid "Dockitem which 'owns' this tablabel"
 msgstr "Élément d'attache qui « possède » ce tablabel"
 
-#: ../src/libnrtype/FontFactory.cpp:806
+#: ../src/libnrtype/FontFactory.cpp:821
 msgid "Ignoring font without family that will crash Pango"
 msgstr "Ignorer les polices sans famille qui font planter Pango"
 
@@ -7696,20 +7699,20 @@ msgid "Both"
 msgstr "Les deux"
 
 #: ../src/live_effects/lpe-ruler.cpp:35
-#: ../src/widgets/toolbox.cpp:5387
+#: ../src/widgets/toolbox.cpp:5390
 msgid "Start"
 msgstr "Début"
 
 #: ../src/live_effects/lpe-ruler.cpp:36
-#: ../src/widgets/toolbox.cpp:5400
+#: ../src/widgets/toolbox.cpp:5403
 msgid "End"
 msgstr "Fin"
 
-#: ../src/live_effects/lpe-ruler.cpp:44
+#: ../src/live_effects/lpe-ruler.cpp:43
 msgid "Mark distance"
 msgstr "Distance entre graduations"
 
-#: ../src/live_effects/lpe-ruler.cpp:44
+#: ../src/live_effects/lpe-ruler.cpp:43
 msgid "Distance between successive ruler marks"
 msgstr "Distance entre deux graduations successives"
 
@@ -7848,7 +7851,7 @@ msgid "How many construction lines (tangents) to draw"
 msgstr "Nombre de lignes de construction (tangentes) à dessiner"
 
 #: ../src/live_effects/lpe-sketch.cpp:55
-#: ../src/selection-chemistry.cpp:1516
+#: ../src/selection-chemistry.cpp:1539
 #: ../src/seltrans.cpp:531
 #: ../src/ui/dialog/transformation.cpp:738
 #: ../share/extensions/interp_att_g.inx.h:16
@@ -8218,8 +8221,8 @@ msgstr "OBJECT-ID"
 msgid "Start Inkscape in interactive shell mode."
 msgstr "Démarrer Inkscape en mode de commande interactif."
 
-#: ../src/main.cpp:762
-#: ../src/main.cpp:1088
+#: ../src/main.cpp:766
+#: ../src/main.cpp:1092
 msgid ""
 "[OPTIONS...] [FILE...]\n"
 "\n"
@@ -8241,87 +8244,85 @@ msgstr "_Fichier"
 msgid "_New"
 msgstr "_Nouveau"
 
-#. TODO look at some dynamic option for changing the menu tree:
-#. "       <verb verb-id=\"DialogInput2\" />\n"
-#: ../src/menus-skeleton.h:49
-#: ../src/verbs.cpp:2498
+#: ../src/menus-skeleton.h:48
 #: ../src/verbs.cpp:2504
+#: ../src/verbs.cpp:2510
 msgid "_Edit"
 msgstr "_Édition"
 
-#: ../src/menus-skeleton.h:59
-#: ../src/verbs.cpp:2298
+#: ../src/menus-skeleton.h:58
+#: ../src/verbs.cpp:2304
 msgid "Paste Si_ze"
 msgstr "Coller les d_imensions"
 
-#: ../src/menus-skeleton.h:71
+#: ../src/menus-skeleton.h:70
 msgid "Clo_ne"
 msgstr "Clo_ner"
 
-#: ../src/menus-skeleton.h:91
+#: ../src/menus-skeleton.h:90
 msgid "_View"
 msgstr "_Affichage"
 
-#: ../src/menus-skeleton.h:92
+#: ../src/menus-skeleton.h:91
 msgid "_Zoom"
 msgstr "_Zoom"
 
-#: ../src/menus-skeleton.h:108
+#: ../src/menus-skeleton.h:107
 msgid "_Display mode"
 msgstr "Mode d'_affichage"
 
-#: ../src/menus-skeleton.h:120
+#: ../src/menus-skeleton.h:121
 msgid "Show/Hide"
 msgstr "Afficher/cacher"
 
 #. "       <verb verb-id=\"DialogScript\" />\n"
 #. Not quite ready to be in the menus.
 #. "       <verb verb-id=\"FocusToggle\" />\n"
-#: ../src/menus-skeleton.h:139
+#: ../src/menus-skeleton.h:140
 msgid "_Layer"
 msgstr "Ca_lque"
 
-#: ../src/menus-skeleton.h:159
+#: ../src/menus-skeleton.h:160
 msgid "_Object"
 msgstr "_Objet"
 
-#: ../src/menus-skeleton.h:166
+#: ../src/menus-skeleton.h:167
 msgid "Cli_p"
 msgstr "D_écoupe"
 
-#: ../src/menus-skeleton.h:170
+#: ../src/menus-skeleton.h:171
 msgid "Mas_k"
 msgstr "Mas_que"
 
-#: ../src/menus-skeleton.h:174
+#: ../src/menus-skeleton.h:175
 msgid "Patter_n"
 msgstr "Moti_f"
 
-#: ../src/menus-skeleton.h:198
+#: ../src/menus-skeleton.h:199
 msgid "_Path"
 msgstr "_Chemin"
 
-#: ../src/menus-skeleton.h:225
+#: ../src/menus-skeleton.h:226
 msgid "_Text"
 msgstr "_Texte"
 
-#: ../src/menus-skeleton.h:244
+#: ../src/menus-skeleton.h:245
 msgid "Filter_s"
 msgstr "Filtre_s"
 
-#: ../src/menus-skeleton.h:250
+#: ../src/menus-skeleton.h:251
 msgid "Exte_nsions"
 msgstr "Exte_nsions"
 
-#: ../src/menus-skeleton.h:257
+#: ../src/menus-skeleton.h:258
 msgid "Whiteboa_rd"
 msgstr "Tableau _blanc"
 
-#: ../src/menus-skeleton.h:261
+#: ../src/menus-skeleton.h:262
 msgid "_Help"
 msgstr "Aid_e"
 
-#: ../src/menus-skeleton.h:265
+#: ../src/menus-skeleton.h:266
 msgid "Tutorials"
 msgstr "Didacticiels"
 
@@ -8774,11 +8775,11 @@ msgstr "<b>Poignée de la courbe</b> : angle %3.2f&#176;, longueur %s ; avec <
 msgid "Drawing finished"
 msgstr "Tracé terminé"
 
-#: ../src/persp3d.cpp:335
+#: ../src/persp3d.cpp:345
 msgid "Toggle vanishing point"
 msgstr "Alterner les points de fuite"
 
-#: ../src/persp3d.cpp:346
+#: ../src/persp3d.cpp:356
 msgid "Toggle multiple vanishing points"
 msgstr "Alterner entre des points de fuite multiples"
 
@@ -9092,361 +9093,361 @@ msgstr "<b>Alt</b> : cliquer pour sélectionner sous, cliquer-déplacer pour d
 msgid "Selected object is not a group. Cannot enter."
 msgstr "L'objet sélectionné n'est pas un groupe. Impossible d'y entrer."
 
-#: ../src/selection-chemistry.cpp:195
+#: ../src/selection-chemistry.cpp:196
 msgid "Delete text"
 msgstr "Supprimer le texte"
 
-#: ../src/selection-chemistry.cpp:203
+#: ../src/selection-chemistry.cpp:204
 msgid "<b>Nothing</b> was deleted."
 msgstr "<b>Rien</b> n'a été supprimé."
 
-#: ../src/selection-chemistry.cpp:221
-#: ../src/text-context.cpp:995
+#: ../src/selection-chemistry.cpp:222
+#: ../src/text-context.cpp:1002
 #: ../src/ui/dialog/swatches.cpp:471
 #: ../src/widgets/toolbox.cpp:1330
-#: ../src/widgets/toolbox.cpp:5971
+#: ../src/widgets/toolbox.cpp:5974
 msgid "Delete"
 msgstr "Supprimer"
 
-#: ../src/selection-chemistry.cpp:249
+#: ../src/selection-chemistry.cpp:250
 msgid "Select <b>object(s)</b> to duplicate."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à dupliquer."
 
-#: ../src/selection-chemistry.cpp:341
+#: ../src/selection-chemistry.cpp:342
 msgid "Delete all"
 msgstr "Supprimer tout"
 
-#: ../src/selection-chemistry.cpp:464
+#: ../src/selection-chemistry.cpp:465
 msgid "Select <b>some objects</b> to group."
 msgstr "Sélectionner <b>des objets</b> à grouper."
 
-#: ../src/selection-chemistry.cpp:537
+#: ../src/selection-chemistry.cpp:538
 #: ../src/selection-describer.cpp:53
 msgid "Group"
 msgstr "Groupe"
 
-#: ../src/selection-chemistry.cpp:551
+#: ../src/selection-chemistry.cpp:552
 msgid "Select a <b>group</b> to ungroup."
 msgstr "Sélectionner un <b>groupe</b> à dégrouper."
 
-#: ../src/selection-chemistry.cpp:592
+#: ../src/selection-chemistry.cpp:593
 msgid "<b>No groups</b> to ungroup in the selection."
 msgstr "<b>Aucun groupe</b> à dégrouper dans la sélection."
 
-#: ../src/selection-chemistry.cpp:598
-#: ../src/sp-item-group.cpp:516
+#: ../src/selection-chemistry.cpp:599
+#: ../src/sp-item-group.cpp:496
 msgid "Ungroup"
 msgstr "Dégrouper"
 
-#: ../src/selection-chemistry.cpp:688
+#: ../src/selection-chemistry.cpp:689
 msgid "Select <b>object(s)</b> to raise."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à monter."
 
-#: ../src/selection-chemistry.cpp:694
-#: ../src/selection-chemistry.cpp:756
-#: ../src/selection-chemistry.cpp:790
-#: ../src/selection-chemistry.cpp:854
+#: ../src/selection-chemistry.cpp:695
+#: ../src/selection-chemistry.cpp:757
+#: ../src/selection-chemistry.cpp:791
+#: ../src/selection-chemistry.cpp:855
 msgid "You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."
 msgstr "Vous ne pouvez pas monter/descendre des objets de <b>différents groupes</b> ou <b>calques</b>."
 
 #. TRANSLATORS: only translate "string" in "context|string".
 #. For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
 #. "Raise" means "to raise an object" in the undo history
-#: ../src/selection-chemistry.cpp:736
+#: ../src/selection-chemistry.cpp:737
 msgid "undo_action|Raise"
 msgstr "Monter"
 
-#: ../src/selection-chemistry.cpp:748
+#: ../src/selection-chemistry.cpp:749
 msgid "Select <b>object(s)</b> to raise to top."
 msgstr "Sélectionner des <b>objets</b> à monter au premier plan."
 
-#: ../src/selection-chemistry.cpp:771
+#: ../src/selection-chemistry.cpp:772
 msgid "Raise to top"
 msgstr "Monter au premier plan"
 
-#: ../src/selection-chemistry.cpp:784
+#: ../src/selection-chemistry.cpp:785
 msgid "Select <b>object(s)</b> to lower."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à descendre."
 
-#: ../src/selection-chemistry.cpp:834
+#: ../src/selection-chemistry.cpp:835
 msgid "Lower"
 msgstr "Descendre"
 
-#: ../src/selection-chemistry.cpp:846
+#: ../src/selection-chemistry.cpp:847
 msgid "Select <b>object(s)</b> to lower to bottom."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à descendre à l'arrière-plan."
 
-#: ../src/selection-chemistry.cpp:881
+#: ../src/selection-chemistry.cpp:882
 msgid "Lower to bottom"
 msgstr "Descendre à l'arrière-plan"
 
-#: ../src/selection-chemistry.cpp:888
+#: ../src/selection-chemistry.cpp:889
 msgid "Nothing to undo."
 msgstr "Rien à défaire."
 
-#: ../src/selection-chemistry.cpp:895
+#: ../src/selection-chemistry.cpp:896
 msgid "Nothing to redo."
 msgstr "Rien à refaire."
 
-#: ../src/selection-chemistry.cpp:955
+#: ../src/selection-chemistry.cpp:956
 msgid "Paste"
 msgstr "Coller"
 
-#: ../src/selection-chemistry.cpp:962
+#: ../src/selection-chemistry.cpp:963
 msgid "Paste style"
 msgstr "Coller le style"
 
-#: ../src/selection-chemistry.cpp:971
+#: ../src/selection-chemistry.cpp:972
 msgid "Paste live path effect"
 msgstr "Coller l'effet de chemin en direct"
 
-#: ../src/selection-chemistry.cpp:991
+#: ../src/selection-chemistry.cpp:992
 msgid "Select <b>object(s)</b> to remove live path effects from."
 msgstr "Sélectionner un ou des <b>objet(s)</b> sur lesquels supprimer des effets de chemin."
 
-#: ../src/selection-chemistry.cpp:1003
+#: ../src/selection-chemistry.cpp:1004
 msgid "Remove live path effect"
 msgstr "Supprimer l'effet de chemin en direct"
 
-#: ../src/selection-chemistry.cpp:1014
+#: ../src/selection-chemistry.cpp:1015
 msgid "Select <b>object(s)</b> to remove filters from."
 msgstr "Sélectionner les <b>objets</b> pour en retirer les filtres."
 
-#: ../src/selection-chemistry.cpp:1024
+#: ../src/selection-chemistry.cpp:1025
 #: ../src/ui/dialog/filter-effects-dialog.cpp:1336
 msgid "Remove filter"
 msgstr "Supprimer le filtre"
 
-#: ../src/selection-chemistry.cpp:1033
+#: ../src/selection-chemistry.cpp:1034
 msgid "Paste size"
 msgstr "Coller les dimensions"
 
-#: ../src/selection-chemistry.cpp:1041
+#: ../src/selection-chemistry.cpp:1042
 msgid "Paste size separately"
 msgstr "Coller les dimensions séparément"
 
-#: ../src/selection-chemistry.cpp:1050
+#: ../src/selection-chemistry.cpp:1051
 msgid "Select <b>object(s)</b> to move to the layer above."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à déplacer au calque du dessus."
 
-#: ../src/selection-chemistry.cpp:1076
+#: ../src/selection-chemistry.cpp:1077
 msgid "Raise to next layer"
 msgstr "Monter au calque suivant"
 
-#: ../src/selection-chemistry.cpp:1083
+#: ../src/selection-chemistry.cpp:1084
 msgid "No more layers above."
 msgstr "Plus de calque au-dessus."
 
-#: ../src/selection-chemistry.cpp:1095
+#: ../src/selection-chemistry.cpp:1096
 msgid "Select <b>object(s)</b> to move to the layer below."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à déplacer au calque du dessous."
 
-#: ../src/selection-chemistry.cpp:1121
+#: ../src/selection-chemistry.cpp:1122
 msgid "Lower to previous layer"
 msgstr "Descendre au calque précédent."
 
-#: ../src/selection-chemistry.cpp:1128
+#: ../src/selection-chemistry.cpp:1129
 msgid "No more layers below."
 msgstr "Plus de calque en-dessous."
 
-#: ../src/selection-chemistry.cpp:1315
+#: ../src/selection-chemistry.cpp:1338
 msgid "Remove transform"
 msgstr "Retirer les transformations"
 
-#: ../src/selection-chemistry.cpp:1418
+#: ../src/selection-chemistry.cpp:1441
 msgid "Rotate 90&#176; CCW"
 msgstr "Tourner de 90&#176; dans le sens anti-horaire"
 
-#: ../src/selection-chemistry.cpp:1418
+#: ../src/selection-chemistry.cpp:1441
 msgid "Rotate 90&#176; CW"
 msgstr "Tourner de 90&#176; dans le sens horaire"
 
-#: ../src/selection-chemistry.cpp:1439
+#: ../src/selection-chemistry.cpp:1462
 #: ../src/seltrans.cpp:534
 #: ../src/ui/dialog/transformation.cpp:760
 msgid "Rotate"
 msgstr "Tourner"
 
-#: ../src/selection-chemistry.cpp:1486
+#: ../src/selection-chemistry.cpp:1509
 msgid "Rotate by pixels"
 msgstr "Tourner par pixels"
 
-#: ../src/selection-chemistry.cpp:1541
+#: ../src/selection-chemistry.cpp:1564
 msgid "Scale by whole factor"
 msgstr "Redimensionner d'un facteur entier"
 
-#: ../src/selection-chemistry.cpp:1556
+#: ../src/selection-chemistry.cpp:1579
 msgid "Move vertically"
 msgstr "Déplacer verticalement"
 
-#: ../src/selection-chemistry.cpp:1559
+#: ../src/selection-chemistry.cpp:1582
 msgid "Move horizontally"
 msgstr "Déplacer horizontalement"
 
-#: ../src/selection-chemistry.cpp:1562
-#: ../src/selection-chemistry.cpp:1588
+#: ../src/selection-chemistry.cpp:1585
+#: ../src/selection-chemistry.cpp:1611
 #: ../src/seltrans.cpp:528
 #: ../src/ui/dialog/transformation.cpp:681
 msgid "Move"
 msgstr "Déplacer"
 
-#: ../src/selection-chemistry.cpp:1582
+#: ../src/selection-chemistry.cpp:1605
 msgid "Move vertically by pixels"
 msgstr "Déplacer verticalement par pixels"
 
-#: ../src/selection-chemistry.cpp:1585
+#: ../src/selection-chemistry.cpp:1608
 msgid "Move horizontally by pixels"
 msgstr "Déplacer horizontalement par pixels"
 
-#: ../src/selection-chemistry.cpp:1713
+#: ../src/selection-chemistry.cpp:1736
 msgid "The selection has no applied path effect."
 msgstr "Il n'y a pas d'effet de chemin appliqué sur cette sélection."
 
-#: ../src/selection-chemistry.cpp:1760
+#: ../src/selection-chemistry.cpp:1783
 msgid "The selection has no applied clip path."
 msgstr "Aucune découpe n'est appliquée à cette sélection."
 
-#: ../src/selection-chemistry.cpp:1762
+#: ../src/selection-chemistry.cpp:1785
 msgid "The selection has no applied mask."
 msgstr "Aucun masque n'est appliqué à cette sélection."
 
-#: ../src/selection-chemistry.cpp:1919
+#: ../src/selection-chemistry.cpp:1942
 msgid "action|Clone"
 msgstr "Cloner"
 
-#: ../src/selection-chemistry.cpp:1935
+#: ../src/selection-chemistry.cpp:1958
 msgid "Select <b>clones</b> to relink."
 msgstr "Sélectionner les <b>clones</b> à relier."
 
-#: ../src/selection-chemistry.cpp:1942
+#: ../src/selection-chemistry.cpp:1965
 msgid "Copy an <b>object</b> to clipboard to relink clones to."
 msgstr "Copier un <b>objet</b> dans le presse-papier pour y relier les clones."
 
-#: ../src/selection-chemistry.cpp:1966
+#: ../src/selection-chemistry.cpp:1989
 msgid "<b>No clones to relink</b> in the selection."
 msgstr "<b>Aucun clone à relier</b> dans la sélection."
 
-#: ../src/selection-chemistry.cpp:1969
+#: ../src/selection-chemistry.cpp:1992
 msgid "Relink clone"
 msgstr "Relier le clone"
 
-#: ../src/selection-chemistry.cpp:1983
+#: ../src/selection-chemistry.cpp:2006
 msgid "Select <b>clones</b> to unlink."
 msgstr "Sélectionner les <b>clones</b> à délier."
 
-#: ../src/selection-chemistry.cpp:2032
+#: ../src/selection-chemistry.cpp:2055
 msgid "<b>No clones to unlink</b> in the selection."
 msgstr "<b>Aucun clone à délier</b> dans la sélection."
 
-#: ../src/selection-chemistry.cpp:2036
+#: ../src/selection-chemistry.cpp:2059
 msgid "Unlink clone"
 msgstr "Délier le clone"
 
-#: ../src/selection-chemistry.cpp:2049
+#: ../src/selection-chemistry.cpp:2072
 msgid "Select a <b>clone</b> to go to its original. Select a <b>linked offset</b> to go to its source. Select a <b>text on path</b> to go to the path. Select a <b>flowed text</b> to go to its frame."
 msgstr "Sélectionner un <b>clone</b> pour sélectionner son original. Sélectionner un <b>offset lié</b> pour sélectionner sa source. Sélectionner un <b>texte suivant un chemin</b> pour sélectionner son chemin. Sélectionner un <b>texte encadré</b> pour sélectionner son cadre."
 
-#: ../src/selection-chemistry.cpp:2072
+#: ../src/selection-chemistry.cpp:2095
 msgid "<b>Cannot find</b> the object to select (orphaned clone, offset, textpath, flowed text?)"
 msgstr "<b>Impossible de trouver</b> l'objet à sélectionner (clone orphelin, offset, chemin de texte, texte encadré ?)"
 
-#: ../src/selection-chemistry.cpp:2078
+#: ../src/selection-chemistry.cpp:2101
 msgid "The object you're trying to select is <b>not visible</b> (it is in &lt;defs&gt;)"
 msgstr "L'objet que vous essayez de sélectionner n'est <b>pas visible</b> (il est dans &lt;defs&gt;)"
 
-#: ../src/selection-chemistry.cpp:2124
+#: ../src/selection-chemistry.cpp:2147
 msgid "Select <b>object(s)</b> to convert to marker."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à convertir en marqueur."
 
-#: ../src/selection-chemistry.cpp:2192
+#: ../src/selection-chemistry.cpp:2215
 msgid "Objects to marker"
 msgstr "Objets en marqueur"
 
-#: ../src/selection-chemistry.cpp:2220
+#: ../src/selection-chemistry.cpp:2243
 msgid "Select <b>object(s)</b> to convert to guides."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à convertir en guides."
 
-#: ../src/selection-chemistry.cpp:2232
+#: ../src/selection-chemistry.cpp:2255
 msgid "Objects to guides"
 msgstr "Objets en guides"
 
-#: ../src/selection-chemistry.cpp:2248
+#: ../src/selection-chemistry.cpp:2271
 msgid "Select <b>object(s)</b> to convert to pattern."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à convertir en motif de remplissage."
 
-#: ../src/selection-chemistry.cpp:2336
+#: ../src/selection-chemistry.cpp:2359
 msgid "Objects to pattern"
 msgstr "Objets en motif"
 
-#: ../src/selection-chemistry.cpp:2352
+#: ../src/selection-chemistry.cpp:2375
 msgid "Select an <b>object with pattern fill</b> to extract objects from."
 msgstr "Sélectionner un <b>objet rempli avec un motif</b> pour en extraire des objets."
 
-#: ../src/selection-chemistry.cpp:2405
+#: ../src/selection-chemistry.cpp:2428
 msgid "<b>No pattern fills</b> in the selection."
 msgstr "<b>Aucun motif de remplissage</b> dans la sélection."
 
-#: ../src/selection-chemistry.cpp:2408
+#: ../src/selection-chemistry.cpp:2431
 msgid "Pattern to objects"
 msgstr "Motif en objets"
 
-#: ../src/selection-chemistry.cpp:2493
+#: ../src/selection-chemistry.cpp:2516
 msgid "Select <b>object(s)</b> to make a bitmap copy."
 msgstr "Sélectionner un ou des <b>objet(s)</b> pour en faire une copie bitmap."
 
-#: ../src/selection-chemistry.cpp:2497
+#: ../src/selection-chemistry.cpp:2520
 msgid "Rendering bitmap..."
 msgstr "Génération du bitmap..."
 
-#: ../src/selection-chemistry.cpp:2676
+#: ../src/selection-chemistry.cpp:2699
 msgid "Create bitmap"
 msgstr "Créer un bitmap"
 
-#: ../src/selection-chemistry.cpp:2708
+#: ../src/selection-chemistry.cpp:2731
 msgid "Select <b>object(s)</b> to create clippath or mask from."
 msgstr "Sélectionner un ou des <b>objet(s)</b> à partir desquels un chemin de découpe ou un masque sera créé."
 
-#: ../src/selection-chemistry.cpp:2711
+#: ../src/selection-chemistry.cpp:2734
 msgid "Select mask object and <b>object(s)</b> to apply clippath or mask to."
 msgstr "Sélectionner un objet masque et un ou des <b>objet(s)</b> auxquels appliquer ce chemin de découpe ou masque."
 
-#: ../src/selection-chemistry.cpp:2818
+#: ../src/selection-chemistry.cpp:2841
 msgid "Set clipping path"
 msgstr "Définir un chemin de découpe"
 
-#: ../src/selection-chemistry.cpp:2820
+#: ../src/selection-chemistry.cpp:2843
 msgid "Set mask"
 msgstr "Définir un masque"
 
-#: ../src/selection-chemistry.cpp:2833
+#: ../src/selection-chemistry.cpp:2856
 msgid "Select <b>object(s)</b> to remove clippath or mask from."
 msgstr "Sélectionner un ou des <b>objet(s)</b> pour en retirer le chemin de découpe ou le masque."
 
-#: ../src/selection-chemistry.cpp:2906
+#: ../src/selection-chemistry.cpp:2929
 msgid "Release clipping path"
 msgstr "Retirer le chemin de découpe"
 
-#: ../src/selection-chemistry.cpp:2908
+#: ../src/selection-chemistry.cpp:2931
 msgid "Release mask"
 msgstr "Retirer le masque"
 
-#: ../src/selection-chemistry.cpp:2924
+#: ../src/selection-chemistry.cpp:2947
 msgid "Select <b>object(s)</b> to fit canvas to."
 msgstr "Sélectionner un ou des <b>objet(s)</b> pour y ajuster la taille de la zone de travail."
 
 #. Fit Page
-#: ../src/selection-chemistry.cpp:2944
-#: ../src/verbs.cpp:2739
+#: ../src/selection-chemistry.cpp:2967
+#: ../src/verbs.cpp:2749
 msgid "Fit Page to Selection"
 msgstr "Ajuster la page à la sélection"
 
-#: ../src/selection-chemistry.cpp:2969
-#: ../src/verbs.cpp:2741
+#: ../src/selection-chemistry.cpp:2992
+#: ../src/verbs.cpp:2751
 msgid "Fit Page to Drawing"
 msgstr "Ajuster la page au dessin"
 
-#: ../src/selection-chemistry.cpp:2985
-#: ../src/verbs.cpp:2743
+#: ../src/selection-chemistry.cpp:3008
+#: ../src/verbs.cpp:2753
 msgid "Fit Page to Selection or Drawing"
 msgstr "Ajuster la page à la sélection ou au dessin"
 
@@ -9465,8 +9466,8 @@ msgstr "Cercle"
 #: ../src/selection-describer.cpp:49
 #: ../src/selection-describer.cpp:76
 #: ../src/ui/dialog/inkscape-preferences.cpp:480
-#: ../src/verbs.cpp:2522
-#: ../src/widgets/toolbox.cpp:3917
+#: ../src/verbs.cpp:2528
+#: ../src/widgets/toolbox.cpp:3920
 msgid "Ellipse"
 msgstr "Ellipse"
 
@@ -9494,14 +9495,14 @@ msgstr "Polyligne"
 #. Rectangle
 #: ../src/selection-describer.cpp:65
 #: ../src/ui/dialog/inkscape-preferences.cpp:470
-#: ../src/verbs.cpp:2518
+#: ../src/verbs.cpp:2524
 msgid "Rectangle"
 msgstr "Rectangle"
 
 #. 3D box
 #: ../src/selection-describer.cpp:67
 #: ../src/ui/dialog/inkscape-preferences.cpp:475
-#: ../src/verbs.cpp:2520
+#: ../src/verbs.cpp:2526
 msgid "3D Box"
 msgstr "Boîte 3D"
 
@@ -9519,14 +9520,14 @@ msgstr "Chemin offset"
 #. Spiral
 #: ../src/selection-describer.cpp:80
 #: ../src/ui/dialog/inkscape-preferences.cpp:488
-#: ../src/verbs.cpp:2526
+#: ../src/verbs.cpp:2532
 msgid "Spiral"
 msgstr "Spirale"
 
 #. Star
 #: ../src/selection-describer.cpp:82
 #: ../src/ui/dialog/inkscape-preferences.cpp:484
-#: ../src/verbs.cpp:2524
+#: ../src/verbs.cpp:2530
 #: ../src/widgets/toolbox.cpp:2760
 msgid "Star"
 msgstr "Étoile"
@@ -9597,7 +9598,7 @@ msgstr "Utilisez <b>Maj+D</b> pour sélectionner le cadre"
 
 #. this is only used with 2 or more objects
 #: ../src/selection-describer.cpp:211
-#: ../src/spray-context.cpp:288
+#: ../src/spray-context.cpp:284
 #: ../src/tweak-context.cpp:202
 #, c-format
 msgid "<b>%i</b> object selected"
@@ -9750,19 +9751,25 @@ msgstr "Région d'encadrement"
 msgid "Flow excluded region"
 msgstr "Région d'encadrement exclue"
 
-#: ../src/sp-flowtext.cpp:376
+#: ../src/sp-flowtext.cpp:378
+#: ../src/sp-text.cpp:427
+#: ../src/text-context.cpp:1604
+msgid " [truncated]"
+msgstr "[tronqué]"
+
+#: ../src/sp-flowtext.cpp:382
 #, c-format
-msgid "<b>Flowed text</b> (%d character)"
-msgid_plural "<b>Flowed text</b> (%d characters)"
-msgstr[0] "<b>Texte encadré</b> (%d caractère)"
-msgstr[1] "<b>Texte encadré</b> (%d caractères)"
+msgid "<b>Flowed text</b> (%d character%s)"
+msgid_plural "<b>Flowed text</b> (%d characters%s)"
+msgstr[0] "<b>Texte encadré</b> (%d caractère%s)"
+msgstr[1] "<b>Texte encadré</b> (%d caractères%s)"
 
-#: ../src/sp-flowtext.cpp:378
+#: ../src/sp-flowtext.cpp:384
 #, c-format
-msgid "<b>Linked flowed text</b> (%d character)"
-msgid_plural "<b>Linked flowed text</b> (%d characters)"
-msgstr[0] "<b>Texte encadré lié</b> (%d caractère)"
-msgstr[1] "<b>Texte encadré lié</b> (%d caractères)"
+msgid "<b>Linked flowed text</b> (%d character%s)"
+msgid_plural "<b>Linked flowed text</b> (%d characters%s)"
+msgstr[0] "<b>Texte encadré lié</b> (%d caractère%s)"
+msgstr[1] "<b>Texte encadré lié</b> (%d caractères%s)"
 
 #: ../src/sp-guide.cpp:287
 msgid "Guides Around Page"
@@ -9842,7 +9849,7 @@ msgstr "%s; <i>filtré (%s)</i>"
 msgid "%s; <i>filtered</i>"
 msgstr "%s; <i>filtré</i>"
 
-#: ../src/sp-item-group.cpp:761
+#: ../src/sp-item-group.cpp:741
 #, c-format
 msgid "<b>Group</b> of <b>%d</b> object"
 msgid_plural "<b>Group</b> of <b>%d</b> objects"
@@ -10058,15 +10065,15 @@ msgstr[1] "<b>Groupe conditionnel</b> de <b>%d</b> objets"
 msgid "&lt;no name found&gt;"
 msgstr "&lt;aucun nom trouvé&gt;"
 
-#: ../src/sp-text.cpp:425
+#: ../src/sp-text.cpp:431
 #, c-format
-msgid "<b>Text on path</b> (%s, %s)"
-msgstr "<b>Texte le long d'un chemin</b> (%s, %s)"
+msgid "<b>Text on path</b>%s (%s, %s)"
+msgstr "<b>Texte le long d'un chemin</b>%s (%s, %s)"
 
-#: ../src/sp-text.cpp:426
+#: ../src/sp-text.cpp:432
 #, c-format
-msgid "<b>Text</b> (%s, %s)"
-msgstr "<b>Texte</b> (%s, %s)"
+msgid "<b>Text</b>%s (%s, %s)"
+msgstr "<b>Texte</b>%s (%s, %s)"
 
 #: ../src/sp-tref.cpp:368
 #, c-format
@@ -10100,47 +10107,47 @@ msgstr "<b>Clone</b> de : %s"
 msgid "<b>Orphaned clone</b>"
 msgstr "<b>Clone orphelin</b>"
 
-#: ../src/spray-context.cpp:290
+#: ../src/spray-context.cpp:286
 #: ../src/tweak-context.cpp:204
 #, c-format
 msgid "<b>Nothing</b> selected"
 msgstr "<b>Rien</b> n'a été sélectionné."
 
-#: ../src/spray-context.cpp:296
+#: ../src/spray-context.cpp:292
 #, c-format
 msgid "%s. Drag, click or scroll to spray <b>copies</b> of the initial selection"
 msgstr "%s. Cliquer-déplacer, cliquer ou défiler pour pulvériser des <b>copies</b> de la sélection initiale"
 
-#: ../src/spray-context.cpp:299
+#: ../src/spray-context.cpp:295
 #, c-format
 msgid "%s. Drag, click or scroll to spray <b>clones</b> of the initial selection"
 msgstr "%s. Cliquer-déplacer, cliquer ou défiler pour pulvériser des <b>clones</b> de la sélection initiale"
 
-#: ../src/spray-context.cpp:302
+#: ../src/spray-context.cpp:298
 #, c-format
 msgid "%s. Drag, click or scroll to spray in a <b>single path</b> of the initial selection"
 msgstr "%s. Cliquer-déplacer, cliquer ou défiler pour pulvériser dans un <b>chemin unique</b> la sélection initiale"
 
-#: ../src/spray-context.cpp:305
+#: ../src/spray-context.cpp:301
 #, c-format
 msgid "%s. Modify <b>spray</b> options"
 msgstr "%s. Modifier les options du  <b>pulvérisateur</b>"
 
-#: ../src/spray-context.cpp:917
+#: ../src/spray-context.cpp:926
 msgid "<b>Nothing selected!</b> Select objects to spray."
 msgstr "<b>Sélection vide !</b> Sélectionner les objets à pulvériser."
 
-#: ../src/spray-context.cpp:1025
-#: ../src/widgets/toolbox.cpp:4525
+#: ../src/spray-context.cpp:1034
+#: ../src/widgets/toolbox.cpp:4528
 msgid "Spray with copies"
 msgstr "Pulvérise avec des copies"
 
-#: ../src/spray-context.cpp:1029
-#: ../src/widgets/toolbox.cpp:4532
+#: ../src/spray-context.cpp:1038
+#: ../src/widgets/toolbox.cpp:4535
 msgid "Spray with clones"
 msgstr "Pulvérise avec des clones"
 
-#: ../src/spray-context.cpp:1033
+#: ../src/spray-context.cpp:1042
 msgid "Spray in single path"
 msgstr "Pulvérisation par union des formes"
 
@@ -10180,7 +10187,7 @@ msgid "The flowed text(s) must be <b>visible</b> in order to be put on a path."
 msgstr "Le texte à mettre le long d'un chemin doit être <b>visible</b>."
 
 #: ../src/text-chemistry.cpp:192
-#: ../src/verbs.cpp:2374
+#: ../src/verbs.cpp:2380
 msgid "Put text on path"
 msgstr "Mettre le texte le long d'un chemin"
 
@@ -10193,7 +10200,7 @@ msgid "<b>No texts-on-paths</b> in the selection."
 msgstr "<b>Aucun texte le long d'un chemin</b> dans la sélection."
 
 #: ../src/text-chemistry.cpp:229
-#: ../src/verbs.cpp:2376
+#: ../src/verbs.cpp:2382
 msgid "Remove text from path"
 msgstr "Retirer le texte du chemin"
 
@@ -10238,141 +10245,141 @@ msgstr "Convertir du texte encadré en texte"
 msgid "<b>No flowed text(s)</b> to convert in the selection."
 msgstr "<b>Aucun texte encadré</b> à convertir dans la sélection."
 
-#: ../src/text-context.cpp:441
+#: ../src/text-context.cpp:448
 msgid "<b>Click</b> to edit the text, <b>drag</b> to select part of the text."
 msgstr "<b>Cliquer</b> pour éditer le texte, <b>cliquer-déplacer</b> pour sélectionner une partie du texte."
 
-#: ../src/text-context.cpp:443
+#: ../src/text-context.cpp:450
 msgid "<b>Click</b> to edit the flowed text, <b>drag</b> to select part of the text."
 msgstr "<b>Cliquer</b> pour éditer le texte encadré, <b>cliquer-déplacer</b> pour sélectionner une partie du texte."
 
-#: ../src/text-context.cpp:498
+#: ../src/text-context.cpp:505
 msgid "Create text"
 msgstr "Créer un texte"
 
-#: ../src/text-context.cpp:522
+#: ../src/text-context.cpp:529
 msgid "Non-printable character"
 msgstr "Caractère non imprimable"
 
-#: ../src/text-context.cpp:537
+#: ../src/text-context.cpp:544
 msgid "Insert Unicode character"
 msgstr "Insérer un caractère Unicode"
 
-#: ../src/text-context.cpp:572
+#: ../src/text-context.cpp:579
 #, c-format
 msgid "Unicode (<b>Enter</b> to finish): %s: %s"
 msgstr "Unicode (<b>Entrée</b> pour terminer) : %s: %s"
 
-#: ../src/text-context.cpp:574
-#: ../src/text-context.cpp:849
+#: ../src/text-context.cpp:581
+#: ../src/text-context.cpp:856
 msgid "Unicode (<b>Enter</b> to finish): "
 msgstr "Unicode (<b>Entrée</b> pour terminer) : "
 
-#: ../src/text-context.cpp:649
+#: ../src/text-context.cpp:656
 #, c-format
 msgid "<b>Flowed text frame</b>: %s &#215; %s"
 msgstr "<b>Cadre de texte </b>: %s &#215; %s"
 
-#: ../src/text-context.cpp:681
+#: ../src/text-context.cpp:688
 msgid "Type text; <b>Enter</b> to start new line."
-msgstr "Taper le texte; <b>Entrée</b> pour commencer une nouvelle ligne."
+msgstr "Taper le texte ; <b>Entrée</b> pour commencer une nouvelle ligne."
 
-#: ../src/text-context.cpp:694
+#: ../src/text-context.cpp:701
 msgid "Flowed text is created."
 msgstr "Le texte encadré est créé."
 
-#: ../src/text-context.cpp:696
+#: ../src/text-context.cpp:703
 msgid "Create flowed text"
 msgstr "Créer un texte encadré"
 
-#: ../src/text-context.cpp:698
+#: ../src/text-context.cpp:705
 msgid "The frame is <b>too small</b> for the current font size. Flowed text not created."
 msgstr "Le cadre est <b>trop petit</b> pour la taille de police courante. Le texte encadré n'a pas été créé."
 
-#: ../src/text-context.cpp:834
+#: ../src/text-context.cpp:841
 msgid "No-break space"
 msgstr "Espace insécable"
 
-#: ../src/text-context.cpp:836
+#: ../src/text-context.cpp:843
 msgid "Insert no-break space"
 msgstr "Insérer un espace insécable"
 
-#: ../src/text-context.cpp:873
+#: ../src/text-context.cpp:880
 msgid "Make bold"
 msgstr "Rendre gras"
 
-#: ../src/text-context.cpp:891
+#: ../src/text-context.cpp:898
 msgid "Make italic"
 msgstr "Rendre italique"
 
-#: ../src/text-context.cpp:930
+#: ../src/text-context.cpp:937
 msgid "New line"
 msgstr "Nouvelle ligne"
 
-#: ../src/text-context.cpp:964
+#: ../src/text-context.cpp:971
 msgid "Backspace"
 msgstr "Retour arrière"
 
-#: ../src/text-context.cpp:1012
+#: ../src/text-context.cpp:1019
 msgid "Kern to the left"
 msgstr "Créner vers la gauche"
 
-#: ../src/text-context.cpp:1037
+#: ../src/text-context.cpp:1044
 msgid "Kern to the right"
 msgstr "Créner vers la droite"
 
-#: ../src/text-context.cpp:1062
+#: ../src/text-context.cpp:1069
 msgid "Kern up"
 msgstr "Créner vers le haut"
 
-#: ../src/text-context.cpp:1088
+#: ../src/text-context.cpp:1095
 msgid "Kern down"
 msgstr "Créner vers le bas"
 
-#: ../src/text-context.cpp:1165
+#: ../src/text-context.cpp:1172
 msgid "Rotate counterclockwise"
 msgstr "Tourner dans le sens anti-horaire"
 
-#: ../src/text-context.cpp:1186
+#: ../src/text-context.cpp:1193
 msgid "Rotate clockwise"
 msgstr "Tourner dans le sens horaire"
 
-#: ../src/text-context.cpp:1203
+#: ../src/text-context.cpp:1210
 msgid "Contract line spacing"
 msgstr "Diminuer l'espacement entre les lignes"
 
-#: ../src/text-context.cpp:1211
+#: ../src/text-context.cpp:1218
 msgid "Contract letter spacing"
 msgstr "Diminuer l'espacement des lettres"
 
-#: ../src/text-context.cpp:1230
+#: ../src/text-context.cpp:1237
 msgid "Expand line spacing"
 msgstr "Augmenter l'espacement entre les lignes"
 
-#: ../src/text-context.cpp:1238
+#: ../src/text-context.cpp:1245
 msgid "Expand letter spacing"
 msgstr "Augmenter l'espacement des lettres"
 
-#: ../src/text-context.cpp:1368
+#: ../src/text-context.cpp:1375
 msgid "Paste text"
 msgstr "Coller le texte"
 
-#: ../src/text-context.cpp:1602
+#: ../src/text-context.cpp:1621
 #, c-format
-msgid "Type or edit flowed text (%d characters); <b>Enter</b> to start new paragraph."
-msgstr "Taper ou modifier le texte encadré (%d caractères); <b>Entrée</b> pour commencer un nouveau paragraphe."
+msgid "Type or edit flowed text (%d characters%s); <b>Enter</b> to start new paragraph."
+msgstr "Saisir ou modifier le texte encadré (%d caractères%s) ; <b>Entrée</b> pour commencer un nouveau paragraphe."
 
-#: ../src/text-context.cpp:1604
+#: ../src/text-context.cpp:1623
 #, c-format
-msgid "Type or edit text (%d characters); <b>Enter</b> to start new line."
-msgstr "Taper ou modifier le texte (%d caractères) ; <b>Entrée</b> pour commencer une nouvelle ligne."
+msgid "Type or edit text (%d characters%s); <b>Enter</b> to start new line."
+msgstr "Saisir ou modifier le texte (%d caractères%s) ; <b>Entrée</b> pour commencer une nouvelle ligne."
 
-#: ../src/text-context.cpp:1612
+#: ../src/text-context.cpp:1631
 #: ../src/tools-switch.cpp:198
 msgid "<b>Click</b> to select or create text, <b>drag</b> to create flowed text; then type."
 msgstr "<b>Cliquer</b> pour sélectionner ou créer un texte, <b>cliquer-déplacer</b> pour créer un texte encadré; puis taper le texte."
 
-#: ../src/text-context.cpp:1722
+#: ../src/text-context.cpp:1741
 msgid "Type text"
 msgstr "Taper du texte"
 
@@ -10703,7 +10710,7 @@ msgstr "Créer un lien"
 
 #. "Ungroup"
 #: ../src/ui/context-menu.cpp:306
-#: ../src/verbs.cpp:2370
+#: ../src/verbs.cpp:2376
 msgid "_Ungroup"
 msgstr "_Dégrouper"
 
@@ -10821,15 +10828,15 @@ msgstr "V :"
 
 #: ../src/ui/dialog/align-and-distribute.cpp:509
 #: ../src/ui/dialog/align-and-distribute.cpp:789
-#: ../src/ui/dialog/spray-option.cpp:116
-#: ../src/ui/dialog/spray-option.cpp:194
-#: ../src/ui/dialog/spray-option.cpp:212
-#: ../src/widgets/toolbox.cpp:7475
+#: ../src/ui/dialog/spray-option.cpp:117
+#: ../src/ui/dialog/spray-option.cpp:195
+#: ../src/ui/dialog/spray-option.cpp:213
+#: ../src/widgets/toolbox.cpp:7555
 msgid "Remove overlaps"
 msgstr "Supprimer les chevauchements"
 
 #: ../src/ui/dialog/align-and-distribute.cpp:540
-#: ../src/widgets/toolbox.cpp:7265
+#: ../src/widgets/toolbox.cpp:7345
 msgid "Arrange connector network"
 msgstr "Arranger le réseau de connecteurs"
 
@@ -10967,7 +10974,7 @@ msgid "Move objects as little as possible so that their bounding boxes do not ov
 msgstr "Déplacer les objets aussi peu que possible afin que leurs boîtes englobantes ne se chevauchent pas"
 
 #: ../src/ui/dialog/align-and-distribute.cpp:893
-#: ../src/widgets/toolbox.cpp:7436
+#: ../src/widgets/toolbox.cpp:7516
 msgid "Nicely arrange selected connector network"
 msgstr "Dispose le réseau de connecteurs sélectionnés de façon agréable"
 
@@ -11007,7 +11014,7 @@ msgstr "Objet le plus petit"
 #: ../src/ui/dialog/align-and-distribute.cpp:921
 #: ../src/ui/dialog/filedialogimpl-gtkmm.cpp:1414
 #: ../src/ui/dialog/icon-preview.cpp:178
-#: ../src/widgets/desktop-widget.cpp:1580
+#: ../src/widgets/desktop-widget.cpp:1588
 msgid "Selection"
 msgstr "Sélection"
 
@@ -11188,7 +11195,7 @@ msgid "Grids"
 msgstr "Grilles"
 
 #: ../src/ui/dialog/document-properties.cpp:121
-#: ../src/verbs.cpp:2601
+#: ../src/verbs.cpp:2607
 #: ../src/widgets/toolbox.cpp:2055
 msgid "Snap"
 msgstr "Magnétisme"
@@ -11311,7 +11318,7 @@ msgstr "Le répertoire des profils (%s) est indisponible."
 #. inform the document, so we can undo
 #. Color Management
 #: ../src/ui/dialog/document-properties.cpp:452
-#: ../src/verbs.cpp:2755
+#: ../src/verbs.cpp:2765
 msgid "Link Color Profile"
 msgstr "Lier un profil de couleurs"
 
@@ -11717,9 +11724,9 @@ msgid "Height of filter effects region"
 msgstr "Hauteur de la zone d'action du filtre"
 
 #: ../src/ui/dialog/filter-effects-dialog.cpp:2165
-#: ../src/widgets/toolbox.cpp:3886
-#: ../src/widgets/toolbox.cpp:4277
-#: ../src/widgets/toolbox.cpp:4545
+#: ../src/widgets/toolbox.cpp:3889
+#: ../src/widgets/toolbox.cpp:4278
+#: ../src/widgets/toolbox.cpp:4548
 #: ../share/extensions/extrude.inx.h:4
 msgid "Mode:"
 msgstr "Mode :"
@@ -11891,7 +11898,7 @@ msgid "The whole filter region will be filled with this color."
 msgstr "Toute la région affectée par le filtre sera remplie avec cette couleur."
 
 #: ../src/ui/dialog/filter-effects-dialog.cpp:2214
-#: ../src/widgets/toolbox.cpp:5518
+#: ../src/widgets/toolbox.cpp:5521
 msgid "Opacity:"
 msgstr "Opacité :"
 
@@ -12183,7 +12190,7 @@ msgstr "Vitesse du défilement automatique de la zone de travail lors que l'on t
 #: ../src/ui/dialog/tracedialog.cpp:420
 #: ../src/ui/dialog/tracedialog.cpp:453
 #: ../src/ui/dialog/tracedialog.cpp:596
-#: ../src/widgets/toolbox.cpp:7617
+#: ../src/widgets/toolbox.cpp:7697
 msgid "Threshold:"
 msgstr "Seuil :"
 
@@ -12535,7 +12542,7 @@ msgstr "Définit combien de temps le contour sera visible après son survol par
 
 #. Tweak
 #: ../src/ui/dialog/inkscape-preferences.cpp:447
-#: ../src/verbs.cpp:2514
+#: ../src/verbs.cpp:2520
 msgid "Tweak"
 msgstr "Ajuster"
 
@@ -12546,14 +12553,14 @@ msgstr "Peindre les objets avec :"
 
 #. Spray
 #: ../src/ui/dialog/inkscape-preferences.cpp:453
-#: ../src/verbs.cpp:2516
+#: ../src/verbs.cpp:2522
 msgid "Spray"
 msgstr "Pulvérisateur"
 
 #. Zoom
 #: ../src/ui/dialog/inkscape-preferences.cpp:459
 #: ../src/ui/view/edit-widget.cpp:1068
-#: ../src/verbs.cpp:2538
+#: ../src/verbs.cpp:2544
 #: ../src/widgets/desktop-widget.cpp:483
 msgid "Zoom"
 msgstr "Zoom"
@@ -12573,13 +12580,13 @@ msgstr "Si coché, le résultat du croquis sera moyenné avec tous les autres cr
 
 #. Pen
 #: ../src/ui/dialog/inkscape-preferences.cpp:501
-#: ../src/verbs.cpp:2530
+#: ../src/verbs.cpp:2536
 msgid "Pen"
 msgstr "Stylo"
 
 #. Calligraphy
 #: ../src/ui/dialog/inkscape-preferences.cpp:507
-#: ../src/verbs.cpp:2532
+#: ../src/verbs.cpp:2538
 msgid "Calligraphy"
 msgstr "Plume calligraphique"
 
@@ -12593,19 +12600,19 @@ msgstr "Activer pour que les nouveaux objets soient automatiquement sélectionn
 
 #. Paint Bucket
 #: ../src/ui/dialog/inkscape-preferences.cpp:515
-#: ../src/verbs.cpp:2544
+#: ../src/verbs.cpp:2550
 msgid "Paint Bucket"
 msgstr "Remplissage au seau"
 
 #. Eraser
 #: ../src/ui/dialog/inkscape-preferences.cpp:520
-#: ../src/verbs.cpp:2548
+#: ../src/verbs.cpp:2554
 msgid "Eraser"
 msgstr "Gomme"
 
 #. LPETool
 #: ../src/ui/dialog/inkscape-preferences.cpp:524
-#: ../src/verbs.cpp:2550
+#: ../src/verbs.cpp:2556
 msgid "LPE Tool"
 msgstr "Outil effets de chemin en direct"
 
@@ -12619,13 +12626,13 @@ msgstr "Affiche les échantillons de police à côté du nom dans la liste déro
 
 #. Gradient
 #: ../src/ui/dialog/inkscape-preferences.cpp:539
-#: ../src/verbs.cpp:2536
+#: ../src/verbs.cpp:2542
 msgid "Gradient"
 msgstr "Dégradé"
 
 #. Connector
 #: ../src/ui/dialog/inkscape-preferences.cpp:543
-#: ../src/verbs.cpp:2542
+#: ../src/verbs.cpp:2548
 msgid "Connector"
 msgstr "Connecteur"
 
@@ -12635,7 +12642,7 @@ msgstr "Si coché, les points d'accroche de connecteur ne sont pas montrés pour
 
 #. Dropper
 #: ../src/ui/dialog/inkscape-preferences.cpp:548
-#: ../src/verbs.cpp:2540
+#: ../src/verbs.cpp:2546
 msgid "Dropper"
 msgstr "Pipette"
 
@@ -14115,32 +14122,64 @@ msgstr "Rechercher"
 msgid "Files found"
 msgstr "Fichiers trouvés"
 
-#: ../src/ui/dialog/print.cpp:93
+#: ../src/ui/dialog/print.cpp:97
 msgid "Could not open temporary PNG for bitmap printing"
 msgstr "Impossible d'ouvrir un PNG temporaire pour imprimer en bitmap."
 
-#: ../src/ui/dialog/print.cpp:136
+#: ../src/ui/dialog/print.cpp:140
 msgid "Could not set up Document"
 msgstr "Impossible de préparer le document"
 
-#: ../src/ui/dialog/print.cpp:140
+#: ../src/ui/dialog/print.cpp:144
 msgid "Failed to set CairoRenderContext"
 msgstr "Erreur au réglage de CairoRenderContext"
 
 #. set up dialog title, based on document name
-#: ../src/ui/dialog/print.cpp:180
+#: ../src/ui/dialog/print.cpp:184
 msgid "SVG Document"
 msgstr "Document SVG"
 
-#: ../src/ui/dialog/print.cpp:181
+#: ../src/ui/dialog/print.cpp:185
 msgid "Print"
 msgstr "Imprimer"
 
 #. build custom preferences tab
-#: ../src/ui/dialog/print.cpp:215
+#: ../src/ui/dialog/print.cpp:219
 msgid "Rendering"
 msgstr "Rendu"
 
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:61
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:466
+#: ../src/widgets/sp-color-scales.cpp:467
+msgid "Cyan"
+msgstr "Cyan"
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:66
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:469
+#: ../src/widgets/sp-color-scales.cpp:470
+msgid "Magenta"
+msgstr "Magenta"
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:71
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:472
+#: ../src/widgets/sp-color-scales.cpp:473
+msgid "Yellow"
+msgstr "Jaune"
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:76
+#: ../src/ui/widget/selected-style.cpp:236
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-scales.cpp:475
+#: ../src/widgets/sp-color-scales.cpp:476
+msgid "Black"
+msgstr "Noir"
+
 #: ../src/ui/dialog/scriptdialog.cpp:211
 msgid "_Execute Javascript"
 msgstr "_Exécuter Javascript"
@@ -14165,21 +14204,21 @@ msgstr "Résultat"
 msgid "Errors"
 msgstr "Erreurs"
 
-#: ../src/ui/dialog/spray-option.cpp:154
+#: ../src/ui/dialog/spray-option.cpp:155
 #: ../share/extensions/polyhedron_3d.inx.h:26
 msgid "Minimum"
 msgstr "Minimum"
 
-#: ../src/ui/dialog/spray-option.cpp:156
+#: ../src/ui/dialog/spray-option.cpp:157
 msgid "Min"
 msgstr "Min"
 
-#: ../src/ui/dialog/spray-option.cpp:164
+#: ../src/ui/dialog/spray-option.cpp:165
 #: ../share/extensions/polyhedron_3d.inx.h:24
 msgid "Maximum"
 msgstr "Maximum"
 
-#: ../src/ui/dialog/spray-option.cpp:166
+#: ../src/ui/dialog/spray-option.cpp:167
 msgid "Max:"
 msgstr "Max :"
 
@@ -14195,60 +14234,60 @@ msgstr "Options du curseur"
 msgid "sprayOptions|Random Options"
 msgstr "Options aléatoires"
 
+#: ../src/ui/dialog/spray-option.cpp:262
+msgid "sprayOptions|Distribution:"
+msgstr "Distribution :"
+
 #. ComboBoxText
-#: ../src/ui/dialog/spray-option.cpp:251
-#: ../src/ui/dialog/spray-option.cpp:260
+#: ../src/ui/dialog/spray-option.cpp:263
+#: ../src/ui/dialog/spray-option.cpp:276
 msgid "sprayOptions|Uniform"
 msgstr "Uniforme"
 
-#: ../src/ui/dialog/spray-option.cpp:252
-#: ../src/ui/dialog/spray-option.cpp:261
+#: ../src/ui/dialog/spray-option.cpp:264
+#: ../src/ui/dialog/spray-option.cpp:277
 msgid "sprayOptions|Gaussian"
 msgstr "Gaussienne"
 
-#: ../src/ui/dialog/spray-option.cpp:253
-msgid "sprayOptions|Distribution:"
-msgstr "Distribution :"
-
 #. Hbox Random
-#: ../src/ui/dialog/spray-option.cpp:277
+#: ../src/ui/dialog/spray-option.cpp:293
 msgid "sprayOptions|Scale:"
 msgstr "Échelle :"
 
-#: ../src/ui/dialog/spray-option.cpp:277
+#: ../src/ui/dialog/spray-option.cpp:293
 msgid "Apply a scale factor"
 msgstr "Appliquer un facteur d'échelle"
 
-#: ../src/ui/dialog/spray-option.cpp:278
+#: ../src/ui/dialog/spray-option.cpp:294
 msgid "sprayOptions|Rotation:"
 msgstr "Rotation :"
 
-#: ../src/ui/dialog/spray-option.cpp:278
+#: ../src/ui/dialog/spray-option.cpp:294
 msgid "Apply rotation"
 msgstr "Appliquer une totation"
 
 #. Hbox Cursor
-#: ../src/ui/dialog/spray-option.cpp:287
+#: ../src/ui/dialog/spray-option.cpp:303
 msgid "sprayOptions|Ratio:"
 msgstr "Rapport :"
 
-#: ../src/ui/dialog/spray-option.cpp:287
+#: ../src/ui/dialog/spray-option.cpp:303
 msgid "Eccentricity of the ellipse"
 msgstr "Excentricité de l'ellipse"
 
-#: ../src/ui/dialog/spray-option.cpp:288
+#: ../src/ui/dialog/spray-option.cpp:304
 msgid "sprayOptions|Angle:"
 msgstr "Angle :"
 
-#: ../src/ui/dialog/spray-option.cpp:288
+#: ../src/ui/dialog/spray-option.cpp:304
 msgid "Angle of the ellipse"
 msgstr "Angle de l'ellipse"
 
-#: ../src/ui/dialog/spray-option.cpp:289
+#: ../src/ui/dialog/spray-option.cpp:305
 msgid "sprayOptions|Width:"
 msgstr "Largeur :"
 
-#: ../src/ui/dialog/spray-option.cpp:289
+#: ../src/ui/dialog/spray-option.cpp:305
 msgid "Size of the ellipse"
 msgstr "Taille de l'ellipse"
 
@@ -14680,8 +14719,8 @@ msgstr "Passes multiples : crée un groupe de chemins"
 #. # end multiple scan
 #. ## end mode page
 #: ../src/ui/dialog/tracedialog.cpp:563
-#: ../src/widgets/toolbox.cpp:4276
-#: ../src/widgets/toolbox.cpp:4544
+#: ../src/widgets/toolbox.cpp:4277
+#: ../src/widgets/toolbox.cpp:4547
 #: ../share/extensions/triangle.inx.h:9
 msgid "Mode"
 msgstr "Mode"
@@ -14966,7 +15005,7 @@ msgid "<b>Welcome to Inkscape!</b> Use shape or drawing tools to create objects;
 msgstr "<b>Bienvenue dans Inkscape !</b> Utilisez les outils de formes ou de dessin à main levée pour créer des objets; utilisez les sélecteurs (flèches) pour les déplacer ou les modifier."
 
 #: ../src/ui/view/edit-widget.cpp:1206
-#: ../src/widgets/desktop-widget.cpp:838
+#: ../src/widgets/desktop-widget.cpp:846
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">Save changes to document \"%s\" before closing?</span>\n"
@@ -14979,13 +15018,13 @@ msgstr ""
 
 #: ../src/ui/view/edit-widget.cpp:1217
 #: ../src/ui/view/edit-widget.cpp:1265
-#: ../src/widgets/desktop-widget.cpp:845
-#: ../src/widgets/desktop-widget.cpp:902
+#: ../src/widgets/desktop-widget.cpp:853
+#: ../src/widgets/desktop-widget.cpp:910
 msgid "Close _without saving"
 msgstr "Fermer _sans enregistrer"
 
 #: ../src/ui/view/edit-widget.cpp:1253
-#: ../src/widgets/desktop-widget.cpp:894
+#: ../src/widgets/desktop-widget.cpp:902
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format (%s) that may cause data loss!</span>\n"
@@ -14997,7 +15036,7 @@ msgstr ""
 "Voulez-vous enregistrer ce fichier au format Inkscape SVG ?"
 
 #: ../src/ui/view/edit-widget.cpp:1268
-#: ../src/widgets/desktop-widget.cpp:905
+#: ../src/widgets/desktop-widget.cpp:913
 msgid "_Save as SVG"
 msgstr "Enregi_strer comme SVG"
 
@@ -15362,13 +15401,6 @@ msgstr "Dernière couleur sélectionnée"
 msgid "White"
 msgstr "Blanc"
 
-#: ../src/ui/widget/selected-style.cpp:236
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-scales.cpp:475
-#: ../src/widgets/sp-color-scales.cpp:476
-msgid "Black"
-msgstr "Noir"
-
 #: ../src/ui/widget/selected-style.cpp:240
 msgid "Copy color"
 msgstr "Copier la couleur"
@@ -15701,1534 +15733,1542 @@ msgstr "Retourner verticalement"
 #. TRANSLATORS: If you have translated the tutorial-basic.svg file to your language,
 #. then translate this string as "tutorial-basic.LANG.svg" (where LANG is your language
 #. code); otherwise leave as "tutorial-basic.svg".
-#: ../src/verbs.cpp:1922
+#: ../src/verbs.cpp:1928
 msgid "tutorial-basic.svg"
 msgstr "tutorial-basic.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1926
+#: ../src/verbs.cpp:1932
 msgid "tutorial-shapes.svg"
 msgstr "tutorial-shapes.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1930
+#: ../src/verbs.cpp:1936
 msgid "tutorial-advanced.svg"
 msgstr "tutorial-advanced.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1934
+#: ../src/verbs.cpp:1940
 msgid "tutorial-tracing.svg"
 msgstr "tutorial-tracing.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1938
+#: ../src/verbs.cpp:1944
 msgid "tutorial-calligraphy.svg"
 msgstr "tutorial-calligraphy.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1942
+#: ../src/verbs.cpp:1948
 msgid "tutorial-elements.svg"
 msgstr "tutorial-elements.fr.svg"
 
 # Name of the displayed file (in Help > tutorials > ...). To be translated if the tutorial has been translated.
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1946
+#: ../src/verbs.cpp:1952
 msgid "tutorial-tips.svg"
 msgstr "tutorial-tips.fr.svg"
 
-#: ../src/verbs.cpp:2222
-#: ../src/verbs.cpp:2747
+#: ../src/verbs.cpp:2228
+#: ../src/verbs.cpp:2757
 msgid "Unlock all objects in the current layer"
 msgstr "Déverrouiller tous les objets sur le calque courant"
 
-#: ../src/verbs.cpp:2226
-#: ../src/verbs.cpp:2749
+#: ../src/verbs.cpp:2232
+#: ../src/verbs.cpp:2759
 msgid "Unlock all objects in all layers"
 msgstr "Déverouiller tous les objets sur tous les calques"
 
-#: ../src/verbs.cpp:2230
-#: ../src/verbs.cpp:2751
+#: ../src/verbs.cpp:2236
+#: ../src/verbs.cpp:2761
 msgid "Unhide all objects in the current layer"
 msgstr "Montrer tous les objets sur le calque courant"
 
-#: ../src/verbs.cpp:2234
-#: ../src/verbs.cpp:2753
+#: ../src/verbs.cpp:2240
+#: ../src/verbs.cpp:2763
 msgid "Unhide all objects in all layers"
 msgstr "Montrer tous les objets sur tous les calques"
 
-#: ../src/verbs.cpp:2249
+#: ../src/verbs.cpp:2255
 msgid "Does nothing"
 msgstr "Ne fait rien"
 
-#: ../src/verbs.cpp:2252
+#: ../src/verbs.cpp:2258
 msgid "Create new document from the default template"
 msgstr "Créer un nouveau document depuis le modèle par défaut"
 
-#: ../src/verbs.cpp:2254
+#: ../src/verbs.cpp:2260
 msgid "_Open..."
 msgstr "_Ouvrir..."
 
-#: ../src/verbs.cpp:2255
+#: ../src/verbs.cpp:2261
 msgid "Open an existing document"
 msgstr "Ouvrir un document existant"
 
-#: ../src/verbs.cpp:2256
+#: ../src/verbs.cpp:2262
 msgid "Re_vert"
 msgstr "_Recharger"
 
-#: ../src/verbs.cpp:2257
+#: ../src/verbs.cpp:2263
 msgid "Revert to the last saved version of document (changes will be lost)"
 msgstr "Recharger le dernier enregistrement du document (les changements seront perdus)"
 
-#: ../src/verbs.cpp:2258
+#: ../src/verbs.cpp:2264
 msgid "_Save"
 msgstr "_Enregistrer"
 
-#: ../src/verbs.cpp:2258
+#: ../src/verbs.cpp:2264
 msgid "Save document"
 msgstr "Enregistrer le document"
 
-#: ../src/verbs.cpp:2260
+#: ../src/verbs.cpp:2266
 msgid "Save _As..."
 msgstr "Enregistrer _sous..."
 
-#: ../src/verbs.cpp:2261
+#: ../src/verbs.cpp:2267
 msgid "Save document under a new name"
 msgstr "Enregistrer le document sous un nouveau nom"
 
-#: ../src/verbs.cpp:2262
+#: ../src/verbs.cpp:2268
 msgid "Save a Cop_y..."
 msgstr "Enregistrer une cop_ie..."
 
-#: ../src/verbs.cpp:2263
+#: ../src/verbs.cpp:2269
 msgid "Save a copy of the document under a new name"
 msgstr "Enregistrer une copie du document sous un nouveau nom"
 
-#: ../src/verbs.cpp:2264
+#: ../src/verbs.cpp:2270
 msgid "_Print..."
 msgstr "Im_primer..."
 
-#: ../src/verbs.cpp:2264
+#: ../src/verbs.cpp:2270
 msgid "Print document"
 msgstr "Imprimer le document"
 
 #. TRANSLATORS: "Vacuum Defs" means "Clean up defs" (so as to remove unused definitions)
-#: ../src/verbs.cpp:2267
+#: ../src/verbs.cpp:2273
 msgid "Vac_uum Defs"
 msgstr "Nettoyer les De_fs"
 
-#: ../src/verbs.cpp:2267
+#: ../src/verbs.cpp:2273
 msgid "Remove unused definitions (such as gradients or clipping paths) from the &lt;defs&gt; of the document"
 msgstr "Retirer les définitions inutilisées (comme des dégradés ou des chemins de découpe) des &lt;defs&gt; du document"
 
-#: ../src/verbs.cpp:2269
+#: ../src/verbs.cpp:2275
 msgid "Print Previe_w"
 msgstr "A_perçu avant impression"
 
-#: ../src/verbs.cpp:2270
+#: ../src/verbs.cpp:2276
 msgid "Preview document printout"
 msgstr "Prévisualiser avant impression"
 
-#: ../src/verbs.cpp:2271
+#: ../src/verbs.cpp:2277
 msgid "_Import..."
 msgstr "_Importer..."
 
-#: ../src/verbs.cpp:2272
+#: ../src/verbs.cpp:2278
 msgid "Import a bitmap or SVG image into this document"
 msgstr "Importer une image SVG ou bitmap dans ce document"
 
-#: ../src/verbs.cpp:2273
+#: ../src/verbs.cpp:2279
 msgid "_Export Bitmap..."
 msgstr "E_xporter en bitmap..."
 
-#: ../src/verbs.cpp:2274
+#: ../src/verbs.cpp:2280
 msgid "Export this document or a selection as a bitmap image"
 msgstr "Exporter ce document ou la sélection en image bitmap"
 
-#: ../src/verbs.cpp:2275
+#: ../src/verbs.cpp:2281
 msgid "Import a document from Open Clip Art Library"
 msgstr "Importer un document depuis la bibliothèque Open Clip Art"
 
 #. new FileVerb(SP_VERB_FILE_EXPORT_TO_OCAL, "FileExportToOCAL", N_("Export To Open Clip Art Library"), N_("Export this document to Open Clip Art Library"), INKSCAPE_ICON_DOCUMENT_EXPORT_OCAL),
-#: ../src/verbs.cpp:2277
+#: ../src/verbs.cpp:2283
 msgid "N_ext Window"
 msgstr "Fenêtre _suivante"
 
-#: ../src/verbs.cpp:2278
+#: ../src/verbs.cpp:2284
 msgid "Switch to the next document window"
 msgstr "Passer à la fenêtre (document) suivante"
 
-#: ../src/verbs.cpp:2279
+#: ../src/verbs.cpp:2285
 msgid "P_revious Window"
 msgstr "Fenêtre _précédente"
 
-#: ../src/verbs.cpp:2280
+#: ../src/verbs.cpp:2286
 msgid "Switch to the previous document window"
 msgstr "Passer à la fenêtre (document) précédente"
 
-#: ../src/verbs.cpp:2281
+#: ../src/verbs.cpp:2287
 msgid "_Close"
 msgstr "_Fermer"
 
-#: ../src/verbs.cpp:2282
+#: ../src/verbs.cpp:2288
 msgid "Close this document window"
 msgstr "Fermer cette fenêtre document"
 
-#: ../src/verbs.cpp:2283
+#: ../src/verbs.cpp:2289
 msgid "_Quit"
 msgstr "_Quitter"
 
-#: ../src/verbs.cpp:2283
+#: ../src/verbs.cpp:2289
 msgid "Quit Inkscape"
 msgstr "Quitter Inkscape"
 
-#: ../src/verbs.cpp:2286
+#: ../src/verbs.cpp:2292
 msgid "Undo last action"
 msgstr "Annuler la dernière action"
 
-#: ../src/verbs.cpp:2289
+#: ../src/verbs.cpp:2295
 msgid "Do again the last undone action"
 msgstr "Refaire la dernière action annulée"
 
-#: ../src/verbs.cpp:2290
+#: ../src/verbs.cpp:2296
 msgid "Cu_t"
 msgstr "_Couper"
 
-#: ../src/verbs.cpp:2291
+#: ../src/verbs.cpp:2297
 msgid "Cut selection to clipboard"
 msgstr "Couper la sélection vers le presse-papiers"
 
-#: ../src/verbs.cpp:2292
+#: ../src/verbs.cpp:2298
 msgid "_Copy"
 msgstr "Co_pier"
 
-#: ../src/verbs.cpp:2293
+#: ../src/verbs.cpp:2299
 msgid "Copy selection to clipboard"
 msgstr "Copier la sélection vers le presse-papiers"
 
-#: ../src/verbs.cpp:2294
+#: ../src/verbs.cpp:2300
 msgid "_Paste"
 msgstr "C_oller"
 
-#: ../src/verbs.cpp:2295
+#: ../src/verbs.cpp:2301
 msgid "Paste objects from clipboard to mouse point, or paste text"
 msgstr "Coller les objets du presse-papiers sous le pointeur de souris, ou coller du texte"
 
-#: ../src/verbs.cpp:2296
+#: ../src/verbs.cpp:2302
 msgid "Paste _Style"
 msgstr "Coller le st_yle"
 
-#: ../src/verbs.cpp:2297
+#: ../src/verbs.cpp:2303
 msgid "Apply the style of the copied object to selection"
 msgstr "Appliquer le style de l'objet copié à la sélection"
 
-#: ../src/verbs.cpp:2299
+#: ../src/verbs.cpp:2305
 msgid "Scale selection to match the size of the copied object"
 msgstr "Redimensionner la sélection afin de correspondre aux dimensions de l'objet sélectionné"
 
-#: ../src/verbs.cpp:2300
+#: ../src/verbs.cpp:2306
 msgid "Paste _Width"
 msgstr "Coller la _largeur"
 
-#: ../src/verbs.cpp:2301
+#: ../src/verbs.cpp:2307
 msgid "Scale selection horizontally to match the width of the copied object"
 msgstr "Redimensionne horizontalement la sélection afin d'avoir la largeur de l'objet copié"
 
-#: ../src/verbs.cpp:2302
+#: ../src/verbs.cpp:2308
 msgid "Paste _Height"
 msgstr "Coller la _hauteur"
 
-#: ../src/verbs.cpp:2303
+#: ../src/verbs.cpp:2309
 msgid "Scale selection vertically to match the height of the copied object"
 msgstr "Redimensionne verticalement la sélection afin d'avoir la hauteur de l'objet copié"
 
-#: ../src/verbs.cpp:2304
+#: ../src/verbs.cpp:2310
 msgid "Paste Size Separately"
 msgstr "Coller les dimensions séparément"
 
-#: ../src/verbs.cpp:2305
+#: ../src/verbs.cpp:2311
 msgid "Scale each selected object to match the size of the copied object"
 msgstr "Redimensionner chaque objet sélectionné afin de correspondre aux dimensions de l'objet copié"
 
-#: ../src/verbs.cpp:2306
+#: ../src/verbs.cpp:2312
 msgid "Paste Width Separately"
 msgstr "Coller la largeur séparément"
 
-#: ../src/verbs.cpp:2307
+#: ../src/verbs.cpp:2313
 msgid "Scale each selected object horizontally to match the width of the copied object"
 msgstr "Redimensionner horizontalement chaque objet sélectionné afin de correspondre à la largeur de l'objet copié"
 
-#: ../src/verbs.cpp:2308
+#: ../src/verbs.cpp:2314
 msgid "Paste Height Separately"
 msgstr "Coller la hauteur séparément"
 
-#: ../src/verbs.cpp:2309
+#: ../src/verbs.cpp:2315
 msgid "Scale each selected object vertically to match the height of the copied object"
 msgstr "Redimensionner verticalement chaque objet sélectionné afin de correspondre à la hauteur de l'objet copié"
 
-#: ../src/verbs.cpp:2310
+#: ../src/verbs.cpp:2316
 msgid "Paste _In Place"
 msgstr "Coller sur pl_ace"
 
-#: ../src/verbs.cpp:2311
+#: ../src/verbs.cpp:2317
 msgid "Paste objects from clipboard to the original location"
 msgstr "Coller les objets du presse-papiers à leur emplacement d'origine"
 
-#: ../src/verbs.cpp:2312
+#: ../src/verbs.cpp:2318
 msgid "Paste Path _Effect"
 msgstr "Coller l'effet de chemin"
 
-#: ../src/verbs.cpp:2313
+#: ../src/verbs.cpp:2319
 msgid "Apply the path effect of the copied object to selection"
 msgstr "Appliquer l'effet de chemin de l'objet copié à la sélection"
 
-#: ../src/verbs.cpp:2314
+#: ../src/verbs.cpp:2320
 msgid "Remove Path _Effect"
 msgstr "Supprimer l'_effet de chemin"
 
-#: ../src/verbs.cpp:2315
+#: ../src/verbs.cpp:2321
 msgid "Remove any path effects from selected objects"
 msgstr "Retirer tous les effets de chemin de la sélection"
 
-#: ../src/verbs.cpp:2316
+#: ../src/verbs.cpp:2322
 msgid "Remove Filters"
 msgstr "Supprimer les filtres"
 
-#: ../src/verbs.cpp:2317
+#: ../src/verbs.cpp:2323
 msgid "Remove any filters from selected objects"
 msgstr "Retirer tous les filtres de la sélection"
 
-#: ../src/verbs.cpp:2318
+#: ../src/verbs.cpp:2324
 msgid "_Delete"
 msgstr "_Supprimer"
 
-#: ../src/verbs.cpp:2319
+#: ../src/verbs.cpp:2325
 msgid "Delete selection"
 msgstr "Supprimer la sélection"
 
-#: ../src/verbs.cpp:2320
+#: ../src/verbs.cpp:2326
 msgid "Duplic_ate"
 msgstr "Dupli_quer"
 
-#: ../src/verbs.cpp:2321
+#: ../src/verbs.cpp:2327
 msgid "Duplicate selected objects"
 msgstr "Dupliquer les objets sélectionnés"
 
-#: ../src/verbs.cpp:2322
+#: ../src/verbs.cpp:2328
 msgid "Create Clo_ne"
 msgstr "Créer un clo_ne"
 
-#: ../src/verbs.cpp:2323
+#: ../src/verbs.cpp:2329
 msgid "Create a clone (a copy linked to the original) of selected object"
 msgstr "Créer un clone (une copie liée à l'original) de l'objet sélectionné"
 
-#: ../src/verbs.cpp:2324
+#: ../src/verbs.cpp:2330
 msgid "Unlin_k Clone"
 msgstr "_Délier le clone"
 
-#: ../src/verbs.cpp:2325
+#: ../src/verbs.cpp:2331
 msgid "Cut the selected clones' links to the originals, turning them into standalone objects"
 msgstr "Couper le lien entre le clone sélectionné et son original, le transformant en objet indépendant"
 
-#: ../src/verbs.cpp:2326
+#: ../src/verbs.cpp:2332
 msgid "Relink to Copied"
 msgstr "Relier à la copie"
 
-#: ../src/verbs.cpp:2327
+#: ../src/verbs.cpp:2333
 msgid "Relink the selected clones to the object currently on the clipboard"
 msgstr "Relier les clones sélectionnés à l'objet actuellement placé dans le presse-papier"
 
-#: ../src/verbs.cpp:2328
+#: ../src/verbs.cpp:2334
 msgid "Select _Original"
 msgstr "Sélectionner l'_original"
 
-#: ../src/verbs.cpp:2329
+#: ../src/verbs.cpp:2335
 msgid "Select the object to which the selected clone is linked"
 msgstr "Sélectionner l'objet auquel le clone sélectionné est lié"
 
-#: ../src/verbs.cpp:2330
+#: ../src/verbs.cpp:2336
 msgid "Objects to _Marker"
 msgstr "Objets en _marqueur"
 
-#: ../src/verbs.cpp:2331
+#: ../src/verbs.cpp:2337
 msgid "Convert selection to a line marker"
 msgstr "Transforme la sélection en marqueur de ligne"
 
-#: ../src/verbs.cpp:2332
+#: ../src/verbs.cpp:2338
 msgid "Objects to Gu_ides"
 msgstr "Objets en gu_ides"
 
-#: ../src/verbs.cpp:2333
+#: ../src/verbs.cpp:2339
 msgid "Convert selected objects to a collection of guidelines aligned with their edges"
 msgstr "Convertir les objets sélectionnés en une collection de guides alignés avec leurs bords"
 
-#: ../src/verbs.cpp:2334
+#: ../src/verbs.cpp:2340
 msgid "Objects to Patter_n"
 msgstr "Objets en _motif"
 
-#: ../src/verbs.cpp:2335
+#: ../src/verbs.cpp:2341
 msgid "Convert selection to a rectangle with tiled pattern fill"
 msgstr "Convertir la sélection en rectangle rempli par ce motif"
 
-#: ../src/verbs.cpp:2336
+#: ../src/verbs.cpp:2342
 msgid "Pattern to _Objects"
 msgstr "Motif en _objets"
 
-#: ../src/verbs.cpp:2337
+#: ../src/verbs.cpp:2343
 msgid "Extract objects from a tiled pattern fill"
 msgstr "Extraire des objet(s) d'un motif de remplissage"
 
-#: ../src/verbs.cpp:2338
+#: ../src/verbs.cpp:2344
 msgid "Clea_r All"
 msgstr "Efface_r tout"
 
-#: ../src/verbs.cpp:2339
+#: ../src/verbs.cpp:2345
 msgid "Delete all objects from document"
 msgstr "Supprimer tous les objets du document"
 
-#: ../src/verbs.cpp:2340
+#: ../src/verbs.cpp:2346
 msgid "Select Al_l"
 msgstr "Sélectionner _tout"
 
-#: ../src/verbs.cpp:2341
+#: ../src/verbs.cpp:2347
 msgid "Select all objects or all nodes"
 msgstr "Sélectionner tous les objets ou tous les nœuds"
 
-#: ../src/verbs.cpp:2342
+#: ../src/verbs.cpp:2348
 msgid "Select All in All La_yers"
 msgstr "Tout s_électionner dans tous les calques"
 
-#: ../src/verbs.cpp:2343
+#: ../src/verbs.cpp:2349
 msgid "Select all objects in all visible and unlocked layers"
 msgstr "Sélectionner tous les objets dans tous les calques visibles et non verrouillés"
 
-#: ../src/verbs.cpp:2344
+#: ../src/verbs.cpp:2350
 msgid "In_vert Selection"
 msgstr "In_verser la sélection"
 
-#: ../src/verbs.cpp:2345
+#: ../src/verbs.cpp:2351
 msgid "Invert selection (unselect what is selected and select everything else)"
 msgstr "Inverser la sélection (désélectionner tout ce qui était sélectionné, et sélectionner tout le reste)"
 
-#: ../src/verbs.cpp:2346
+#: ../src/verbs.cpp:2352
 msgid "Invert in All Layers"
 msgstr "Inverser dans tous les calques"
 
-#: ../src/verbs.cpp:2347
+#: ../src/verbs.cpp:2353
 msgid "Invert selection in all visible and unlocked layers"
 msgstr "Inverser la sélection dans tous les calques visibles et non verrouillés"
 
-#: ../src/verbs.cpp:2348
+#: ../src/verbs.cpp:2354
 msgid "Select Next"
 msgstr "Sélectionner suivant"
 
-#: ../src/verbs.cpp:2349
+#: ../src/verbs.cpp:2355
 msgid "Select next object or node"
 msgstr "Sélectionner l'objet ou nœud suivant"
 
-#: ../src/verbs.cpp:2350
+#: ../src/verbs.cpp:2356
 msgid "Select Previous"
 msgstr "Sélectionner précédent"
 
-#: ../src/verbs.cpp:2351
+#: ../src/verbs.cpp:2357
 msgid "Select previous object or node"
 msgstr "Sélectionner l'objet ou nœud précédent"
 
-#: ../src/verbs.cpp:2352
+#: ../src/verbs.cpp:2358
 msgid "D_eselect"
 msgstr "_Désélectionner"
 
-#: ../src/verbs.cpp:2353
+#: ../src/verbs.cpp:2359
 msgid "Deselect any selected objects or nodes"
 msgstr "Désélectionner tous les objets ou nœuds"
 
-#: ../src/verbs.cpp:2354
+#: ../src/verbs.cpp:2360
 msgid "_Guides Around Page"
 msgstr "_Guides autour de la page"
 
-#: ../src/verbs.cpp:2355
+#: ../src/verbs.cpp:2361
 msgid "Create four guides aligned with the page borders"
 msgstr "Crée quatre guides alignés sur les bords de la page"
 
-#: ../src/verbs.cpp:2356
+#: ../src/verbs.cpp:2362
 msgid "Next Path Effect Parameter"
 msgstr "Paramètre suivant"
 
-#: ../src/verbs.cpp:2357
+#: ../src/verbs.cpp:2363
 msgid "Show next Path Effect parameter for editing"
 msgstr "Afficher le paramètre d'effet de chemin suivant pour le modifier"
 
 #. Selection
-#: ../src/verbs.cpp:2360
+#: ../src/verbs.cpp:2366
 msgid "Raise to _Top"
 msgstr "Monter au premier p_lan"
 
-#: ../src/verbs.cpp:2361
+#: ../src/verbs.cpp:2367
 msgid "Raise selection to top"
 msgstr "Monter la sélection au premier plan"
 
-#: ../src/verbs.cpp:2362
+#: ../src/verbs.cpp:2368
 msgid "Lower to _Bottom"
 msgstr "Descendre à l'arrière-pl_an"
 
-#: ../src/verbs.cpp:2363
+#: ../src/verbs.cpp:2369
 msgid "Lower selection to bottom"
 msgstr "Descendre la sélection à l'arrière-plan"
 
-#: ../src/verbs.cpp:2364
+#: ../src/verbs.cpp:2370
 msgid "_Raise"
 msgstr "_Monter"
 
-#: ../src/verbs.cpp:2365
+#: ../src/verbs.cpp:2371
 msgid "Raise selection one step"
 msgstr "Monter la sélection d'un cran"
 
-#: ../src/verbs.cpp:2366
+#: ../src/verbs.cpp:2372
 msgid "_Lower"
 msgstr "D_escendre"
 
-#: ../src/verbs.cpp:2367
+#: ../src/verbs.cpp:2373
 msgid "Lower selection one step"
 msgstr "Descendre la sélection d'un cran"
 
-#: ../src/verbs.cpp:2368
+#: ../src/verbs.cpp:2374
 msgid "_Group"
 msgstr "_Grouper"
 
-#: ../src/verbs.cpp:2369
+#: ../src/verbs.cpp:2375
 msgid "Group selected objects"
 msgstr "Grouper les objets sélectionnés"
 
-#: ../src/verbs.cpp:2371
+#: ../src/verbs.cpp:2377
 msgid "Ungroup selected groups"
 msgstr "Dégrouper les groupes sélectionnés"
 
-#: ../src/verbs.cpp:2373
+#: ../src/verbs.cpp:2379
 msgid "_Put on Path"
 msgstr "Mettre _suivant un chemin"
 
-#: ../src/verbs.cpp:2375
+#: ../src/verbs.cpp:2381
 msgid "_Remove from Path"
 msgstr "_Retirer du chemin"
 
-#: ../src/verbs.cpp:2377
+#: ../src/verbs.cpp:2383
 msgid "Remove Manual _Kerns"
 msgstr "Retirer les crénages _manuels"
 
 #. TRANSLATORS: "glyph": An image used in the visual representation of characters;
 #. roughly speaking, how a character looks. A font is a set of glyphs.
-#: ../src/verbs.cpp:2380
+#: ../src/verbs.cpp:2386
 msgid "Remove all manual kerns and glyph rotations from a text object"
 msgstr "Retirer les crénages manuels et rotations de glyphes d'un texte"
 
-#: ../src/verbs.cpp:2382
+#: ../src/verbs.cpp:2388
 msgid "_Union"
 msgstr "_Union"
 
-#: ../src/verbs.cpp:2383
+#: ../src/verbs.cpp:2389
 msgid "Create union of selected paths"
 msgstr "Créer l'union des chemins sélectionnés"
 
-#: ../src/verbs.cpp:2384
+#: ../src/verbs.cpp:2390
 msgid "_Intersection"
 msgstr "_Intersection"
 
-#: ../src/verbs.cpp:2385
+#: ../src/verbs.cpp:2391
 msgid "Create intersection of selected paths"
 msgstr "Créer l'intersection des chemins sélectionnés"
 
-#: ../src/verbs.cpp:2386
+#: ../src/verbs.cpp:2392
 msgid "_Difference"
 msgstr "_Différence"
 
-#: ../src/verbs.cpp:2387
+#: ../src/verbs.cpp:2393
 msgid "Create difference of selected paths (bottom minus top)"
 msgstr "Créer la différence des chemins sélectionnés (dessous moins dessus)"
 
-#: ../src/verbs.cpp:2388
+#: ../src/verbs.cpp:2394
 msgid "E_xclusion"
 msgstr "E_xclusion"
 
-#: ../src/verbs.cpp:2389
+#: ../src/verbs.cpp:2395
 msgid "Create exclusive OR of selected paths (those parts that belong to only one path)"
 msgstr "Créer un OU exclusif des chemins sélectionnés (seules les parties qui n'appartiennent qu'à un seul chemin)"
 
-#: ../src/verbs.cpp:2390
+#: ../src/verbs.cpp:2396
 msgid "Di_vision"
 msgstr "Di_vision"
 
-#: ../src/verbs.cpp:2391
+#: ../src/verbs.cpp:2397
 msgid "Cut the bottom path into pieces"
 msgstr "Couper le chemin du dessous en morceaux"
 
 #. TRANSLATORS: "to cut a path" is not the same as "to break a path apart" - see the
 #. Advanced tutorial for more info
-#: ../src/verbs.cpp:2394
+#: ../src/verbs.cpp:2400
 msgid "Cut _Path"
 msgstr "Décou_per le chemin"
 
-#: ../src/verbs.cpp:2395
+#: ../src/verbs.cpp:2401
 msgid "Cut the bottom path's stroke into pieces, removing fill"
 msgstr "Couper le contour du chemin du dessous, et supprimer son remplissage"
 
 #. TRANSLATORS: "outset": expand a shape by offsetting the object's path,
 #. i.e. by displacing it perpendicular to the path in each point.
 #. See also the Advanced Tutorial for explanation.
-#: ../src/verbs.cpp:2399
+#: ../src/verbs.cpp:2405
 msgid "Outs_et"
 msgstr "Dil_ater"
 
-#: ../src/verbs.cpp:2400
+#: ../src/verbs.cpp:2406
 msgid "Outset selected paths"
 msgstr "Dilater les chemins sélectionnés"
 
-#: ../src/verbs.cpp:2402
+#: ../src/verbs.cpp:2408
 msgid "O_utset Path by 1 px"
 msgstr "_Dilater le chemin de 1px"
 
-#: ../src/verbs.cpp:2403
+#: ../src/verbs.cpp:2409
 msgid "Outset selected paths by 1 px"
 msgstr "Dilater les chemins sélectionnés de 1px"
 
-#: ../src/verbs.cpp:2405
+#: ../src/verbs.cpp:2411
 msgid "O_utset Path by 10 px"
 msgstr "_Dilater le chemin de 10px"
 
-#: ../src/verbs.cpp:2406
+#: ../src/verbs.cpp:2412
 msgid "Outset selected paths by 10 px"
 msgstr "Dilater les chemins sélectionnés de 10px"
 
 #. TRANSLATORS: "inset": contract a shape by offsetting the object's path,
 #. i.e. by displacing it perpendicular to the path in each point.
 #. See also the Advanced Tutorial for explanation.
-#: ../src/verbs.cpp:2410
+#: ../src/verbs.cpp:2416
 msgid "I_nset"
 msgstr "Co_ntracter"
 
-#: ../src/verbs.cpp:2411
+#: ../src/verbs.cpp:2417
 msgid "Inset selected paths"
 msgstr "Contracter les chemins sélectionnés"
 
-#: ../src/verbs.cpp:2413
+#: ../src/verbs.cpp:2419
 msgid "I_nset Path by 1 px"
 msgstr "Co_ntracter le chemin de 1px"
 
-#: ../src/verbs.cpp:2414
+#: ../src/verbs.cpp:2420
 msgid "Inset selected paths by 1 px"
 msgstr "Contracter les chemins sélectionnés de 1px"
 
-#: ../src/verbs.cpp:2416
+#: ../src/verbs.cpp:2422
 msgid "I_nset Path by 10 px"
 msgstr "Co_ntracter le chemin de 10px"
 
-#: ../src/verbs.cpp:2417
+#: ../src/verbs.cpp:2423
 msgid "Inset selected paths by 10 px"
 msgstr "Contracter les chemins sélectionnés de 10px"
 
-#: ../src/verbs.cpp:2419
+#: ../src/verbs.cpp:2425
 msgid "D_ynamic Offset"
 msgstr "Offset d_ynamique"
 
-#: ../src/verbs.cpp:2419
+#: ../src/verbs.cpp:2425
 msgid "Create a dynamic offset object"
 msgstr "Créer un objet offset dynamique"
 
-#: ../src/verbs.cpp:2421
+#: ../src/verbs.cpp:2427
 msgid "_Linked Offset"
 msgstr "Offset _lié"
 
-#: ../src/verbs.cpp:2422
+#: ../src/verbs.cpp:2428
 msgid "Create a dynamic offset object linked to the original path"
 msgstr "Créer un objet offset dynamique lié au chemin original"
 
-#: ../src/verbs.cpp:2424
+#: ../src/verbs.cpp:2430
 msgid "_Stroke to Path"
 msgstr "_Contour en chemin"
 
-#: ../src/verbs.cpp:2425
+#: ../src/verbs.cpp:2431
 msgid "Convert selected object's stroke to paths"
 msgstr "Convertir les contours des objets sélectionnés en chemins"
 
-#: ../src/verbs.cpp:2426
+#: ../src/verbs.cpp:2432
 msgid "Si_mplify"
 msgstr "Si_mplifier"
 
-#: ../src/verbs.cpp:2427
+#: ../src/verbs.cpp:2433
 msgid "Simplify selected paths (remove extra nodes)"
 msgstr "Simplifier les chemins sélectionnés (supprimer des nœuds superflus)"
 
-#: ../src/verbs.cpp:2428
+#: ../src/verbs.cpp:2434
 msgid "_Reverse"
 msgstr "Invers_er"
 
-#: ../src/verbs.cpp:2429
+#: ../src/verbs.cpp:2435
 msgid "Reverse the direction of selected paths (useful for flipping markers)"
 msgstr "Inverser la direction des chemins sélectionnés (utile pour retourner des marqueurs)"
 
 #. TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
-#: ../src/verbs.cpp:2431
+#: ../src/verbs.cpp:2437
 msgid "_Trace Bitmap..."
 msgstr "Vec_toriser le bitmap..."
 
-#: ../src/verbs.cpp:2432
+#: ../src/verbs.cpp:2438
 msgid "Create one or more paths from a bitmap by tracing it"
 msgstr "Créer un ou plusieurs chemin en vectorisant un bitmap"
 
-#: ../src/verbs.cpp:2433
+#: ../src/verbs.cpp:2439
 msgid "_Make a Bitmap Copy"
 msgstr "Faire une copie bit_map"
 
-#: ../src/verbs.cpp:2434
+#: ../src/verbs.cpp:2440
 msgid "Export selection to a bitmap and insert it into document"
 msgstr "Exporter la sélection en bitmap et insérer celui-ci dans le document"
 
-#: ../src/verbs.cpp:2435
+#: ../src/verbs.cpp:2441
 msgid "_Combine"
 msgstr "Com_biner"
 
-#: ../src/verbs.cpp:2436
+#: ../src/verbs.cpp:2442
 msgid "Combine several paths into one"
 msgstr "Combiner plusieurs chemins en un seul"
 
 #. TRANSLATORS: "to cut a path" is not the same as "to break a path apart" - see the
 #. Advanced tutorial for more info
-#: ../src/verbs.cpp:2439
+#: ../src/verbs.cpp:2445
 msgid "Break _Apart"
 msgstr "Sépa_rer"
 
-#: ../src/verbs.cpp:2440
+#: ../src/verbs.cpp:2446
 msgid "Break selected paths into subpaths"
 msgstr "Séparer les chemins sélectionnés en sous-chemins"
 
-#: ../src/verbs.cpp:2441
+#: ../src/verbs.cpp:2447
 msgid "Rows and Columns..."
 msgstr "Lignes et colonnes..."
 
-#: ../src/verbs.cpp:2442
+#: ../src/verbs.cpp:2448
 msgid "Arrange selected objects in a table"
 msgstr "Arranger les objets sélectionnés dans une grille"
 
 #. Layer
-#: ../src/verbs.cpp:2444
+#: ../src/verbs.cpp:2450
 msgid "_Add Layer..."
 msgstr "_Ajouter un calque..."
 
-#: ../src/verbs.cpp:2445
+#: ../src/verbs.cpp:2451
 msgid "Create a new layer"
 msgstr "Créer un nouveau calque"
 
-#: ../src/verbs.cpp:2446
+#: ../src/verbs.cpp:2452
 msgid "Re_name Layer..."
 msgstr "Re_nommer le calque..."
 
-#: ../src/verbs.cpp:2447
+#: ../src/verbs.cpp:2453
 msgid "Rename the current layer"
 msgstr "Renommer le calque courant"
 
-#: ../src/verbs.cpp:2448
+#: ../src/verbs.cpp:2454
 msgid "Switch to Layer Abov_e"
 msgstr "Passer au calque supéri_eur"
 
-#: ../src/verbs.cpp:2449
+#: ../src/verbs.cpp:2455
 msgid "Switch to the layer above the current"
 msgstr "Passer au calque au-dessus du calque courant"
 
-#: ../src/verbs.cpp:2450
+#: ../src/verbs.cpp:2456
 msgid "Switch to Layer Belo_w"
 msgstr "Passer au calque inférie_ur"
 
-#: ../src/verbs.cpp:2451
+#: ../src/verbs.cpp:2457
 msgid "Switch to the layer below the current"
 msgstr "Passer au calque en-dessous du calque courant"
 
-#: ../src/verbs.cpp:2452
+#: ../src/verbs.cpp:2458
 msgid "Move Selection to Layer Abo_ve"
 msgstr "Déplacer la sélection au calque su_périeur"
 
-#: ../src/verbs.cpp:2453
+#: ../src/verbs.cpp:2459
 msgid "Move selection to the layer above the current"
 msgstr "Déplacer la sélection vers le calque au-dessus du calque courant"
 
-#: ../src/verbs.cpp:2454
+#: ../src/verbs.cpp:2460
 msgid "Move Selection to Layer Bel_ow"
 msgstr "Déplacer la sélection au calque in_férieur"
 
-#: ../src/verbs.cpp:2455
+#: ../src/verbs.cpp:2461
 msgid "Move selection to the layer below the current"
 msgstr "Déplacer la sélection vers le calque en-dessous du calque courant"
 
-#: ../src/verbs.cpp:2456
+#: ../src/verbs.cpp:2462
 msgid "Layer to _Top"
 msgstr "Calque au pre_mier plan"
 
-#: ../src/verbs.cpp:2457
+#: ../src/verbs.cpp:2463
 msgid "Raise the current layer to the top"
 msgstr "Monter le calque courant au premier plan"
 
-#: ../src/verbs.cpp:2458
+#: ../src/verbs.cpp:2464
 msgid "Layer to _Bottom"
 msgstr "Calque à l'a_rrière-plan"
 
-#: ../src/verbs.cpp:2459
+#: ../src/verbs.cpp:2465
 msgid "Lower the current layer to the bottom"
 msgstr "Descendre le calque courant à l'arrière-plan"
 
-#: ../src/verbs.cpp:2460
+#: ../src/verbs.cpp:2466
 msgid "_Raise Layer"
 msgstr "M_onter le calque"
 
-#: ../src/verbs.cpp:2461
+#: ../src/verbs.cpp:2467
 msgid "Raise the current layer"
 msgstr "Monter le calque courant"
 
-#: ../src/verbs.cpp:2462
+#: ../src/verbs.cpp:2468
 msgid "_Lower Layer"
 msgstr "Descen_dre le calque"
 
-#: ../src/verbs.cpp:2463
+#: ../src/verbs.cpp:2469
 msgid "Lower the current layer"
 msgstr "Descendre le calque courant"
 
-#: ../src/verbs.cpp:2464
+#: ../src/verbs.cpp:2470
 msgid "Duplicate Current Layer"
 msgstr "Dupliquer le calque courant"
 
-#: ../src/verbs.cpp:2465
+#: ../src/verbs.cpp:2471
 msgid "Duplicate an existing layer"
 msgstr "Dupliquer un calque existant"
 
-#: ../src/verbs.cpp:2466
+#: ../src/verbs.cpp:2472
 msgid "_Delete Current Layer"
 msgstr "_Supprimer le calque courant"
 
-#: ../src/verbs.cpp:2467
+#: ../src/verbs.cpp:2473
 msgid "Delete the current layer"
 msgstr "Supprimer le calque courant"
 
-#: ../src/verbs.cpp:2468
+#: ../src/verbs.cpp:2474
 msgid "_Show/hide other layers"
 msgstr "Afficher ou masquer les autres calques"
 
-#: ../src/verbs.cpp:2469
+#: ../src/verbs.cpp:2475
 msgid "Solo the current layer"
 msgstr "Afficher le calque courant uniquement"
 
 #. Object
-#: ../src/verbs.cpp:2472
+#: ../src/verbs.cpp:2478
 msgid "Rotate _90&#176; CW"
 msgstr "Tourner de _90&#176; dans le sens horaire"
 
 #. This is shared between tooltips and statusbar, so they
 #. must use UTF-8, not HTML entities for special characters.
-#: ../src/verbs.cpp:2475
+#: ../src/verbs.cpp:2481
 msgid "Rotate selection 90° clockwise"
 msgstr "Tourner la sélection de 90° dans le sens horaire"
 
-#: ../src/verbs.cpp:2476
+#: ../src/verbs.cpp:2482
 msgid "Rotate 9_0&#176; CCW"
 msgstr "Tourner de 9_0&#176; dans le sens anti-horaire"
 
 #. This is shared between tooltips and statusbar, so they
 #. must use UTF-8, not HTML entities for special characters.
-#: ../src/verbs.cpp:2479
+#: ../src/verbs.cpp:2485
 msgid "Rotate selection 90° counter-clockwise"
 msgstr "Tourner la sélection de 90° dans le sens anti-horaire"
 
-#: ../src/verbs.cpp:2480
+#: ../src/verbs.cpp:2486
 msgid "Remove _Transformations"
 msgstr "Retirer les _transformations"
 
-#: ../src/verbs.cpp:2481
+#: ../src/verbs.cpp:2487
 msgid "Remove transformations from object"
 msgstr "retirer les transformations de l'objet"
 
-#: ../src/verbs.cpp:2482
+#: ../src/verbs.cpp:2488
 msgid "_Object to Path"
 msgstr "_Objet en chemin"
 
-#: ../src/verbs.cpp:2483
+#: ../src/verbs.cpp:2489
 msgid "Convert selected object to path"
 msgstr "Convertir les objets sélectionnés en chemins"
 
-#: ../src/verbs.cpp:2484
+#: ../src/verbs.cpp:2490
 msgid "_Flow into Frame"
 msgstr "_Encadrer"
 
-#: ../src/verbs.cpp:2485
+#: ../src/verbs.cpp:2491
 msgid "Put text into a frame (path or shape), creating a flowed text linked to the frame object"
 msgstr "Placer du texte dans un cadre (chemin ou forme), créant un texte encadré lié à l'objet cadre"
 
-#: ../src/verbs.cpp:2486
+#: ../src/verbs.cpp:2492
 msgid "_Unflow"
 msgstr "_Désencadrer"
 
-#: ../src/verbs.cpp:2487
+#: ../src/verbs.cpp:2493
 msgid "Remove text from frame (creates a single-line text object)"
 msgstr "Retirer le texte du cadre (crée un objet texte d'une seule ligne)"
 
-#: ../src/verbs.cpp:2488
+#: ../src/verbs.cpp:2494
 msgid "_Convert to Text"
 msgstr "_Convertir en texte"
 
-#: ../src/verbs.cpp:2489
+#: ../src/verbs.cpp:2495
 msgid "Convert flowed text to regular text object (preserves appearance)"
 msgstr "Convertir du texte encadré en objet texte normal (en préservant l'apparence)"
 
-#: ../src/verbs.cpp:2491
+#: ../src/verbs.cpp:2497
 msgid "Flip _Horizontal"
 msgstr "Retourner _horizontalement"
 
-#: ../src/verbs.cpp:2491
+#: ../src/verbs.cpp:2497
 msgid "Flip selected objects horizontally"
 msgstr "Retourner horizontalement les objets sélectionnés"
 
-#: ../src/verbs.cpp:2494
+#: ../src/verbs.cpp:2500
 msgid "Flip _Vertical"
 msgstr "Retourner _verticalement"
 
-#: ../src/verbs.cpp:2494
+#: ../src/verbs.cpp:2500
 msgid "Flip selected objects vertically"
 msgstr "Retourner verticalement les objets sélectionnés"
 
-#: ../src/verbs.cpp:2497
+#: ../src/verbs.cpp:2503
 msgid "Apply mask to selection (using the topmost object as mask)"
 msgstr "Appliquer un masque à la sélection (en utilisant l'objet le plus au-dessus comme masque)"
 
-#: ../src/verbs.cpp:2499
+#: ../src/verbs.cpp:2505
 msgid "Edit mask"
 msgstr "Modifier le masque"
 
-#: ../src/verbs.cpp:2500
 #: ../src/verbs.cpp:2506
+#: ../src/verbs.cpp:2512
 msgid "_Release"
 msgstr "_Retirer"
 
-#: ../src/verbs.cpp:2501
+#: ../src/verbs.cpp:2507
 msgid "Remove mask from selection"
 msgstr "Retirer le masque de la sélection"
 
-#: ../src/verbs.cpp:2503
+#: ../src/verbs.cpp:2509
 msgid "Apply clipping path to selection (using the topmost object as clipping path)"
 msgstr "Appliquer un chemin de découpe à la sélection (en utilisant l'objet le plus au-dessus comme chemin de découpe)"
 
-#: ../src/verbs.cpp:2505
+#: ../src/verbs.cpp:2511
 #: ../src/widgets/toolbox.cpp:1472
 msgid "Edit clipping path"
 msgstr "Modifier le chemin de découpe"
 
-#: ../src/verbs.cpp:2507
+#: ../src/verbs.cpp:2513
 msgid "Remove clipping path from selection"
 msgstr "Retirer le chemin de découpe de la sélection"
 
 #. Tools
-#: ../src/verbs.cpp:2510
+#: ../src/verbs.cpp:2516
 msgid "Select"
 msgstr "Sélectionner"
 
-#: ../src/verbs.cpp:2511
+#: ../src/verbs.cpp:2517
 msgid "Select and transform objects"
 msgstr "Sélectionner et transformer des objets"
 
-#: ../src/verbs.cpp:2512
+#: ../src/verbs.cpp:2518
 msgid "Node Edit"
 msgstr "Éditer les nœuds"
 
-#: ../src/verbs.cpp:2513
+#: ../src/verbs.cpp:2519
 msgid "Edit paths by nodes"
 msgstr "Éditer les nœuds ou les poignées de contrôle d'un chemin"
 
-#: ../src/verbs.cpp:2515
+#: ../src/verbs.cpp:2521
 msgid "Tweak objects by sculpting or painting"
 msgstr "Ajuster les objets en les sculptant ou en les peignant"
 
-#: ../src/verbs.cpp:2517
+#: ../src/verbs.cpp:2523
 msgid "Spray objects by sculpting or painting"
 msgstr "Pulvériser les objets en les sculptant ou en les peignant"
 
-#: ../src/verbs.cpp:2519
+#: ../src/verbs.cpp:2525
 msgid "Create rectangles and squares"
 msgstr "Créer des rectangles et des carrés"
 
-#: ../src/verbs.cpp:2521
+#: ../src/verbs.cpp:2527
 msgid "Create 3D boxes"
 msgstr "Créer une boîte 3D"
 
-#: ../src/verbs.cpp:2523
+#: ../src/verbs.cpp:2529
 msgid "Create circles, ellipses, and arcs"
 msgstr "Créer des cercles, des ellipses et des arcs"
 
-#: ../src/verbs.cpp:2525
+#: ../src/verbs.cpp:2531
 msgid "Create stars and polygons"
 msgstr "Créer des étoiles et des polygones"
 
-#: ../src/verbs.cpp:2527
+#: ../src/verbs.cpp:2533
 msgid "Create spirals"
 msgstr "Créer des spirales"
 
-#: ../src/verbs.cpp:2529
+#: ../src/verbs.cpp:2535
 msgid "Draw freehand lines"
 msgstr "Dessiner des lignes à main levée"
 
-#: ../src/verbs.cpp:2531
+#: ../src/verbs.cpp:2537
 msgid "Draw Bezier curves and straight lines"
 msgstr "Tracer des courbes de Bézier et des segments de droites"
 
-#: ../src/verbs.cpp:2533
+#: ../src/verbs.cpp:2539
 msgid "Draw calligraphic or brush strokes"
 msgstr "Créer un tracé calligraphique ou au pinceau"
 
-#: ../src/verbs.cpp:2535
+#: ../src/verbs.cpp:2541
 msgid "Create and edit text objects"
 msgstr "Créer et éditer des objets textes"
 
-#: ../src/verbs.cpp:2537
+#: ../src/verbs.cpp:2543
 msgid "Create and edit gradients"
 msgstr "Créer et éditer des dégradés"
 
-#: ../src/verbs.cpp:2539
+#: ../src/verbs.cpp:2545
 msgid "Zoom in or out"
 msgstr "(Dé)zoommer"
 
-#: ../src/verbs.cpp:2541
+#: ../src/verbs.cpp:2547
 msgid "Pick colors from image"
 msgstr "Capturer des couleurs depuis l'image"
 
-#: ../src/verbs.cpp:2543
+#: ../src/verbs.cpp:2549
 msgid "Create diagram connectors"
 msgstr "Créer des connecteurs"
 
-#: ../src/verbs.cpp:2545
+#: ../src/verbs.cpp:2551
 msgid "Fill bounded areas"
 msgstr "Remplir une zone bornée"
 
-#: ../src/verbs.cpp:2546
+#: ../src/verbs.cpp:2552
 msgid "LPE Edit"
 msgstr "Édition des effets de chemin en direct"
 
-#: ../src/verbs.cpp:2547
+#: ../src/verbs.cpp:2553
 msgid "Edit Path Effect parameters"
 msgstr "Modifier les paramètres des effets de chemin"
 
-#: ../src/verbs.cpp:2549
+#: ../src/verbs.cpp:2555
 msgid "Erase existing paths"
 msgstr "Effacer les chemins existants"
 
-#: ../src/verbs.cpp:2551
+#: ../src/verbs.cpp:2557
 msgid "Do geometric constructions"
 msgstr "Réalise des contructions géométriques"
 
 #. Tool prefs
-#: ../src/verbs.cpp:2553
+#: ../src/verbs.cpp:2559
 msgid "Selector Preferences"
 msgstr "Préférences du sélecteur"
 
-#: ../src/verbs.cpp:2554
+#: ../src/verbs.cpp:2560
 msgid "Open Preferences for the Selector tool"
 msgstr "Ouvrir les préférences de l'outil sélecteur"
 
-#: ../src/verbs.cpp:2555
+#: ../src/verbs.cpp:2561
 msgid "Node Tool Preferences"
 msgstr "Préférences des nœuds"
 
-#: ../src/verbs.cpp:2556
+#: ../src/verbs.cpp:2562
 msgid "Open Preferences for the Node tool"
 msgstr "Ouvrir les préférences de l'outil nœud"
 
 # flo: je ne suis pas certain du nom bidouillage, à changer si tu as mieux.
-#: ../src/verbs.cpp:2557
+#: ../src/verbs.cpp:2563
 msgid "Tweak Tool Preferences"
 msgstr "Préférences de l'outil d'ajustement"
 
-#: ../src/verbs.cpp:2558
+#: ../src/verbs.cpp:2564
 msgid "Open Preferences for the Tweak tool"
 msgstr "Ouvrir les préférences de l'outil d'ajustement"
 
-#: ../src/verbs.cpp:2559
+#: ../src/verbs.cpp:2565
 msgid "Spray Tool Preferences"
 msgstr "Préférences de l'outil pulvérisateur"
 
-#: ../src/verbs.cpp:2560
+#: ../src/verbs.cpp:2566
 msgid "Open Preferences for the Spray tool"
 msgstr "Ouvrir les préférences de l'outil pulvérisateur"
 
-#: ../src/verbs.cpp:2561
+#: ../src/verbs.cpp:2567
 msgid "Rectangle Preferences"
 msgstr "Préférences des rectangles"
 
-#: ../src/verbs.cpp:2562
+#: ../src/verbs.cpp:2568
 msgid "Open Preferences for the Rectangle tool"
 msgstr "Ouvrir les préférences de l'outil rectangle"
 
-#: ../src/verbs.cpp:2563
+#: ../src/verbs.cpp:2569
 msgid "3D Box Preferences"
 msgstr "Préférences des boîtes 3D"
 
-#: ../src/verbs.cpp:2564
+#: ../src/verbs.cpp:2570
 msgid "Open Preferences for the 3D Box tool"
 msgstr "Ouvrir les préférences de l'outil boîte 3D"
 
-#: ../src/verbs.cpp:2565
+#: ../src/verbs.cpp:2571
 msgid "Ellipse Preferences"
 msgstr "Préférences des ellipses"
 
-#: ../src/verbs.cpp:2566
+#: ../src/verbs.cpp:2572
 msgid "Open Preferences for the Ellipse tool"
 msgstr "Ouvrir les préférences de l'outil ellipse"
 
-#: ../src/verbs.cpp:2567
+#: ../src/verbs.cpp:2573
 msgid "Star Preferences"
 msgstr "Préférences des étoiles"
 
-#: ../src/verbs.cpp:2568
+#: ../src/verbs.cpp:2574
 msgid "Open Preferences for the Star tool"
 msgstr "Ouvrir les préférences de l'outil étoile"
 
-#: ../src/verbs.cpp:2569
+#: ../src/verbs.cpp:2575
 msgid "Spiral Preferences"
 msgstr "Préférences des spirales"
 
-#: ../src/verbs.cpp:2570
+#: ../src/verbs.cpp:2576
 msgid "Open Preferences for the Spiral tool"
 msgstr "Ouvrir les préférences de l'outil spirale"
 
-#: ../src/verbs.cpp:2571
+#: ../src/verbs.cpp:2577
 msgid "Pencil Preferences"
 msgstr "Préférences du crayon"
 
-#: ../src/verbs.cpp:2572
+#: ../src/verbs.cpp:2578
 msgid "Open Preferences for the Pencil tool"
 msgstr "Ouvrir les préférences de l'outil crayon"
 
-#: ../src/verbs.cpp:2573
+#: ../src/verbs.cpp:2579
 msgid "Pen Preferences"
 msgstr "Préférences du stylo"
 
-#: ../src/verbs.cpp:2574
+#: ../src/verbs.cpp:2580
 msgid "Open Preferences for the Pen tool"
 msgstr "Ouvrir les préférences de l'outil stylo"
 
-#: ../src/verbs.cpp:2575
+#: ../src/verbs.cpp:2581
 msgid "Calligraphic Preferences"
 msgstr "Préférences de la plume calligraphique"
 
-#: ../src/verbs.cpp:2576
+#: ../src/verbs.cpp:2582
 msgid "Open Preferences for the Calligraphy tool"
 msgstr "Ouvrir les préférences de la plume calligraphique"
 
-#: ../src/verbs.cpp:2577
+#: ../src/verbs.cpp:2583
 msgid "Text Preferences"
 msgstr "Préférences des textes"
 
-#: ../src/verbs.cpp:2578
+#: ../src/verbs.cpp:2584
 msgid "Open Preferences for the Text tool"
 msgstr "Ouvrir les préférences de l'outil texte"
 
-#: ../src/verbs.cpp:2579
+#: ../src/verbs.cpp:2585
 msgid "Gradient Preferences"
 msgstr "Préférences des dégradés"
 
-#: ../src/verbs.cpp:2580
+#: ../src/verbs.cpp:2586
 msgid "Open Preferences for the Gradient tool"
 msgstr "Ouvrir les préférences de l'outil de dégradé"
 
-#: ../src/verbs.cpp:2581
+#: ../src/verbs.cpp:2587
 msgid "Zoom Preferences"
 msgstr "Préférences du zoom"
 
-#: ../src/verbs.cpp:2582
+#: ../src/verbs.cpp:2588
 msgid "Open Preferences for the Zoom tool"
 msgstr "Ouvrir les préférences de l'outil zoom"
 
-#: ../src/verbs.cpp:2583
+#: ../src/verbs.cpp:2589
 msgid "Dropper Preferences"
 msgstr "Préférences de la pipette"
 
-#: ../src/verbs.cpp:2584
+#: ../src/verbs.cpp:2590
 msgid "Open Preferences for the Dropper tool"
 msgstr "Ouvrir les préférences de l'outil pipette"
 
-#: ../src/verbs.cpp:2585
+#: ../src/verbs.cpp:2591
 msgid "Connector Preferences"
 msgstr "Préférences des connecteurs"
 
-#: ../src/verbs.cpp:2586
+#: ../src/verbs.cpp:2592
 msgid "Open Preferences for the Connector tool"
 msgstr "Ouvrir les préférences de l'outil connecteur"
 
-#: ../src/verbs.cpp:2587
+#: ../src/verbs.cpp:2593
 msgid "Paint Bucket Preferences"
 msgstr "Préférences de remplissage au seau"
 
-#: ../src/verbs.cpp:2588
+#: ../src/verbs.cpp:2594
 msgid "Open Preferences for the Paint Bucket tool"
 msgstr "Ouvrir les préférences de l'outil de remplissage au seau"
 
-#: ../src/verbs.cpp:2589
+#: ../src/verbs.cpp:2595
 msgid "Eraser Preferences"
 msgstr "Préférences de la gomme"
 
-#: ../src/verbs.cpp:2590
+#: ../src/verbs.cpp:2596
 msgid "Open Preferences for the Eraser tool"
 msgstr "Ouvrir les préférences de l'outil gomme"
 
-#: ../src/verbs.cpp:2591
+#: ../src/verbs.cpp:2597
 msgid "LPE Tool Preferences"
 msgstr "Préférences de l'outil Effets de chemin en direct"
 
-#: ../src/verbs.cpp:2592
+#: ../src/verbs.cpp:2598
 msgid "Open Preferences for the LPETool tool"
 msgstr "Ouvrir les préférences de l'outil Effets de chemin en direct"
 
 #. Zoom/View
-#: ../src/verbs.cpp:2595
+#: ../src/verbs.cpp:2601
 msgid "Zoom In"
 msgstr "Zoommer"
 
-#: ../src/verbs.cpp:2595
+#: ../src/verbs.cpp:2601
 msgid "Zoom in"
 msgstr "Zoommer"
 
-#: ../src/verbs.cpp:2596
+#: ../src/verbs.cpp:2602
 msgid "Zoom Out"
 msgstr "Dézoommer"
 
-#: ../src/verbs.cpp:2596
+#: ../src/verbs.cpp:2602
 msgid "Zoom out"
 msgstr "Dézoommer"
 
-#: ../src/verbs.cpp:2597
+#: ../src/verbs.cpp:2603
 msgid "_Rulers"
 msgstr "_Règles"
 
-#: ../src/verbs.cpp:2597
+#: ../src/verbs.cpp:2603
 msgid "Show or hide the canvas rulers"
 msgstr "Afficher ou non les règles de la zone de travail"
 
-#: ../src/verbs.cpp:2598
+#: ../src/verbs.cpp:2604
 msgid "Scroll_bars"
 msgstr "_Barres de défilement"
 
-#: ../src/verbs.cpp:2598
+#: ../src/verbs.cpp:2604
 msgid "Show or hide the canvas scrollbars"
 msgstr "Afficher ou non les barres de défilement de la zone de travail"
 
-#: ../src/verbs.cpp:2599
+#: ../src/verbs.cpp:2605
 msgid "_Grid"
 msgstr "_Grille"
 
-#: ../src/verbs.cpp:2599
+#: ../src/verbs.cpp:2605
 msgid "Show or hide the grid"
 msgstr "Afficher ou non la grille"
 
-#: ../src/verbs.cpp:2600
+#: ../src/verbs.cpp:2606
 msgid "G_uides"
 msgstr "G_uides"
 
-#: ../src/verbs.cpp:2600
+#: ../src/verbs.cpp:2606
 msgid "Show or hide guides (drag from a ruler to create a guide)"
 msgstr "Afficher ou non les guides (pour créer un guide, effectuer un cliquer-déplacer depuis une règle)"
 
-#: ../src/verbs.cpp:2601
+#: ../src/verbs.cpp:2607
 msgid "Toggle snapping on or off"
 msgstr "Activer ou désactiver le magnétisme"
 
-#: ../src/verbs.cpp:2602
+#: ../src/verbs.cpp:2608
 msgid "Nex_t Zoom"
 msgstr "Zoom suivan_t"
 
-#: ../src/verbs.cpp:2602
+#: ../src/verbs.cpp:2608
 msgid "Next zoom (from the history of zooms)"
 msgstr "Zoom suivant (dans l'historique des zooms)"
 
-#: ../src/verbs.cpp:2604
+#: ../src/verbs.cpp:2610
 msgid "Pre_vious Zoom"
 msgstr "Zoom _précédent"
 
-#: ../src/verbs.cpp:2604
+#: ../src/verbs.cpp:2610
 msgid "Previous zoom (from the history of zooms)"
 msgstr "Zoom précédent (dans l'historique des zooms)"
 
-#: ../src/verbs.cpp:2606
+#: ../src/verbs.cpp:2612
 msgid "Zoom 1:_1"
 msgstr "Zoom 1:_1"
 
-#: ../src/verbs.cpp:2606
+#: ../src/verbs.cpp:2612
 msgid "Zoom to 1:1"
 msgstr "Zoommer à 1:1"
 
-#: ../src/verbs.cpp:2608
+#: ../src/verbs.cpp:2614
 msgid "Zoom 1:_2"
 msgstr "Zoom 1:_2"
 
-#: ../src/verbs.cpp:2608
+#: ../src/verbs.cpp:2614
 msgid "Zoom to 1:2"
 msgstr "Zoommer à 1:2"
 
-#: ../src/verbs.cpp:2610
+#: ../src/verbs.cpp:2616
 msgid "_Zoom 2:1"
 msgstr "_Zoom 2:1"
 
-#: ../src/verbs.cpp:2610
+#: ../src/verbs.cpp:2616
 msgid "Zoom to 2:1"
 msgstr "Zoommer à 2:1"
 
-#: ../src/verbs.cpp:2613
+#: ../src/verbs.cpp:2619
 msgid "_Fullscreen"
 msgstr "Plein _écran"
 
-#: ../src/verbs.cpp:2613
+#: ../src/verbs.cpp:2619
 msgid "Stretch this document window to full screen"
 msgstr "Afficher cette fenêtre (document) en plein écran"
 
-#: ../src/verbs.cpp:2616
+#: ../src/verbs.cpp:2622
 msgid "Toggle _Focus Mode"
 msgstr "Inverser le mode de _focus"
 
-#: ../src/verbs.cpp:2616
+#: ../src/verbs.cpp:2622
 msgid "Remove excess toolbars to focus on drawing"
 msgstr "Supprime les barres superflues pour se concentrer sur le dessin"
 
-#: ../src/verbs.cpp:2618
+#: ../src/verbs.cpp:2624
 msgid "Duplic_ate Window"
 msgstr "Dupliquer la _fenêtre"
 
-#: ../src/verbs.cpp:2618
+#: ../src/verbs.cpp:2624
 msgid "Open a new window with the same document"
 msgstr "Ouvrir une nouvelle fenêtre avec le même document"
 
-#: ../src/verbs.cpp:2620
+#: ../src/verbs.cpp:2626
 msgid "_New View Preview"
 msgstr "_Nouvel aperçu"
 
-#: ../src/verbs.cpp:2621
+#: ../src/verbs.cpp:2627
 msgid "New View Preview"
 msgstr "Nouvel aperçu"
 
 #. "view_new_preview"
-#: ../src/verbs.cpp:2623
+#: ../src/verbs.cpp:2629
 msgid "_Normal"
 msgstr "_Normal"
 
-#: ../src/verbs.cpp:2624
+#: ../src/verbs.cpp:2630
 msgid "Switch to normal display mode"
 msgstr "Passer en mode d'affichage normal"
 
-#: ../src/verbs.cpp:2625
+#: ../src/verbs.cpp:2631
 msgid "No _Filters"
 msgstr "Sans _filtre"
 
-#: ../src/verbs.cpp:2626
+#: ../src/verbs.cpp:2632
 msgid "Switch to normal display without filters"
 msgstr "Passer en mode d'affichage normal, sans filtre"
 
-#: ../src/verbs.cpp:2627
+#: ../src/verbs.cpp:2633
 msgid "_Outline"
 msgstr "_Contour"
 
-#: ../src/verbs.cpp:2628
+#: ../src/verbs.cpp:2634
 msgid "Switch to outline (wireframe) display mode"
 msgstr "Passer en mode d'affichage contour (fil de fer)"
 
-#: ../src/verbs.cpp:2629
+#: ../src/verbs.cpp:2635
+msgid "_Print Colors Preview"
+msgstr "A_perçu des couleurs d'impression"
+
+#: ../src/verbs.cpp:2636
+msgid "Switch to print colors preview mode"
+msgstr "Passer en mode aperçu des couleurs d'impression"
+
+#: ../src/verbs.cpp:2637
 msgid "_Toggle"
 msgstr "Al_terner"
 
-#: ../src/verbs.cpp:2630
+#: ../src/verbs.cpp:2638
 msgid "Toggle between normal and outline display modes"
 msgstr "Alterner entre les modes d'affichage normal et contour"
 
-#: ../src/verbs.cpp:2632
+#: ../src/verbs.cpp:2640
 msgid "Color-managed view"
 msgstr "Affichage avec gestion des couleurs"
 
-#: ../src/verbs.cpp:2633
+#: ../src/verbs.cpp:2641
 msgid "Toggle color-managed display for this document window"
 msgstr "Alterner entre le mode d'affichage avec gestion des couleurs et le mode normal pour cette fenêtre de document"
 
-#: ../src/verbs.cpp:2635
+#: ../src/verbs.cpp:2643
 msgid "Ico_n Preview..."
 msgstr "Aperçu d'_icône..."
 
-#: ../src/verbs.cpp:2636
+#: ../src/verbs.cpp:2644
 msgid "Open a window to preview objects at different icon resolutions"
 msgstr "Ouvrir une fenêtre d'aperçu des objets en icônes à différentes résolutions"
 
-#: ../src/verbs.cpp:2638
+#: ../src/verbs.cpp:2646
 msgid "Zoom to fit page in window"
 msgstr "Ajuster la page à la fenêtre"
 
-#: ../src/verbs.cpp:2639
+#: ../src/verbs.cpp:2647
 msgid "Page _Width"
 msgstr "_Largeur de la page"
 
-#: ../src/verbs.cpp:2640
+#: ../src/verbs.cpp:2648
 msgid "Zoom to fit page width in window"
 msgstr "Zoomer pour ajuster la largeur de la page à la fenêtre"
 
-#: ../src/verbs.cpp:2642
+#: ../src/verbs.cpp:2650
 msgid "Zoom to fit drawing in window"
 msgstr "Zoomer pour ajuster le dessin à la fenêtre"
 
-#: ../src/verbs.cpp:2644
+#: ../src/verbs.cpp:2652
 msgid "Zoom to fit selection in window"
 msgstr "Zoomer pour ajuster la sélection à la fenêtre"
 
 #. Dialogs
-#: ../src/verbs.cpp:2647
+#: ../src/verbs.cpp:2655
 msgid "In_kscape Preferences..."
 msgstr "Préférences d'In_kscape..."
 
-#: ../src/verbs.cpp:2648
+#: ../src/verbs.cpp:2656
 msgid "Edit global Inkscape preferences"
 msgstr "Éditer les préférences globales d'Inkscape"
 
-#: ../src/verbs.cpp:2649
+#: ../src/verbs.cpp:2657
 msgid "_Document Properties..."
 msgstr "Propriétés du do_cument..."
 
-#: ../src/verbs.cpp:2650
+#: ../src/verbs.cpp:2658
 msgid "Edit properties of this document (to be saved with the document)"
 msgstr "Éditer les préférences du document (enregistrées avec celui-ci)"
 
-#: ../src/verbs.cpp:2651
+#: ../src/verbs.cpp:2659
 msgid "Document _Metadata..."
 msgstr "_Métadonnées du document..."
 
-#: ../src/verbs.cpp:2652
+#: ../src/verbs.cpp:2660
 msgid "Edit document metadata (to be saved with the document)"
 msgstr "Éditer les métadonnées du document (enregistrées avec celui-ci)"
 
-#: ../src/verbs.cpp:2653
+#: ../src/verbs.cpp:2661
 msgid "_Fill and Stroke..."
 msgstr "_Remplissage et contour..."
 
-#: ../src/verbs.cpp:2654
+#: ../src/verbs.cpp:2662
 msgid "Edit objects' colors, gradients, stroke width, arrowheads, dash patterns..."
 msgstr "Éditer les couleurs de l'objet, ses dégradés, l'épaisseur de son contour, les têtes de flèches, les pointillés..."
 
 #. TRANSLATORS: "Swatches" means: color samples
-#: ../src/verbs.cpp:2656
+#: ../src/verbs.cpp:2664
 msgid "S_watches..."
 msgstr "_Palettes..."
 
-#: ../src/verbs.cpp:2657
+#: ../src/verbs.cpp:2665
 msgid "Select colors from a swatches palette"
 msgstr "Sélectionner des couleurs depuis une palette"
 
-#: ../src/verbs.cpp:2658
+#: ../src/verbs.cpp:2666
 msgid "Transfor_m..."
 msgstr "_Transformer..."
 
-#: ../src/verbs.cpp:2659
+#: ../src/verbs.cpp:2667
 msgid "Precisely control objects' transformations"
 msgstr "Contrôler précisément les transformations d'objets"
 
-#: ../src/verbs.cpp:2660
+#: ../src/verbs.cpp:2668
 msgid "_Align and Distribute..."
 msgstr "Aligner et distri_buer..."
 
-#: ../src/verbs.cpp:2661
+#: ../src/verbs.cpp:2669
 msgid "Align and distribute objects"
 msgstr "Aligner et distribuer des objets"
 
-#: ../src/verbs.cpp:2662
+#: ../src/verbs.cpp:2670
 msgid "_Spray options..."
 msgstr "Options du pulvéri_sateur..."
 
-#: ../src/verbs.cpp:2663
+#: ../src/verbs.cpp:2671
 msgid "Some options for the spray"
 msgstr "Options pour le pulvérisateur"
 
-#: ../src/verbs.cpp:2664
+#: ../src/verbs.cpp:2672
 msgid "Undo _History..."
 msgstr "_Historique des annulations"
 
-#: ../src/verbs.cpp:2665
+#: ../src/verbs.cpp:2673
 msgid "Undo History"
 msgstr "Historique des annulations"
 
-#: ../src/verbs.cpp:2666
+#: ../src/verbs.cpp:2674
 msgid "_Text and Font..."
 msgstr "_Texte et police..."
 
-#: ../src/verbs.cpp:2667
+#: ../src/verbs.cpp:2675
 msgid "View and select font family, font size and other text properties"
 msgstr "Voir et sélectionner une police, une taille de police et autres propriétés de texte"
 
-#: ../src/verbs.cpp:2668
+#: ../src/verbs.cpp:2676
 msgid "_XML Editor..."
 msgstr "Éditeur _XML..."
 
-#: ../src/verbs.cpp:2669
+#: ../src/verbs.cpp:2677
 msgid "View and edit the XML tree of the document"
 msgstr "Voir et éditer l'arbre XML du document"
 
-#: ../src/verbs.cpp:2670
+#: ../src/verbs.cpp:2678
 msgid "_Find..."
 msgstr "_Rechercher..."
 
-#: ../src/verbs.cpp:2671
+#: ../src/verbs.cpp:2679
 msgid "Find objects in document"
 msgstr "Rechercher des objets dans le document"
 
-#: ../src/verbs.cpp:2672
+#: ../src/verbs.cpp:2680
 msgid "Find and _Replace Text..."
 msgstr "Trouver et _remplacer le texte..."
 
-#: ../src/verbs.cpp:2673
+#: ../src/verbs.cpp:2681
 msgid "Find and replace text in document"
 msgstr "Rechercher et remplacer du texte dans le document"
 
-#: ../src/verbs.cpp:2674
+#: ../src/verbs.cpp:2682
 msgid "Check Spellin_g..."
 msgstr "Vérification ortho_graphique..."
 
-#: ../src/verbs.cpp:2675
+#: ../src/verbs.cpp:2683
 msgid "Check spelling of text in document"
 msgstr "Vérifier l'orthographe des texte du document"
 
-#: ../src/verbs.cpp:2676
+#: ../src/verbs.cpp:2684
 msgid "_Messages..."
 msgstr "_Messages..."
 
-#: ../src/verbs.cpp:2677
+#: ../src/verbs.cpp:2685
 msgid "View debug messages"
 msgstr "Voir les messages de débuggage"
 
-#: ../src/verbs.cpp:2678
+#: ../src/verbs.cpp:2686
 msgid "S_cripts..."
 msgstr "S_cripts..."
 
-#: ../src/verbs.cpp:2679
+#: ../src/verbs.cpp:2687
 msgid "Run scripts"
 msgstr "Exécuter des scripts"
 
-#: ../src/verbs.cpp:2680
+#: ../src/verbs.cpp:2688
 msgid "Show/Hide D_ialogs"
 msgstr "Afficher/cacher les boîtes de d_ialogue"
 
-#: ../src/verbs.cpp:2681
+#: ../src/verbs.cpp:2689
 msgid "Show or hide all open dialogs"
 msgstr "Afficher ou non les dialogues ouverts"
 
-#: ../src/verbs.cpp:2682
+#: ../src/verbs.cpp:2690
 msgid "Create Tiled Clones..."
 msgstr "Créer un pavage avec des clones..."
 
-#: ../src/verbs.cpp:2683
+#: ../src/verbs.cpp:2691
 msgid "Create multiple clones of selected object, arranging them into a pattern or scattering"
 msgstr "Créer des clones multiple d'un objet, et les arranger selon un motif ou les disperser"
 
-#: ../src/verbs.cpp:2684
+#: ../src/verbs.cpp:2692
 msgid "_Object Properties..."
 msgstr "Propriétés de l'_objet..."
 
-#: ../src/verbs.cpp:2685
+#: ../src/verbs.cpp:2693
 msgid "Edit the ID, locked and visible status, and other object properties"
 msgstr "Editer l'Id, les statuts de visibilité et de verrouillage et autres propriétés des objets"
 
@@ -17236,204 +17276,212 @@ msgstr "Editer l'Id, les statuts de visibilité et de verrouillage et autres pro
 #. new DialogVerb(SP_VERB_XMPP_CLIENT, "DialogXmppClient",
 #. N_("_Instant Messaging..."), N_("Jabber Instant Messaging Client"), NULL),
 #. #endif
-#: ../src/verbs.cpp:2690
+#: ../src/verbs.cpp:2698
 msgid "_Input Devices..."
 msgstr "Périp_hériques de saisie..."
 
-#: ../src/verbs.cpp:2691
-#: ../src/verbs.cpp:2693
+#: ../src/verbs.cpp:2699
+#: ../src/verbs.cpp:2701
 msgid "Configure extended input devices, such as a graphics tablet"
 msgstr "Configurer les périphériques de saisie étendus, comme une tablette graphique"
 
-#: ../src/verbs.cpp:2692
+#: ../src/verbs.cpp:2700
 msgid "_Input Devices (new)..."
 msgstr "Périphériques de saisie... (nouveau)"
 
-#: ../src/verbs.cpp:2694
+#: ../src/verbs.cpp:2702
 msgid "_Extensions..."
 msgstr "_Extensions..."
 
-#: ../src/verbs.cpp:2695
+#: ../src/verbs.cpp:2703
 msgid "Query information about extensions"
 msgstr "Demander des informations à propos des extensions"
 
-#: ../src/verbs.cpp:2696
+#: ../src/verbs.cpp:2704
 msgid "Layer_s..."
 msgstr "_Calques..."
 
-#: ../src/verbs.cpp:2697
+#: ../src/verbs.cpp:2705
 msgid "View Layers"
 msgstr "Afficher les calques"
 
-#: ../src/verbs.cpp:2698
+#: ../src/verbs.cpp:2706
 msgid "Path Effect Editor..."
 msgstr "Éditeur d'effets de chemin..."
 
-#: ../src/verbs.cpp:2699
+#: ../src/verbs.cpp:2707
 msgid "Manage, edit, and apply path effects"
 msgstr "Créer, modifier et appliquer des effets de chemin"
 
-#: ../src/verbs.cpp:2700
+#: ../src/verbs.cpp:2708
 msgid "Filter Editor..."
 msgstr "Éditeur de filtres..."
 
-#: ../src/verbs.cpp:2701
+#: ../src/verbs.cpp:2709
 msgid "Manage, edit, and apply SVG filters"
 msgstr "Gérer, modifier et appliquer des filtres SVG"
 
-#: ../src/verbs.cpp:2702
+#: ../src/verbs.cpp:2710
 msgid "SVG Font Editor..."
 msgstr "Éditeur de fontes SVG..."
 
-#: ../src/verbs.cpp:2703
+#: ../src/verbs.cpp:2711
 msgid "Edit SVG fonts"
 msgstr "Éditer les fontes SVG"
 
+#: ../src/verbs.cpp:2712
+msgid "Print Colors..."
+msgstr "Imprimer les couleurs..."
+
+#: ../src/verbs.cpp:2713
+msgid "Select which color separations to render in Print Colors Preview rendermode"
+msgstr "Sélectionner quelles séparations de couleur afficher en mode aperçu des couleurs d'impression"
+
 #. Help
-#: ../src/verbs.cpp:2706
+#: ../src/verbs.cpp:2716
 msgid "About E_xtensions"
 msgstr "À propos des e_xtensions"
 
-#: ../src/verbs.cpp:2707
+#: ../src/verbs.cpp:2717
 msgid "Information on Inkscape extensions"
 msgstr "Information sur les extensions d'Inkscape"
 
-#: ../src/verbs.cpp:2708
+#: ../src/verbs.cpp:2718
 msgid "About _Memory"
 msgstr "Gestion _mémoire"
 
-#: ../src/verbs.cpp:2709
+#: ../src/verbs.cpp:2719
 msgid "Memory usage information"
 msgstr "Information sur l'utilisation de la mémoire"
 
-#: ../src/verbs.cpp:2710
+#: ../src/verbs.cpp:2720
 msgid "_About Inkscape"
 msgstr "À _propos d'Inkscape"
 
-#: ../src/verbs.cpp:2711
+#: ../src/verbs.cpp:2721
 msgid "Inkscape version, authors, license"
 msgstr "Version, auteurs et licence d'Inkscape"
 
 #. new HelpVerb(SP_VERB_SHOW_LICENSE, "ShowLicense", N_("_License"),
 #. N_("Distribution terms"), /*"show_license"*/"inkscape_options"),
 #. Tutorials
-#: ../src/verbs.cpp:2716
+#: ../src/verbs.cpp:2726
 msgid "Inkscape: _Basic"
 msgstr "Inkscape : _basique"
 
-#: ../src/verbs.cpp:2717
+#: ../src/verbs.cpp:2727
 msgid "Getting started with Inkscape"
 msgstr "Premiers pas avec Inkscape"
 
 #. "tutorial_basic"
-#: ../src/verbs.cpp:2718
+#: ../src/verbs.cpp:2728
 msgid "Inkscape: _Shapes"
 msgstr "Inkscape : _formes"
 
-#: ../src/verbs.cpp:2719
+#: ../src/verbs.cpp:2729
 msgid "Using shape tools to create and edit shapes"
 msgstr "Utilisation des outils de formes pour créer et éditer des formes"
 
-#: ../src/verbs.cpp:2720
+#: ../src/verbs.cpp:2730
 msgid "Inkscape: _Advanced"
 msgstr "Inkscape : _avancé"
 
-#: ../src/verbs.cpp:2721
+#: ../src/verbs.cpp:2731
 msgid "Advanced Inkscape topics"
 msgstr "Sujets avancés d'Inkscape"
 
 #. "tutorial_advanced"
 #. TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
-#: ../src/verbs.cpp:2723
+#: ../src/verbs.cpp:2733
 msgid "Inkscape: T_racing"
 msgstr "Inkscape : _vectorisation"
 
-#: ../src/verbs.cpp:2724
+#: ../src/verbs.cpp:2734
 msgid "Using bitmap tracing"
 msgstr "Vectorisation de bitmap"
 
 #. "tutorial_tracing"
-#: ../src/verbs.cpp:2725
+#: ../src/verbs.cpp:2735
 msgid "Inkscape: _Calligraphy"
 msgstr "Inkscape : _calligraphie"
 
-#: ../src/verbs.cpp:2726
+#: ../src/verbs.cpp:2736
 msgid "Using the Calligraphy pen tool"
 msgstr "Utilisation de la plume calligraphique d'Inkscape"
 
-#: ../src/verbs.cpp:2727
+#: ../src/verbs.cpp:2737
 msgid "_Elements of Design"
 msgstr "Rudiments de _design"
 
-#: ../src/verbs.cpp:2728
+#: ../src/verbs.cpp:2738
 msgid "Principles of design in the tutorial form"
 msgstr "Rudiments de design sous forme de didacticiel"
 
 #. "tutorial_design"
-#: ../src/verbs.cpp:2729
+#: ../src/verbs.cpp:2739
 msgid "_Tips and Tricks"
 msgstr "_Trucs et astuces"
 
-#: ../src/verbs.cpp:2730
+#: ../src/verbs.cpp:2740
 msgid "Miscellaneous tips and tricks"
 msgstr "Divers trucs et astuces"
 
 #. "tutorial_tips"
 #. Effect -- renamed Extension
-#: ../src/verbs.cpp:2733
+#: ../src/verbs.cpp:2743
 msgid "Previous Extension"
 msgstr "Extension précédente"
 
-#: ../src/verbs.cpp:2734
+#: ../src/verbs.cpp:2744
 msgid "Repeat the last extension with the same settings"
 msgstr "Répéter la dernière extension avec les mêmes paramètres"
 
-#: ../src/verbs.cpp:2735
+#: ../src/verbs.cpp:2745
 msgid "Previous Extension Settings..."
 msgstr "Paramètres de l'extension précédente..."
 
-#: ../src/verbs.cpp:2736
+#: ../src/verbs.cpp:2746
 msgid "Repeat the last extension with new settings"
 msgstr "Répéter la dernière extension avec les nouveaux paramètres"
 
-#: ../src/verbs.cpp:2740
+#: ../src/verbs.cpp:2750
 msgid "Fit the page to the current selection"
 msgstr "Ajuster la page à la sélection courante"
 
-#: ../src/verbs.cpp:2742
+#: ../src/verbs.cpp:2752
 msgid "Fit the page to the drawing"
 msgstr "Ajuster la page au dessin"
 
-#: ../src/verbs.cpp:2744
+#: ../src/verbs.cpp:2754
 msgid "Fit the page to the current selection or the drawing if there is no selection"
 msgstr "Ajuster la page à la sélection courante ou au dessin s'il n'y a pas de sélection"
 
 #. LockAndHide
-#: ../src/verbs.cpp:2746
+#: ../src/verbs.cpp:2756
 msgid "Unlock All"
 msgstr "Déverrouiller tout"
 
-#: ../src/verbs.cpp:2748
+#: ../src/verbs.cpp:2758
 msgid "Unlock All in All Layers"
 msgstr "Tout déverouiller dans tous les calques"
 
-#: ../src/verbs.cpp:2750
+#: ../src/verbs.cpp:2760
 msgid "Unhide All"
 msgstr "Montrer tout"
 
-#: ../src/verbs.cpp:2752
+#: ../src/verbs.cpp:2762
 msgid "Unhide All in All Layers"
 msgstr "Tout montrer dans tous les calques"
 
-#: ../src/verbs.cpp:2756
+#: ../src/verbs.cpp:2766
 msgid "Link an ICC color profile"
 msgstr "Lier un profil de couleur ICC"
 
-#: ../src/verbs.cpp:2757
+#: ../src/verbs.cpp:2767
 msgid "Remove Color Profile"
 msgstr "Supprimer le profil de couleur"
 
-#: ../src/verbs.cpp:2758
+#: ../src/verbs.cpp:2768
 msgid "Remove a linked ICC color profile"
 msgstr "Supprimer un profil de couleur ICC lié"
 
@@ -17457,15 +17505,35 @@ msgstr "%s: %d (contour) - Inkscape"
 
 #: ../src/widgets/desktop-widget.cpp:617
 #, c-format
+msgid "%s: %d (no filters) - Inkscape"
+msgstr "%s: %d (aucun filtre) - Inkscape"
+
+#: ../src/widgets/desktop-widget.cpp:619
+#, c-format
+msgid "%s: %d (print colors preview) - Inkscape"
+msgstr "%s: %d (aperçu des couleurs d'impression) - Inkscape"
+
+#: ../src/widgets/desktop-widget.cpp:621
+#, c-format
 msgid "%s: %d - Inkscape"
 msgstr "%s: %d - Inkscape"
 
-#: ../src/widgets/desktop-widget.cpp:621
+#: ../src/widgets/desktop-widget.cpp:625
 #, c-format
 msgid "%s (outline) - Inkscape"
 msgstr "%s (contour) - Inkscape"
 
-#: ../src/widgets/desktop-widget.cpp:623
+#: ../src/widgets/desktop-widget.cpp:627
+#, c-format
+msgid "%s (no filters) - Inkscape"
+msgstr "%s (aucun filtre) - Inkscape"
+
+#: ../src/widgets/desktop-widget.cpp:629
+#, c-format
+msgid "%s (print colors preview) - Inkscape"
+msgstr "%s (aperçu des couleurs d'impression) - Inkscape"
+
+#: ../src/widgets/desktop-widget.cpp:631
 #, c-format
 msgid "%s - Inkscape"
 msgstr "%s - Inkscape"
@@ -17569,10 +17637,10 @@ msgstr "Éditer les stops du dégradé"
 #: ../src/widgets/toolbox.cpp:2735
 #: ../src/widgets/toolbox.cpp:3066
 #: ../src/widgets/toolbox.cpp:3104
-#: ../src/widgets/toolbox.cpp:3719
-#: ../src/widgets/toolbox.cpp:3743
-#: ../src/widgets/toolbox.cpp:5349
-#: ../src/widgets/toolbox.cpp:5378
+#: ../src/widgets/toolbox.cpp:3722
+#: ../src/widgets/toolbox.cpp:3746
+#: ../src/widgets/toolbox.cpp:5352
+#: ../src/widgets/toolbox.cpp:5381
 msgid "<b>New:</b>"
 msgstr "<b>Créer :</b>"
 
@@ -17603,10 +17671,10 @@ msgstr "Appliquer le dégradé au contour"
 #: ../src/widgets/toolbox.cpp:2659
 #: ../src/widgets/toolbox.cpp:3074
 #: ../src/widgets/toolbox.cpp:3092
-#: ../src/widgets/toolbox.cpp:3721
-#: ../src/widgets/toolbox.cpp:3732
-#: ../src/widgets/toolbox.cpp:5352
-#: ../src/widgets/toolbox.cpp:5363
+#: ../src/widgets/toolbox.cpp:3724
+#: ../src/widgets/toolbox.cpp:3735
+#: ../src/widgets/toolbox.cpp:5355
+#: ../src/widgets/toolbox.cpp:5366
 msgid "<b>Change:</b>"
 msgstr "<b>Modifier :</b>"
 
@@ -17917,27 +17985,6 @@ msgstr "_N"
 msgid "Gray"
 msgstr "Niveaux de gris"
 
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:466
-#: ../src/widgets/sp-color-scales.cpp:467
-msgid "Cyan"
-msgstr "Cyan"
-
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:469
-#: ../src/widgets/sp-color-scales.cpp:470
-msgid "Magenta"
-msgstr "Magenta"
-
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:472
-#: ../src/widgets/sp-color-scales.cpp:473
-msgid "Yellow"
-msgstr "Jaune"
-
 #: ../src/widgets/sp-color-icc-selector.cpp:296
 msgid "Fix"
 msgstr "Fixer"
@@ -18639,14 +18686,14 @@ msgid "Scatter randomly the corners and angles"
 msgstr "Disperser aléatoirement les sommets et les angles"
 
 #: ../src/widgets/toolbox.cpp:2855
-#: ../src/widgets/toolbox.cpp:3794
-#: ../src/widgets/toolbox.cpp:4054
-#: ../src/widgets/toolbox.cpp:7681
+#: ../src/widgets/toolbox.cpp:3797
+#: ../src/widgets/toolbox.cpp:4055
+#: ../src/widgets/toolbox.cpp:7761
 msgid "Defaults"
 msgstr "R-à-z"
 
 #: ../src/widgets/toolbox.cpp:2856
-#: ../src/widgets/toolbox.cpp:3795
+#: ../src/widgets/toolbox.cpp:3798
 msgid "Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"
 msgstr "Restaurer les préférences de la forme par défaut (changez les valeurs par défaut dans Inkscape Préférences > Outils)"
 
@@ -18709,1145 +18756,1145 @@ msgstr "Rendre les coins pointus"
 
 # ligne d'horizon ?
 #. TODO: use the correct axis here, too
-#: ../src/widgets/toolbox.cpp:3379
+#: ../src/widgets/toolbox.cpp:3382
 msgid "3D Box: Change perspective (angle of infinite axis)"
 msgstr "Boîte 3D: changer la perspective (angle de ligne d'horizon)"
 
-#: ../src/widgets/toolbox.cpp:3449
+#: ../src/widgets/toolbox.cpp:3452
 msgid "Angle in X direction"
 msgstr "Angle dans la direction X"
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3451
+#: ../src/widgets/toolbox.cpp:3454
 msgid "Angle of PLs in X direction"
 msgstr "Angle des lignes parallèles dans la direction X"
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3473
+#: ../src/widgets/toolbox.cpp:3476
 msgid "State of VP in X direction"
 msgstr "État du point de fuite dans la direction X"
 
-#: ../src/widgets/toolbox.cpp:3474
+#: ../src/widgets/toolbox.cpp:3477
 msgid "Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"
 msgstr "Alterner le point de fuite dans la direction X entre « fini » et « infini » (=parallèles)"
 
-#: ../src/widgets/toolbox.cpp:3489
+#: ../src/widgets/toolbox.cpp:3492
 msgid "Angle in Y direction"
 msgstr "Angle dans la direction Y"
 
-#: ../src/widgets/toolbox.cpp:3489
+#: ../src/widgets/toolbox.cpp:3492
 msgid "Angle Y:"
 msgstr "Angle Y :"
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3491
+#: ../src/widgets/toolbox.cpp:3494
 msgid "Angle of PLs in Y direction"
 msgstr "Angle des lignes parallèles dans la direction Y"
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3512
+#: ../src/widgets/toolbox.cpp:3515
 msgid "State of VP in Y direction"
 msgstr "État du point de fuite dans la direction Y"
 
-#: ../src/widgets/toolbox.cpp:3513
+#: ../src/widgets/toolbox.cpp:3516
 msgid "Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"
 msgstr "Alterner le point de fuite dans la direction Y entre « fini » et « infini » (=parallèles)"
 
-#: ../src/widgets/toolbox.cpp:3528
+#: ../src/widgets/toolbox.cpp:3531
 msgid "Angle in Z direction"
 msgstr "Angle dans la direction Z"
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3530
+#: ../src/widgets/toolbox.cpp:3533
 msgid "Angle of PLs in Z direction"
 msgstr "Angle des lignes parallèles dans la direction Z"
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3551
+#: ../src/widgets/toolbox.cpp:3554
 msgid "State of VP in Z direction"
 msgstr "État du point de fuite dans la direction Z"
 
-#: ../src/widgets/toolbox.cpp:3552
+#: ../src/widgets/toolbox.cpp:3555
 msgid "Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"
 msgstr "Alterner le point de fuite dans la direction Z entre « fini » et « infini » (=parallèles)"
 
-#: ../src/widgets/toolbox.cpp:3610
+#: ../src/widgets/toolbox.cpp:3613
 msgid "Change spiral"
 msgstr "Modifier une spirale"
 
-#: ../src/widgets/toolbox.cpp:3751
+#: ../src/widgets/toolbox.cpp:3754
 msgid "just a curve"
 msgstr "juste une courbe"
 
-#: ../src/widgets/toolbox.cpp:3751
+#: ../src/widgets/toolbox.cpp:3754
 msgid "one full revolution"
 msgstr "une révolution complète"
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Number of turns"
 msgstr "Nombre de tours"
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Turns:"
 msgstr "Tours :"
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Number of revolutions"
 msgstr "Nombre de révolutions"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "circle"
 msgstr "cercle"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "edge is much denser"
 msgstr "le bord est beaucoup plus dense"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "edge is denser"
 msgstr "le bord est plus dense"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "even"
 msgstr "égal"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "center is denser"
 msgstr "le centre est plus dense"
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "center is much denser"
 msgstr "le centre est beaucoup plus dense"
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "Divergence"
 msgstr "Divergence :"
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "Divergence:"
 msgstr "Divergence :"
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "How much denser/sparser are outer revolutions; 1 = uniform"
 msgstr "Densité de la révolution; 1 = uniforme"
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts from center"
 msgstr "démarrer du centre"
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts mid-way"
 msgstr "démarrer du milieu"
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts near edge"
 msgstr "démarrer près du bord"
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Inner radius"
 msgstr "Rayon intérieur :"
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Inner radius:"
 msgstr "Rayon intérieur :"
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Radius of the innermost revolution (relative to the spiral size)"
 msgstr "Rayon de la révolution intérieure (relatif aux dimensions de la spirale)"
 
-#: ../src/widgets/toolbox.cpp:3855
+#: ../src/widgets/toolbox.cpp:3858
 msgid "Bezier"
 msgstr "Bézier"
 
-#: ../src/widgets/toolbox.cpp:3856
+#: ../src/widgets/toolbox.cpp:3859
 msgid "Create regular Bezier path"
 msgstr "Créer un chemin de Bézier régulier"
 
-#: ../src/widgets/toolbox.cpp:3862
+#: ../src/widgets/toolbox.cpp:3865
 msgid "Spiro"
 msgstr "Spiro"
 
-#: ../src/widgets/toolbox.cpp:3863
+#: ../src/widgets/toolbox.cpp:3866
 msgid "Create Spiro path"
 msgstr "Créer un chemin spirographique"
 
-#: ../src/widgets/toolbox.cpp:3870
+#: ../src/widgets/toolbox.cpp:3873
 msgid "Zigzag"
 msgstr "Zigzag"
 
-#: ../src/widgets/toolbox.cpp:3871
+#: ../src/widgets/toolbox.cpp:3874
 msgid "Create a sequence of straight line segments"
 msgstr "Créer une séquence de segments de lignes droites"
 
-#: ../src/widgets/toolbox.cpp:3877
+#: ../src/widgets/toolbox.cpp:3880
 msgid "Paraxial"
 msgstr "Paraxial"
 
-#: ../src/widgets/toolbox.cpp:3878
+#: ../src/widgets/toolbox.cpp:3881
 msgid "Create a sequence of paraxial line segments"
 msgstr "Créer une séquence de segments de lignes paraxiales"
 
-#: ../src/widgets/toolbox.cpp:3886
+#: ../src/widgets/toolbox.cpp:3889
 msgid "Mode of new lines drawn by this tool"
 msgstr "Mode des nouvelles lignes dessinées avec cet outil"
 
-#: ../src/widgets/toolbox.cpp:3915
+#: ../src/widgets/toolbox.cpp:3918
 msgid "Triangle in"
 msgstr "Triangle décroissant"
 
-#: ../src/widgets/toolbox.cpp:3916
+#: ../src/widgets/toolbox.cpp:3919
 msgid "Triangle out"
 msgstr "Triangle croissant"
 
-#: ../src/widgets/toolbox.cpp:3918
+#: ../src/widgets/toolbox.cpp:3921
 msgid "From clipboard"
 msgstr "À partir du presse-papier"
 
-#: ../src/widgets/toolbox.cpp:3943
-#: ../src/widgets/toolbox.cpp:3944
+#: ../src/widgets/toolbox.cpp:3946
+#: ../src/widgets/toolbox.cpp:3947
 msgid "Shape:"
 msgstr "Forme :"
 
-#: ../src/widgets/toolbox.cpp:3943
+#: ../src/widgets/toolbox.cpp:3946
 msgid "Shape of new paths drawn by this tool"
 msgstr "Style des nouveaux chemins dessinés avec cet outil"
 
-#: ../src/widgets/toolbox.cpp:4028
+#: ../src/widgets/toolbox.cpp:4032
 msgid "(many nodes, rough)"
 msgstr "(nombreux nœuds, rugueux)"
 
-#: ../src/widgets/toolbox.cpp:4028
-#: ../src/widgets/toolbox.cpp:4148
-#: ../src/widgets/toolbox.cpp:4165
-#: ../src/widgets/toolbox.cpp:4368
-#: ../src/widgets/toolbox.cpp:4472
-#: ../src/widgets/toolbox.cpp:4488
-#: ../src/widgets/toolbox.cpp:4504
-#: ../src/widgets/toolbox.cpp:4564
-#: ../src/widgets/toolbox.cpp:4931
-#: ../src/widgets/toolbox.cpp:4964
-#: ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4032
+#: ../src/widgets/toolbox.cpp:4149
+#: ../src/widgets/toolbox.cpp:4166
+#: ../src/widgets/toolbox.cpp:4369
+#: ../src/widgets/toolbox.cpp:4475
+#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4567
+#: ../src/widgets/toolbox.cpp:4934
+#: ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:5953
 msgid "(default)"
 msgstr "(défaut)"
 
-#: ../src/widgets/toolbox.cpp:4028
+#: ../src/widgets/toolbox.cpp:4032
 msgid "(few nodes, smooth)"
 msgstr "(peu de nœuds, doux)"
 
-#: ../src/widgets/toolbox.cpp:4031
+#: ../src/widgets/toolbox.cpp:4035
 msgid "Smoothing:"
 msgstr "Lissage :"
 
-#: ../src/widgets/toolbox.cpp:4031
+#: ../src/widgets/toolbox.cpp:4035
 msgid "Smoothing: "
 msgstr "Lissage :"
 
-#: ../src/widgets/toolbox.cpp:4032
+#: ../src/widgets/toolbox.cpp:4036
 msgid "How much smoothing (simplifying) is applied to the line"
 msgstr "Quel niveau de lissage (simplification) est appliqué à la ligne"
 
-#: ../src/widgets/toolbox.cpp:4055
+#: ../src/widgets/toolbox.cpp:4056
 msgid "Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"
 msgstr "Restaurer les préférences du crayon par défaut (changez les valeurs par défaut dans Préférences d'Inkscape > Outils)"
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4148
+#: ../src/widgets/toolbox.cpp:4149
 msgid "(pinch tweak)"
 msgstr "(ajustement serré)"
 
-#: ../src/widgets/toolbox.cpp:4148
+#: ../src/widgets/toolbox.cpp:4149
 msgid "(broad tweak)"
 msgstr "(ajustement large)"
 
-#: ../src/widgets/toolbox.cpp:4151
+#: ../src/widgets/toolbox.cpp:4152
 msgid "The width of the tweak area (relative to the visible canvas area)"
 msgstr "Largeur de la zone d'ajustement (relativement à la zone de travail visible)"
 
 #. Force
-#: ../src/widgets/toolbox.cpp:4165
+#: ../src/widgets/toolbox.cpp:4166
 msgid "(minimum force)"
 msgstr "(force minimum)"
 
-#: ../src/widgets/toolbox.cpp:4165
+#: ../src/widgets/toolbox.cpp:4166
 msgid "(maximum force)"
 msgstr "(force maximum)"
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "Force"
 msgstr "Force"
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "Force:"
 msgstr "Force :"
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "The force of the tweak action"
 msgstr "Force de l'action d'ajustement"
 
-#: ../src/widgets/toolbox.cpp:4186
+#: ../src/widgets/toolbox.cpp:4187
 msgid "Move mode"
 msgstr "Mode déplacement"
 
-#: ../src/widgets/toolbox.cpp:4187
+#: ../src/widgets/toolbox.cpp:4188
 msgid "Move objects in any direction"
 msgstr "Déplace la sélection dans la direction du curseur"
 
-#: ../src/widgets/toolbox.cpp:4193
+#: ../src/widgets/toolbox.cpp:4194
 msgid "Move in/out mode"
 msgstr "Mode rapprochement/éloignement"
 
-#: ../src/widgets/toolbox.cpp:4194
+#: ../src/widgets/toolbox.cpp:4195
 msgid "Move objects towards cursor; with Shift from cursor"
 msgstr "Déplace l'objet vers le curseur ; avec Maj, à l'encontre du curseur"
 
-#: ../src/widgets/toolbox.cpp:4200
+#: ../src/widgets/toolbox.cpp:4201
 msgid "Move jitter mode"
 msgstr "Mode déplacement aléatoire"
 
-#: ../src/widgets/toolbox.cpp:4201
+#: ../src/widgets/toolbox.cpp:4202
 msgid "Move objects in random directions"
 msgstr "Déplace la sélection dans une direction aléatoire"
 
-#: ../src/widgets/toolbox.cpp:4207
+#: ../src/widgets/toolbox.cpp:4208
 msgid "Scale mode"
 msgstr "Mode redimensionnement"
 
-#: ../src/widgets/toolbox.cpp:4208
+#: ../src/widgets/toolbox.cpp:4209
 msgid "Shrink objects, with Shift enlarge"
 msgstr "Rétrécir les objets, avec Maj. étirer"
 
-#: ../src/widgets/toolbox.cpp:4214
+#: ../src/widgets/toolbox.cpp:4215
 msgid "Rotate mode"
 msgstr "Mode rotation"
 
-#: ../src/widgets/toolbox.cpp:4215
+#: ../src/widgets/toolbox.cpp:4216
 msgid "Rotate objects, with Shift counterclockwise"
 msgstr "Applique une rotation dans le sens horaire ; avec Maj, le sens est inversé"
 
-#: ../src/widgets/toolbox.cpp:4221
+#: ../src/widgets/toolbox.cpp:4222
 msgid "Duplicate/delete mode"
 msgstr "Mode duplication/suppression"
 
-#: ../src/widgets/toolbox.cpp:4222
+#: ../src/widgets/toolbox.cpp:4223
 msgid "Duplicate objects, with Shift delete"
 msgstr "Duplique les objets ; avec Maj, efface"
 
-#: ../src/widgets/toolbox.cpp:4228
+#: ../src/widgets/toolbox.cpp:4229
 msgid "Push mode"
 msgstr "Mode poussée"
 
-#: ../src/widgets/toolbox.cpp:4229
+#: ../src/widgets/toolbox.cpp:4230
 msgid "Push parts of paths in any direction"
 msgstr "Pousse le chemin dans le sens du curseur"
 
-#: ../src/widgets/toolbox.cpp:4235
+#: ../src/widgets/toolbox.cpp:4236
 msgid "Shrink/grow mode"
 msgstr "Mode rétrécissement/élargissement"
 
-#: ../src/widgets/toolbox.cpp:4236
+#: ../src/widgets/toolbox.cpp:4237
 msgid "Shrink (inset) parts of paths; with Shift grow (outset)"
 msgstr "Rétrécit les chemins (contraction) ; avec Maj, élargit (dilatation)"
 
-#: ../src/widgets/toolbox.cpp:4242
+#: ../src/widgets/toolbox.cpp:4243
 msgid "Attract/repel mode"
 msgstr "Mode attraction/répulsion"
 
-#: ../src/widgets/toolbox.cpp:4243
+#: ../src/widgets/toolbox.cpp:4244
 msgid "Attract parts of paths towards cursor; with Shift from cursor"
 msgstr "Attire les chemins vers le curseur ; avec Maj, éloigne les chemins du curseur"
 
-#: ../src/widgets/toolbox.cpp:4249
+#: ../src/widgets/toolbox.cpp:4250
 msgid "Roughen mode"
 msgstr "Mode rugueux"
 
-#: ../src/widgets/toolbox.cpp:4250
+#: ../src/widgets/toolbox.cpp:4251
 msgid "Roughen parts of paths"
 msgstr "Rend les chemins plus rugueux"
 
-#: ../src/widgets/toolbox.cpp:4256
+#: ../src/widgets/toolbox.cpp:4257
 msgid "Color paint mode"
 msgstr "Mode peinture de couleur"
 
-#: ../src/widgets/toolbox.cpp:4257
+#: ../src/widgets/toolbox.cpp:4258
 msgid "Paint the tool's color upon selected objects"
 msgstr "Décaler la couleur des objets vers celle de l'outil"
 
-#: ../src/widgets/toolbox.cpp:4263
+#: ../src/widgets/toolbox.cpp:4264
 msgid "Color jitter mode"
 msgstr "Mode perturbation des couleurs"
 
-#: ../src/widgets/toolbox.cpp:4264
+#: ../src/widgets/toolbox.cpp:4265
 msgid "Jitter the colors of selected objects"
 msgstr "Perturber la couleur des objets sélectionnés"
 
-#: ../src/widgets/toolbox.cpp:4270
+#: ../src/widgets/toolbox.cpp:4271
 msgid "Blur mode"
 msgstr "Mode flou"
 
-#: ../src/widgets/toolbox.cpp:4271
+#: ../src/widgets/toolbox.cpp:4272
 msgid "Blur selected objects more; with Shift, blur less"
 msgstr "Ajoute du flou à la sélection ; avec Maj, retire du flou"
 
-#: ../src/widgets/toolbox.cpp:4298
+#: ../src/widgets/toolbox.cpp:4299
 msgid "Channels:"
 msgstr "Canaux :"
 
-#: ../src/widgets/toolbox.cpp:4309
+#: ../src/widgets/toolbox.cpp:4310
 msgid "In color mode, act on objects' hue"
 msgstr "En mode couleur, agit sur la teinte des objets"
 
 #. TRANSLATORS:  "H" here stands for hue
-#: ../src/widgets/toolbox.cpp:4313
+#: ../src/widgets/toolbox.cpp:4314
 msgid "H"
 msgstr "T"
 
-#: ../src/widgets/toolbox.cpp:4324
+#: ../src/widgets/toolbox.cpp:4325
 msgid "In color mode, act on objects' saturation"
 msgstr "En mode couleur, agit sur la saturation des objets"
 
 # Saturation (in HSL)
 #. TRANSLATORS: "S" here stands for Saturation
-#: ../src/widgets/toolbox.cpp:4328
+#: ../src/widgets/toolbox.cpp:4329
 msgid "S"
 msgstr "S"
 
-#: ../src/widgets/toolbox.cpp:4339
+#: ../src/widgets/toolbox.cpp:4340
 msgid "In color mode, act on objects' lightness"
 msgstr "En mode couleur, agit sur la luminosité des objets"
 
 # Luminosity (in HSL)
 #. TRANSLATORS: "L" here stands for Lightness
-#: ../src/widgets/toolbox.cpp:4343
+#: ../src/widgets/toolbox.cpp:4344
 msgid "L"
 msgstr "L"
 
-#: ../src/widgets/toolbox.cpp:4354
+#: ../src/widgets/toolbox.cpp:4355
 msgid "In color mode, act on objects' opacity"
 msgstr "En mode couleur, agit sur l'opacité des objets"
 
 # Opacity
 #. TRANSLATORS: "O" here stands for Opacity
-#: ../src/widgets/toolbox.cpp:4358
+#: ../src/widgets/toolbox.cpp:4359
 msgid "O"
 msgstr "O"
 
 #. Fidelity
-#: ../src/widgets/toolbox.cpp:4368
+#: ../src/widgets/toolbox.cpp:4369
 msgid "(rough, simplified)"
 msgstr "(grossier, simplifié)"
 
-#: ../src/widgets/toolbox.cpp:4368
+#: ../src/widgets/toolbox.cpp:4369
 msgid "(fine, but many nodes)"
 msgstr "(fin, mais avec beaucoup de nœuds)"
 
-#: ../src/widgets/toolbox.cpp:4371
+#: ../src/widgets/toolbox.cpp:4372
 msgid "Fidelity"
 msgstr "Fidélité"
 
-#: ../src/widgets/toolbox.cpp:4371
+#: ../src/widgets/toolbox.cpp:4372
 msgid "Fidelity:"
 msgstr "Fidélité:"
 
-#: ../src/widgets/toolbox.cpp:4372
+#: ../src/widgets/toolbox.cpp:4373
 msgid "Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"
 msgstr "Une basse fidélité simplifie les chemins; Une haute fidélité préserve les propriétés des chemins mais peut ajouter de nombreux nœuds."
 
-#: ../src/widgets/toolbox.cpp:4389
-#: ../src/widgets/toolbox.cpp:4582
-#: ../src/widgets/toolbox.cpp:5082
+#: ../src/widgets/toolbox.cpp:4390
+#: ../src/widgets/toolbox.cpp:4585
+#: ../src/widgets/toolbox.cpp:5085
 msgid "Pressure"
 msgstr "Pression"
 
-#: ../src/widgets/toolbox.cpp:4390
+#: ../src/widgets/toolbox.cpp:4391
 msgid "Use the pressure of the input device to alter the force of tweak action"
 msgstr "Utiliser la pression du périphérique d'entrée pour modifier la force de l'outil"
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4472
+#: ../src/widgets/toolbox.cpp:4475
 msgid "(narrow spray)"
 msgstr " (pulvérisation étroite)"
 
-#: ../src/widgets/toolbox.cpp:4472
+#: ../src/widgets/toolbox.cpp:4475
 msgid "(broad spray)"
 msgstr " (pulvérisation large)"
 
-#: ../src/widgets/toolbox.cpp:4475
+#: ../src/widgets/toolbox.cpp:4478
 msgid "The width of the spray area (relative to the visible canvas area)"
 msgstr "Largeur de la zone de pulvérisation (relativement à la zone de travail visible)"
 
 #. Mean
-#: ../src/widgets/toolbox.cpp:4488
+#: ../src/widgets/toolbox.cpp:4491
 msgid "(minimum mean)"
 msgstr "(moyenne minimale)"
 
-#: ../src/widgets/toolbox.cpp:4488
+#: ../src/widgets/toolbox.cpp:4491
 msgid "(maximum mean)"
 msgstr "(moyenne maximale)"
 
-#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4494
 #: ../share/extensions/polyhedron_3d.inx.h:25
 msgid "Mean"
 msgstr "Moyenne"
 
-#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4494
 msgid "Mean:"
 msgstr "Moyenne :"
 
-#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4494
 msgid "The mean of the spray action"
 msgstr "La moyenne de la pulvérisation"
 
 #. Standard_deviation
-#: ../src/widgets/toolbox.cpp:4504
+#: ../src/widgets/toolbox.cpp:4507
 msgid "(minimum standard_deviation)"
 msgstr "(écart type minimum)"
 
-#: ../src/widgets/toolbox.cpp:4504
+#: ../src/widgets/toolbox.cpp:4507
 msgid "(maximum standard_deviation)"
 msgstr "(écart type maximum)"
 
 # Saturation (in HSL)
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "SD"
 msgstr "Écart type"
 
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "SD:"
 msgstr "Écart type :"
 
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "The standard deviation of the spray action"
 msgstr "L'écart type de la pulvérisation"
 
-#: ../src/widgets/toolbox.cpp:4526
+#: ../src/widgets/toolbox.cpp:4529
 msgid "Spray copies of the initial selection"
 msgstr "Pulvériser des copies de la sélection initiale"
 
-#: ../src/widgets/toolbox.cpp:4533
+#: ../src/widgets/toolbox.cpp:4536
 msgid "Spray clones of the initial selection"
 msgstr "Pulvériser des clones de la sélection initiale"
 
-#: ../src/widgets/toolbox.cpp:4539
+#: ../src/widgets/toolbox.cpp:4542
 msgid "Spray single path"
 msgstr "Pulvérisation par union des formes"
 
-#: ../src/widgets/toolbox.cpp:4540
+#: ../src/widgets/toolbox.cpp:4543
 msgid "Spray objects in a single path"
 msgstr "Pulvérisation fusionnée en un chemin unique"
 
 #. Population
-#: ../src/widgets/toolbox.cpp:4564
+#: ../src/widgets/toolbox.cpp:4567
 msgid "(low population)"
 msgstr "(faible population)"
 
-#: ../src/widgets/toolbox.cpp:4564
+#: ../src/widgets/toolbox.cpp:4567
 msgid "(high population)"
 msgstr "(forte population)"
 
-#: ../src/widgets/toolbox.cpp:4567
+#: ../src/widgets/toolbox.cpp:4570
 msgid "Population"
 msgstr "Population"
 
-#: ../src/widgets/toolbox.cpp:4567
+#: ../src/widgets/toolbox.cpp:4570
 msgid "Population:"
 msgstr "Population :"
 
-#: ../src/widgets/toolbox.cpp:4568
+#: ../src/widgets/toolbox.cpp:4571
 msgid "This setting adjusts the number of items sprayed"
 msgstr "Ce paramètre spécifie le nombre de d'éléments pulvérisés"
 
-#: ../src/widgets/toolbox.cpp:4583
+#: ../src/widgets/toolbox.cpp:4586
 msgid "Use the pressure of the input device to alter the force of spray action"
 msgstr "Utiliser la pression du périphérique d'entrée pour modifier la force de pulvérisation"
 
-#: ../src/widgets/toolbox.cpp:4762
+#: ../src/widgets/toolbox.cpp:4765
 msgid "No preset"
 msgstr "Aucune présélection"
 
-#: ../src/widgets/toolbox.cpp:4780
+#: ../src/widgets/toolbox.cpp:4783
 msgid "Save..."
 msgstr "Enregistrer sous..."
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4931
-#: ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4934
+#: ../src/widgets/toolbox.cpp:5953
 msgid "(hairline)"
 msgstr "(sans épaisseur)"
 
-#: ../src/widgets/toolbox.cpp:4931
-#: ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4934
+#: ../src/widgets/toolbox.cpp:5953
 msgid "(broad stroke)"
 msgstr " (trait large)"
 
-#: ../src/widgets/toolbox.cpp:4934
-#: ../src/widgets/toolbox.cpp:5953
+#: ../src/widgets/toolbox.cpp:4937
+#: ../src/widgets/toolbox.cpp:5956
 msgid "Pen Width"
 msgstr "Largeur du stylo"
 
-#: ../src/widgets/toolbox.cpp:4935
+#: ../src/widgets/toolbox.cpp:4938
 msgid "The width of the calligraphic pen (relative to the visible canvas area)"
 msgstr "Largeur de la plume (relativement à la zone de travail visible)"
 
 #. Thinning
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(speed blows up stroke)"
 msgstr "(la vitesse gonfle le trait)"
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(slight widening)"
 msgstr "(léger élargissement)"
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(constant width)"
 msgstr "(largeur constante)"
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(slight thinning, default)"
 msgstr "(léger amincissement, défaut)"
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(speed deflates stroke)"
 msgstr "(la vitesse affine le trait)"
 
-#: ../src/widgets/toolbox.cpp:4951
+#: ../src/widgets/toolbox.cpp:4954
 msgid "Stroke Thinning"
 msgstr "Affinnement du trait"
 
-#: ../src/widgets/toolbox.cpp:4951
+#: ../src/widgets/toolbox.cpp:4954
 msgid "Thinning:"
 msgstr "Mincissement :"
 
-#: ../src/widgets/toolbox.cpp:4952
+#: ../src/widgets/toolbox.cpp:4955
 msgid "How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"
 msgstr "Largeur du tracé en fonction de la vélocité. (>0 la vitesse du tracé diminue sa largeur, <0 l'augmente, 0 ne l'influence pas)"
 
 #. Angle
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(left edge up)"
 msgstr "(bord gauche vers le haut)"
 
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(horizontal)"
 msgstr "(horizontal)"
 
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(right edge up)"
 msgstr "(bord droit vers le haut)"
 
-#: ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:4970
 msgid "Pen Angle"
 msgstr "Angle du stylo"
 
-#: ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:4970
 msgid "Angle:"
 msgstr "Angle :"
 
-#: ../src/widgets/toolbox.cpp:4968
+#: ../src/widgets/toolbox.cpp:4971
 msgid "The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"
 msgstr "Angle de la plume (en degrés; 0 = horizontal; n'a pas d'effet si orientation = 0)"
 
 #. Fixation
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(perpendicular to stroke, \"brush\")"
 msgstr "(perpendiculaire au tracé, « pinceau »)"
 
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(almost fixed, default)"
 msgstr "(presque fixe, valeur par défaut)"
 
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(fixed by Angle, \"pen\")"
 msgstr "(fixé par un angle, « stylo »)"
 
-#: ../src/widgets/toolbox.cpp:4985
+#: ../src/widgets/toolbox.cpp:4988
 msgid "Fixation"
 msgstr "Fixité"
 
-#: ../src/widgets/toolbox.cpp:4985
+#: ../src/widgets/toolbox.cpp:4988
 msgid "Fixation:"
 msgstr "Fixité :"
 
-#: ../src/widgets/toolbox.cpp:4986
+#: ../src/widgets/toolbox.cpp:4989
 msgid "Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"
 msgstr "Comportement de l'angle de la plume (0 = toujours perpendiculaire à la direction du tracé, 100 = invariant)"
 
 #. Cap Rounding
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(blunt caps, default)"
 msgstr "(terminaisons planes, défaut)"
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(slightly bulging)"
 msgstr "(légèrement bombées)"
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(approximately round)"
 msgstr "(approximativement arrondies)"
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(long protruding caps)"
 msgstr "(terminaisons très proéminentes)"
 
-#: ../src/widgets/toolbox.cpp:5002
+#: ../src/widgets/toolbox.cpp:5005
 msgid "Cap rounding"
 msgstr "Arrondi de la terminaison"
 
-#: ../src/widgets/toolbox.cpp:5002
+#: ../src/widgets/toolbox.cpp:5005
 msgid "Caps:"
 msgstr "Terminaisons :"
 
-#: ../src/widgets/toolbox.cpp:5003
+#: ../src/widgets/toolbox.cpp:5006
 msgid "Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"
 msgstr "Augmenter ce paramètre pour que les extrémités du tracé soient plus proéminentes (0 = pas de terminaison, 1 = terminaison arrondie)"
 
 #. Tremor
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(smooth line)"
 msgstr "(ligne douce)"
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(slight tremor)"
 msgstr "(léger tremblement)"
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(noticeable tremor)"
 msgstr "(tremblement sensible)"
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(maximum tremor)"
 msgstr "(tremblement maximum)"
 
-#: ../src/widgets/toolbox.cpp:5018
+#: ../src/widgets/toolbox.cpp:5021
 msgid "Stroke Tremor"
 msgstr "Appliquer un tremblement au contour"
 
-#: ../src/widgets/toolbox.cpp:5018
+#: ../src/widgets/toolbox.cpp:5021
 msgid "Tremor:"
 msgstr "Tremblement :"
 
-#: ../src/widgets/toolbox.cpp:5019
+#: ../src/widgets/toolbox.cpp:5022
 msgid "Increase to make strokes rugged and trembling"
 msgstr "Augmenter ce paramètre pour rendre la plume tremblante et irrégulière"
 
 #. Wiggle
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(no wiggle)"
 msgstr "(pas d'agitation)"
 
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(slight deviation)"
 msgstr "(légères déviations)"
 
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(wild waves and curls)"
 msgstr "(grandes vagues et boucles)"
 
-#: ../src/widgets/toolbox.cpp:5036
+#: ../src/widgets/toolbox.cpp:5039
 msgid "Pen Wiggle"
 msgstr "Agitation du stylo"
 
-#: ../src/widgets/toolbox.cpp:5036
+#: ../src/widgets/toolbox.cpp:5039
 msgid "Wiggle:"
 msgstr "Agitation :"
 
-#: ../src/widgets/toolbox.cpp:5037
+#: ../src/widgets/toolbox.cpp:5040
 msgid "Increase to make the pen waver and wiggle"
 msgstr "Augmenter ce paramètre pour rendre la plume hésitante et agitée"
 
 #. Mass
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(no inertia)"
 msgstr "(aucune inertie)"
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(slight smoothing, default)"
 msgstr "(lissage léger, valeur par défaut)"
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(noticeable lagging)"
 msgstr "(retard sensible)"
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(maximum inertia)"
 msgstr "(inertie maximum)"
 
-#: ../src/widgets/toolbox.cpp:5053
+#: ../src/widgets/toolbox.cpp:5056
 msgid "Pen Mass"
 msgstr "Inertie du stylo"
 
-#: ../src/widgets/toolbox.cpp:5053
+#: ../src/widgets/toolbox.cpp:5056
 msgid "Mass:"
 msgstr "Inertie :"
 
-#: ../src/widgets/toolbox.cpp:5054
+#: ../src/widgets/toolbox.cpp:5057
 msgid "Increase to make the pen drag behind, as if slowed by inertia"
 msgstr "Augmenter ce paramètre pour que la plume traîne, ralentie par son inertie"
 
-#: ../src/widgets/toolbox.cpp:5069
+#: ../src/widgets/toolbox.cpp:5072
 msgid "Trace Background"
 msgstr "Tracer selon le fond"
 
-#: ../src/widgets/toolbox.cpp:5070
+#: ../src/widgets/toolbox.cpp:5073
 msgid "Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"
 msgstr "Imiter la luminosité du fond avec l'épaisseur du trait (blanc - trait fin, noir - trait épais)"
 
-#: ../src/widgets/toolbox.cpp:5083
+#: ../src/widgets/toolbox.cpp:5086
 msgid "Use the pressure of the input device to alter the width of the pen"
 msgstr "Utiliser la pression du périphérique d'entrée pour modifier la largeur de la plume"
 
-#: ../src/widgets/toolbox.cpp:5095
+#: ../src/widgets/toolbox.cpp:5098
 msgid "Tilt"
 msgstr "Inclinaison"
 
-#: ../src/widgets/toolbox.cpp:5096
+#: ../src/widgets/toolbox.cpp:5099
 msgid "Use the tilt of the input device to alter the angle of the pen's nib"
 msgstr "Utiliser l'inclinaison du périphérique d'entrée pour modifier l'angle de la plume"
 
-#: ../src/widgets/toolbox.cpp:5109
+#: ../src/widgets/toolbox.cpp:5112
 msgid "Choose a preset"
 msgstr "Aucune présélection"
 
-#: ../src/widgets/toolbox.cpp:5197
+#: ../src/widgets/toolbox.cpp:5200
 msgid "Arc: Change start/end"
 msgstr "Arc : déplacer début/fin"
 
-#: ../src/widgets/toolbox.cpp:5261
+#: ../src/widgets/toolbox.cpp:5264
 msgid "Arc: Change open/closed"
 msgstr "Arc : modifier ouvert/fermé"
 
-#: ../src/widgets/toolbox.cpp:5387
+#: ../src/widgets/toolbox.cpp:5390
 msgid "Start:"
 msgstr "Début :"
 
-#: ../src/widgets/toolbox.cpp:5388
+#: ../src/widgets/toolbox.cpp:5391
 msgid "The angle (in degrees) from the horizontal to the arc's start point"
 msgstr "Angle (en degrés) entre l'horizontale et le début de l'arc"
 
-#: ../src/widgets/toolbox.cpp:5400
+#: ../src/widgets/toolbox.cpp:5403
 msgid "End:"
 msgstr "Fin :"
 
-#: ../src/widgets/toolbox.cpp:5401
+#: ../src/widgets/toolbox.cpp:5404
 msgid "The angle (in degrees) from the horizontal to the arc's end point"
 msgstr "Angle (en degrés) entre l'horizontale et la fin de l'arc"
 
-#: ../src/widgets/toolbox.cpp:5417
+#: ../src/widgets/toolbox.cpp:5420
 msgid "Closed arc"
 msgstr "Arc fermé"
 
-#: ../src/widgets/toolbox.cpp:5418
+#: ../src/widgets/toolbox.cpp:5421
 msgid "Switch to segment (closed shape with two radii)"
 msgstr "Tracer un camembert (forme fermée entre deux rayons)"
 
-#: ../src/widgets/toolbox.cpp:5424
+#: ../src/widgets/toolbox.cpp:5427
 msgid "Open Arc"
 msgstr "Arc ouvert"
 
-#: ../src/widgets/toolbox.cpp:5425
+#: ../src/widgets/toolbox.cpp:5428
 msgid "Switch to arc (unclosed shape)"
 msgstr "Tracer un arc (courbe non fermée)"
 
-#: ../src/widgets/toolbox.cpp:5448
+#: ../src/widgets/toolbox.cpp:5451
 msgid "Make whole"
 msgstr "Refermer"
 
-#: ../src/widgets/toolbox.cpp:5449
+#: ../src/widgets/toolbox.cpp:5452
 msgid "Make the shape a whole ellipse, not arc or segment"
 msgstr "Transformer en ellipse pleine (pas un arc ou un camembert)"
 
-#: ../src/widgets/toolbox.cpp:5525
+#: ../src/widgets/toolbox.cpp:5528
 msgid "Pick opacity"
 msgstr "Capturer l'opacité"
 
-#: ../src/widgets/toolbox.cpp:5526
+#: ../src/widgets/toolbox.cpp:5529
 msgid "Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"
 msgstr "Capturer à la fois la couleur et l'alpha (opacité) sous le curseur; Sinon, ne capturer que la couleur visible prémultipliée par l'alpha"
 
-#: ../src/widgets/toolbox.cpp:5529
+#: ../src/widgets/toolbox.cpp:5532
 msgid "Pick"
 msgstr "Capturer"
 
-#: ../src/widgets/toolbox.cpp:5538
+#: ../src/widgets/toolbox.cpp:5541
 msgid "Assign opacity"
 msgstr "Appliquer l'opacité"
 
-#: ../src/widgets/toolbox.cpp:5539
+#: ../src/widgets/toolbox.cpp:5542
 msgid "If alpha was picked, assign it to selection as fill or stroke transparency"
 msgstr "Si l'alpha a été capturé, l'appliquer comme transparence de remplissage ou de contour à la sélection"
 
-#: ../src/widgets/toolbox.cpp:5542
+#: ../src/widgets/toolbox.cpp:5545
 msgid "Assign"
 msgstr "Appliquer"
 
-#: ../src/widgets/toolbox.cpp:5728
+#: ../src/widgets/toolbox.cpp:5731
 msgid "Closed"
 msgstr "Fermé"
 
-#: ../src/widgets/toolbox.cpp:5730
+#: ../src/widgets/toolbox.cpp:5733
 msgid "Open start"
 msgstr "Début ouvert"
 
-#: ../src/widgets/toolbox.cpp:5732
+#: ../src/widgets/toolbox.cpp:5735
 msgid "Open end"
 msgstr "Fin ouverte"
 
-#: ../src/widgets/toolbox.cpp:5734
+#: ../src/widgets/toolbox.cpp:5737
 msgid "Open both"
 msgstr "Les deux ouverts"
 
-#: ../src/widgets/toolbox.cpp:5793
+#: ../src/widgets/toolbox.cpp:5796
 msgid "All inactive"
 msgstr "Tout inactif"
 
-#: ../src/widgets/toolbox.cpp:5794
+#: ../src/widgets/toolbox.cpp:5797
 msgid "No geometric tool is active"
 msgstr "Aucun outil géométrique n'est actif"
 
-#: ../src/widgets/toolbox.cpp:5827
+#: ../src/widgets/toolbox.cpp:5830
 msgid "Show limiting bounding box"
 msgstr "Montrer la boîte englobante limite"
 
-#: ../src/widgets/toolbox.cpp:5828
+#: ../src/widgets/toolbox.cpp:5831
 msgid "Show bounding box (used to cut infinite lines)"
 msgstr "Affiche la boîte englobante (utilisé pour couper les lignes infinies)"
 
-#: ../src/widgets/toolbox.cpp:5839
+#: ../src/widgets/toolbox.cpp:5842
 msgid "Get limiting bounding box from selection"
 msgstr "Obtenir la boîte englobante limite à partir de la sélection"
 
-#: ../src/widgets/toolbox.cpp:5840
+#: ../src/widgets/toolbox.cpp:5843
 msgid "Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"
 msgstr "Définir la boîte englobante limite (utilisée pour couper les lignes infinies) à la boîte englobante de la sélection"
 
-#: ../src/widgets/toolbox.cpp:5852
+#: ../src/widgets/toolbox.cpp:5855
 msgid "Choose a line segment type"
 msgstr "Sélectionner un type de segment"
 
-#: ../src/widgets/toolbox.cpp:5868
+#: ../src/widgets/toolbox.cpp:5871
 msgid "Display measuring info"
 msgstr "Afficher les informations de mesure"
 
-#: ../src/widgets/toolbox.cpp:5869
+#: ../src/widgets/toolbox.cpp:5872
 msgid "Display measuring info for selected items"
 msgstr "Affiche les informations de mesure pour la sélection"
 
-#: ../src/widgets/toolbox.cpp:5889
+#: ../src/widgets/toolbox.cpp:5892
 msgid "Open LPE dialog"
 msgstr "Ouvrir la boîte de dialogue des effets de chemin"
 
-#: ../src/widgets/toolbox.cpp:5890
+#: ../src/widgets/toolbox.cpp:5893
 msgid "Open LPE dialog (to adapt parameters numerically)"
 msgstr "Ouvrir la boîte de dialogue des effets de chemin (pour adapter les paramètres numériquement)"
 
-#: ../src/widgets/toolbox.cpp:5954
+#: ../src/widgets/toolbox.cpp:5957
 msgid "The width of the eraser pen (relative to the visible canvas area)"
 msgstr "Largeur de la gomme (relativement à la zone de travail visible)"
 
-#: ../src/widgets/toolbox.cpp:5972
+#: ../src/widgets/toolbox.cpp:5975
 msgid "Delete objects touched by the eraser"
 msgstr "Effacer les objets en contact avec la gomme"
 
-#: ../src/widgets/toolbox.cpp:5978
+#: ../src/widgets/toolbox.cpp:5981
 msgid "Cut"
 msgstr "Couper"
 
-#: ../src/widgets/toolbox.cpp:5979
+#: ../src/widgets/toolbox.cpp:5982
 msgid "Cut out from objects"
 msgstr "Effacer une partie d'objet"
 
-#: ../src/widgets/toolbox.cpp:6323
+#: ../src/widgets/toolbox.cpp:6326
 msgid "Text: Change font family"
 msgstr "Texte : modifier la police"
 
-#: ../src/widgets/toolbox.cpp:6393
+#: ../src/widgets/toolbox.cpp:6473
 msgid "Text: Change alignment"
 msgstr "Texte : modifier l'alignement"
 
-#: ../src/widgets/toolbox.cpp:6497
+#: ../src/widgets/toolbox.cpp:6577
 msgid "Text: Change font style"
 msgstr "Texte : modifier le style de la police"
 
-#: ../src/widgets/toolbox.cpp:6544
+#: ../src/widgets/toolbox.cpp:6624
 msgid "Text: Change orientation"
 msgstr "Texte : modifier l'orientation"
 
-#: ../src/widgets/toolbox.cpp:6658
+#: ../src/widgets/toolbox.cpp:6738
 msgid "Text: Change font size"
 msgstr "Texte : modifier la taille de police"
 
-#: ../src/widgets/toolbox.cpp:6877
+#: ../src/widgets/toolbox.cpp:6957
 msgid "Select font family (Alt+X to access)"
 msgstr "Sélectionner une famille de police (Alt+X)"
 
-#: ../src/widgets/toolbox.cpp:6914
+#: ../src/widgets/toolbox.cpp:6994
 msgid "This font is currently not installed on your system. Inkscape will use the default font instead."
 msgstr "Cette police n'est pas installée sur votre système. Inkscape utilisera la police par défaut à la place"
 
-#: ../src/widgets/toolbox.cpp:6950
+#: ../src/widgets/toolbox.cpp:7030
 msgid "Align left"
 msgstr "Aligné à gauche"
 
-#: ../src/widgets/toolbox.cpp:6972
+#: ../src/widgets/toolbox.cpp:7052
 msgid "Align right"
 msgstr "Aligné à droite"
 
-#: ../src/widgets/toolbox.cpp:6983
+#: ../src/widgets/toolbox.cpp:7063
 msgid "Justify"
 msgstr "Justifiié"
 
-#: ../src/widgets/toolbox.cpp:6998
+#: ../src/widgets/toolbox.cpp:7078
 msgid "Bold"
 msgstr "Gras"
 
-#: ../src/widgets/toolbox.cpp:7009
+#: ../src/widgets/toolbox.cpp:7089
 msgid "Italic"
 msgstr "Italique"
 
-#: ../src/widgets/toolbox.cpp:7148
+#: ../src/widgets/toolbox.cpp:7228
 msgid "Set connector type: orthogonal"
 msgstr "Type de connecteur : orthogonal"
 
-#: ../src/widgets/toolbox.cpp:7148
+#: ../src/widgets/toolbox.cpp:7228
 msgid "Set connector type: polyline"
 msgstr "Type de connecteur : polyligne"
 
-#: ../src/widgets/toolbox.cpp:7198
+#: ../src/widgets/toolbox.cpp:7278
 msgid "Change connector curvature"
 msgstr "Modifier la courbure du connecteur"
 
-#: ../src/widgets/toolbox.cpp:7247
+#: ../src/widgets/toolbox.cpp:7327
 msgid "Change connector spacing"
 msgstr "Modifier la marge des connecteurs"
 
-#: ../src/widgets/toolbox.cpp:7361
+#: ../src/widgets/toolbox.cpp:7441
 msgid "EditMode"
 msgstr "Moded'édition"
 
-#: ../src/widgets/toolbox.cpp:7362
+#: ../src/widgets/toolbox.cpp:7442
 msgid "Switch between connection point editing and connector drawing mode"
 msgstr "Permuter entre le mode Édition de point de connexion et le mode Tracé de connecteur"
 
-#: ../src/widgets/toolbox.cpp:7376
+#: ../src/widgets/toolbox.cpp:7456
 msgid "Avoid"
 msgstr "Éviter"
 
-#: ../src/widgets/toolbox.cpp:7386
+#: ../src/widgets/toolbox.cpp:7466
 msgid "Ignore"
 msgstr "Ignorer"
 
-#: ../src/widgets/toolbox.cpp:7397
+#: ../src/widgets/toolbox.cpp:7477
 msgid "Orthogonal"
 msgstr "Othogonal"
 
-#: ../src/widgets/toolbox.cpp:7398
+#: ../src/widgets/toolbox.cpp:7478
 msgid "Make connector orthogonal or polyline"
 msgstr "Rend les connecteurs orthogonaux ou polylignes"
 
-#: ../src/widgets/toolbox.cpp:7412
+#: ../src/widgets/toolbox.cpp:7492
 msgid "Connector Curvature"
 msgstr "Courbure du connecteur"
 
-#: ../src/widgets/toolbox.cpp:7412
+#: ../src/widgets/toolbox.cpp:7492
 msgid "Curvature:"
 msgstr "Courbure :"
 
-#: ../src/widgets/toolbox.cpp:7413
+#: ../src/widgets/toolbox.cpp:7493
 msgid "The amount of connectors curvature"
 msgstr "Quantité de courbure des connecteurs"
 
-#: ../src/widgets/toolbox.cpp:7423
+#: ../src/widgets/toolbox.cpp:7503
 msgid "Connector Spacing"
 msgstr "Espacement des connecteurs"
 
-#: ../src/widgets/toolbox.cpp:7423
+#: ../src/widgets/toolbox.cpp:7503
 msgid "Spacing:"
 msgstr "Espacement :"
 
-#: ../src/widgets/toolbox.cpp:7424
+#: ../src/widgets/toolbox.cpp:7504
 msgid "The amount of space left around objects by auto-routing connectors"
 msgstr "Espace laissé autour des objets par les connecteurs routés automatiquement"
 
-#: ../src/widgets/toolbox.cpp:7435
+#: ../src/widgets/toolbox.cpp:7515
 msgid "Graph"
 msgstr "Graphe"
 
-#: ../src/widgets/toolbox.cpp:7445
+#: ../src/widgets/toolbox.cpp:7525
 msgid "Connector Length"
 msgstr "Longueur des connecteurs"
 
-#: ../src/widgets/toolbox.cpp:7445
+#: ../src/widgets/toolbox.cpp:7525
 msgid "Length:"
 msgstr "Longueur :"
 
-#: ../src/widgets/toolbox.cpp:7446
+#: ../src/widgets/toolbox.cpp:7526
 msgid "Ideal length for connectors when layout is applied"
 msgstr "Longueur idéale pour les connecteurs après routage"
 
-#: ../src/widgets/toolbox.cpp:7458
+#: ../src/widgets/toolbox.cpp:7538
 msgid "Downwards"
 msgstr "Vers le bas"
 
-#: ../src/widgets/toolbox.cpp:7459
+#: ../src/widgets/toolbox.cpp:7539
 msgid "Make connectors with end-markers (arrows) point downwards"
 msgstr "Faire que les connecteurs avec des marqueurs de fin (des flèches) pointent vers le bas"
 
-#: ../src/widgets/toolbox.cpp:7476
+#: ../src/widgets/toolbox.cpp:7556
 msgid "Do not allow overlapping shapes"
 msgstr "Ne pas permettre que deux formes se chevauchent"
 
-#: ../src/widgets/toolbox.cpp:7491
+#: ../src/widgets/toolbox.cpp:7571
 msgid "New connection point"
 msgstr "Nouveau point de connection"
 
-#: ../src/widgets/toolbox.cpp:7492
+#: ../src/widgets/toolbox.cpp:7572
 msgid "Add a new connection point to the currently selected item"
 msgstr "Ajoute un nouveau point de connexion à l'élément sélectionné"
 
-#: ../src/widgets/toolbox.cpp:7503
+#: ../src/widgets/toolbox.cpp:7583
 msgid "Remove connection point"
 msgstr "Supprimer le point de connection"
 
-#: ../src/widgets/toolbox.cpp:7504
+#: ../src/widgets/toolbox.cpp:7584
 msgid "Remove the currently selected connection point"
 msgstr "Supprime le point de connexion sélectionné"
 
-#: ../src/widgets/toolbox.cpp:7604
+#: ../src/widgets/toolbox.cpp:7684
 msgid "Fill by"
 msgstr "Type de remplissage"
 
-#: ../src/widgets/toolbox.cpp:7605
+#: ../src/widgets/toolbox.cpp:7685
 msgid "Fill by:"
 msgstr "Type de remplissage :"
 
-#: ../src/widgets/toolbox.cpp:7617
+#: ../src/widgets/toolbox.cpp:7697
 msgid "Fill Threshold"
 msgstr "Seuil de remplissage :"
 
-#: ../src/widgets/toolbox.cpp:7618
+#: ../src/widgets/toolbox.cpp:7698
 msgid "The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"
 msgstr "La différence maximale entre le pixel du clic et les pixels voisins pour qu'ils soient ajoutés dans le remplissage"
 
-#: ../src/widgets/toolbox.cpp:7643
+#: ../src/widgets/toolbox.cpp:7723
 msgid "Grow/shrink by"
 msgstr "Agrandir/rétrécir de"
 
-#: ../src/widgets/toolbox.cpp:7643
+#: ../src/widgets/toolbox.cpp:7723
 msgid "Grow/shrink by:"
 msgstr "Agrandir/rétrécir de :"
 
-#: ../src/widgets/toolbox.cpp:7644
+#: ../src/widgets/toolbox.cpp:7724
 msgid "The amount to grow (positive) or shrink (negative) the created fill path"
 msgstr "Agrandit (si positif) ou rétrécit (si négatif) de cette quantité le chemin créé par remplissage."
 
-#: ../src/widgets/toolbox.cpp:7669
+#: ../src/widgets/toolbox.cpp:7749
 msgid "Close gaps"
 msgstr "Combler les vides"
 
-#: ../src/widgets/toolbox.cpp:7670
+#: ../src/widgets/toolbox.cpp:7750
 msgid "Close gaps:"
 msgstr "Combler les vides :"
 
-#: ../src/widgets/toolbox.cpp:7682
+#: ../src/widgets/toolbox.cpp:7762
 msgid "Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"
 msgstr "Restaurer les préférences par défaut de l'outil de remplissage au seau (changez les valeurs par défaut dans Inkscape Préférences > Outils)"
 
@@ -19892,16 +19939,16 @@ msgstr "Aire (px²) :"
 msgid "Failed to import the numpy or numpy.linalg modules. These modules are required by this extension. Please install them and try again."
 msgstr "Échec lors de l'import des modules numpy.linalg. Ces modules sont nécessaires à cette extension. Veuillez les installer et réessayer."
 
-#: ../share/extensions/embedimage.py:74
+#: ../share/extensions/embedimage.py:75
 msgid "No xlink:href or sodipodi:absref attributes found, or they do not point to an existing file! Unable to embed image."
 msgstr "Les attributs xlink:href et sodipodi:absref n'ont pas été trouvés, ou n'indiquent pas un fichier existant ! Impossible d'incorporer l'image."
 
-#: ../share/extensions/embedimage.py:76
+#: ../share/extensions/embedimage.py:77
 #, python-format
 msgid "Sorry we could not locate %s"
 msgstr "Désolé, nous ne pouvons pas localiser %s"
 
-#: ../share/extensions/embedimage.py:101
+#: ../share/extensions/embedimage.py:102
 #, python-format
 msgid "%s is not of type image/png, image/jpeg, image/bmp, image/gif, image/tiff, or image/x-icon"
 msgstr "%s n'est pas du type image/png, image/jpeg, image/bmp, image/gif, image/tiff, ou image/x-icon"
@@ -21916,6 +21963,22 @@ msgstr "Données du code-barre :"
 msgid "Barcode Type:"
 msgstr "Type de code-barre :"
 
+#: ../share/extensions/render_barcode_datamatrix.inx.h:1
+msgid "Barcode - Datamatrix"
+msgstr "Code barre - Datamatrix"
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:2
+msgid "Cols"
+msgstr "Colonnes"
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:4
+msgid "Rows"
+msgstr "Lignes"
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:5
+msgid "Square Size / px"
+msgstr "Taille du carré (px)"
+
 #: ../share/extensions/restack.inx.h:2
 msgid "Arbitrary Angle:"
 msgstr "Angle arbitraire"
@@ -22577,6 +22640,34 @@ msgstr "Rotation en sens horaire"
 msgid "Whirl"
 msgstr "Tourbillon"
 
+#: ../share/extensions/wireframe_sphere.inx.h:1
+msgid "Hide lines behind the sphere"
+msgstr "Cacher les lignes derrière la sphère"
+
+#: ../share/extensions/wireframe_sphere.inx.h:2
+msgid "Lines of latitude"
+msgstr "Lignes de latitude"
+
+#: ../share/extensions/wireframe_sphere.inx.h:3
+msgid "Lines of longitude"
+msgstr "Lignes de longitudes"
+
+#: ../share/extensions/wireframe_sphere.inx.h:4
+msgid "Radius [px]"
+msgstr "Rayon (px)"
+
+#: ../share/extensions/wireframe_sphere.inx.h:6
+msgid "Rotation [deg]"
+msgstr "Rotation (deg)"
+
+#: ../share/extensions/wireframe_sphere.inx.h:7
+msgid "Tilt [deg]"
+msgstr "Inclinaison (deg)"
+
+#: ../share/extensions/wireframe_sphere.inx.h:8
+msgid "Wireframe Sphere"
+msgstr "Sphère fil de fer"
+
 #: ../share/extensions/wmf_input.inx.h:1
 #: ../share/extensions/wmf_output.inx.h:1
 msgid "A popular graphics file format for clipart"
@@ -22596,6 +22687,13 @@ msgstr "Entrée métafichier Windows (*.wmf)"
 msgid "XAML Input"
 msgstr "Entrée XAML"
 
+#, fuzzy
+#~ msgid "Exchange Positions"
+#~ msgstr "Position aléatoire"
+
+#, fuzzy
+#~ msgid "Exchange positions of selected objects"
+#~ msgstr "Perturber la couleur des objets sélectionnés"
 #~ msgid "Uniform"
 #~ msgstr "Uniforme"
 #~ msgid "Gaussian   "
@@ -23967,8 +24065,6 @@ msgstr "Entrée XAML"
 #~ msgstr "Sélectionner une deuxième option :"
 #~ msgid "Random Point"
 #~ msgstr "Point aléatoire"
-#~ msgid "Random Position"
-#~ msgstr "Position aléatoire"
 #~ msgid "medium"
 #~ msgstr "moyen"
 #~ msgid "%s selected out of %d gradient handles on %d selected object"
index ced8b271331b554adf32faf292c043deb1848a09..9d14ac6cb93eae565011982edd6b8b6424aa7797 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: inkscape-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2009-12-03 13:24+0100\n"
+"POT-Creation-Date: 2009-12-27 08:18+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -339,7 +339,7 @@ msgstr ""
 
 #. Pencil
 #: ../share/filters/filters.svg.h:29
-#: ../src/ui/dialog/inkscape-preferences.cpp:492 ../src/verbs.cpp:2528
+#: ../src/ui/dialog/inkscape-preferences.cpp:492 ../src/verbs.cpp:2534
 msgid "Pencil"
 msgstr ""
 
@@ -1522,7 +1522,7 @@ msgstr ""
 
 #: ../share/filters/filters.svg.h:162
 #: ../src/ui/dialog/align-and-distribute.cpp:920
-#: ../src/widgets/desktop-widget.cpp:1576
+#: ../src/widgets/desktop-widget.cpp:1584
 msgid "Drawing"
 msgstr ""
 
@@ -2190,22 +2190,22 @@ msgstr ""
 msgid "Create ellipse"
 msgstr ""
 
-#: ../src/box3d-context.cpp:429 ../src/box3d-context.cpp:436
-#: ../src/box3d-context.cpp:443 ../src/box3d-context.cpp:450
-#: ../src/box3d-context.cpp:457 ../src/box3d-context.cpp:464
+#: ../src/box3d-context.cpp:435 ../src/box3d-context.cpp:442
+#: ../src/box3d-context.cpp:449 ../src/box3d-context.cpp:456
+#: ../src/box3d-context.cpp:463 ../src/box3d-context.cpp:470
 msgid "Change perspective (angle of PLs)"
 msgstr ""
 
 #. status text
-#: ../src/box3d-context.cpp:622
+#: ../src/box3d-context.cpp:638
 msgid "<b>3D Box</b>; with <b>Shift</b> to extrude along the Z axis"
 msgstr ""
 
-#: ../src/box3d-context.cpp:650
+#: ../src/box3d-context.cpp:666
 msgid "Create 3D box"
 msgstr ""
 
-#: ../src/box3d.cpp:315
+#: ../src/box3d.cpp:327
 msgid "<b>3D Box</b>"
 msgstr ""
 
@@ -2241,11 +2241,11 @@ msgstr ""
 msgid "Select <b>at least one non-connector object</b>."
 msgstr ""
 
-#: ../src/connector-context.cpp:1930 ../src/widgets/toolbox.cpp:7377
+#: ../src/connector-context.cpp:1930 ../src/widgets/toolbox.cpp:7457
 msgid "Make connectors avoid selected objects"
 msgstr ""
 
-#: ../src/connector-context.cpp:1931 ../src/widgets/toolbox.cpp:7387
+#: ../src/connector-context.cpp:1931 ../src/widgets/toolbox.cpp:7467
 msgid "Make connectors ignore selected objects"
 msgstr ""
 
@@ -2257,11 +2257,11 @@ msgstr ""
 msgid "<b>Current layer is locked</b>. Unlock it to be able to draw on it."
 msgstr ""
 
-#: ../src/desktop.cpp:830
+#: ../src/desktop.cpp:833
 msgid "No previous zoom."
 msgstr ""
 
-#: ../src/desktop.cpp:855
+#: ../src/desktop.cpp:858
 msgid "No next zoom."
 msgstr ""
 
@@ -2316,7 +2316,7 @@ msgstr ""
 msgid "Delete tiled clones"
 msgstr ""
 
-#: ../src/dialogs/clonetiler.cpp:1097 ../src/selection-chemistry.cpp:1883
+#: ../src/dialogs/clonetiler.cpp:1097 ../src/selection-chemistry.cpp:1906
 msgid "Select an <b>object</b> to clone."
 msgstr ""
 
@@ -2790,7 +2790,7 @@ msgstr ""
 #: ../src/dialogs/clonetiler.cpp:2615 ../src/dialogs/clonetiler.cpp:2764
 #: ../src/extension/internal/bitmap/opacity.cpp:37
 #: ../src/extension/internal/bitmap/opacity.cpp:39
-#: ../src/widgets/toolbox.cpp:4353 ../share/extensions/interp_att_g.inx.h:12
+#: ../src/widgets/toolbox.cpp:4354 ../share/extensions/interp_att_g.inx.h:12
 msgid "Opacity"
 msgstr ""
 
@@ -2994,15 +2994,15 @@ msgid ""
 "to zero"
 msgstr ""
 
-#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2637
+#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2645
 msgid "_Page"
 msgstr ""
 
-#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2641
+#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2649
 msgid "_Drawing"
 msgstr ""
 
-#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2643
+#: ../src/dialogs/export.cpp:146 ../src/verbs.cpp:2651
 msgid "_Selection"
 msgstr ""
 
@@ -3062,8 +3062,8 @@ msgstr ""
 msgid "_Height:"
 msgstr ""
 
-#: ../src/dialogs/export.cpp:509 ../src/ui/dialog/inkscape-preferences.cpp:779
-#: ../src/ui/dialog/inkscape-preferences.cpp:1191
+#: ../src/dialogs/export.cpp:509 ../src/ui/dialog/inkscape-preferences.cpp:784
+#: ../src/ui/dialog/inkscape-preferences.cpp:1196
 msgid "dpi"
 msgstr ""
 
@@ -3371,8 +3371,8 @@ msgid ""
 msgstr ""
 
 #. Button for setting the object's id, label, title and description.
-#: ../src/dialogs/item-properties.cpp:143 ../src/verbs.cpp:2496
-#: ../src/verbs.cpp:2502
+#: ../src/dialogs/item-properties.cpp:143 ../src/verbs.cpp:2502
+#: ../src/verbs.cpp:2508
 msgid "_Set"
 msgstr ""
 
@@ -3528,9 +3528,9 @@ msgid "Y:"
 msgstr ""
 
 #: ../src/dialogs/object-attributes.cpp:53
-#: ../src/dialogs/object-attributes.cpp:61 ../src/widgets/toolbox.cpp:4151
-#: ../src/widgets/toolbox.cpp:4475 ../src/widgets/toolbox.cpp:4934
-#: ../src/widgets/toolbox.cpp:5953
+#: ../src/dialogs/object-attributes.cpp:61 ../src/widgets/toolbox.cpp:4152
+#: ../src/widgets/toolbox.cpp:4478 ../src/widgets/toolbox.cpp:4937
+#: ../src/widgets/toolbox.cpp:5956
 msgid "Width:"
 msgstr ""
 
@@ -3644,11 +3644,11 @@ msgstr ""
 msgid "Justify lines"
 msgstr ""
 
-#: ../src/dialogs/text-edit.cpp:300 ../src/widgets/toolbox.cpp:7031
+#: ../src/dialogs/text-edit.cpp:300 ../src/widgets/toolbox.cpp:7111
 msgid "Horizontal text"
 msgstr ""
 
-#: ../src/dialogs/text-edit.cpp:314 ../src/widgets/toolbox.cpp:7043
+#: ../src/dialogs/text-edit.cpp:314 ../src/widgets/toolbox.cpp:7123
 msgid "Vertical text"
 msgstr ""
 
@@ -3658,9 +3658,10 @@ msgstr ""
 
 #. Text
 #: ../src/dialogs/text-edit.cpp:375 ../src/selection-describer.cpp:69
-#: ../src/ui/dialog/inkscape-preferences.cpp:528 ../src/verbs.cpp:2534
+#: ../src/ui/dialog/inkscape-preferences.cpp:528 ../src/verbs.cpp:2540
 #: ../share/extensions/lorem_ipsum.inx.h:5
 #: ../share/extensions/render_alphabetsoup.inx.h:5
+#: ../share/extensions/render_barcode_datamatrix.inx.h:6
 #: ../share/extensions/text_braille.inx.h:2
 #: ../share/extensions/text_flipcase.inx.h:1
 #: ../share/extensions/text_lowercase.inx.h:1
@@ -3676,7 +3677,7 @@ msgstr ""
 msgid "Set as default"
 msgstr ""
 
-#: ../src/dialogs/text-edit.cpp:665 ../src/text-context.cpp:1493
+#: ../src/dialogs/text-edit.cpp:665 ../src/text-context.cpp:1500
 msgid "Set text style"
 msgstr ""
 
@@ -3798,8 +3799,8 @@ msgid "_Origin X:"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:398 ../src/display/canvas-grid.cpp:672
-#: ../src/ui/dialog/inkscape-preferences.cpp:989
-#: ../src/ui/dialog/inkscape-preferences.cpp:1010
+#: ../src/ui/dialog/inkscape-preferences.cpp:994
+#: ../src/ui/dialog/inkscape-preferences.cpp:1015
 msgid "X coordinate of grid origin"
 msgstr ""
 
@@ -3808,8 +3809,8 @@ msgid "O_rigin Y:"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:400 ../src/display/canvas-grid.cpp:674
-#: ../src/ui/dialog/inkscape-preferences.cpp:990
-#: ../src/ui/dialog/inkscape-preferences.cpp:1011
+#: ../src/ui/dialog/inkscape-preferences.cpp:995
+#: ../src/ui/dialog/inkscape-preferences.cpp:1016
 msgid "Y coordinate of grid origin"
 msgstr ""
 
@@ -3818,29 +3819,29 @@ msgid "Spacing _Y:"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:402
-#: ../src/ui/dialog/inkscape-preferences.cpp:1013
+#: ../src/ui/dialog/inkscape-preferences.cpp:1018
 msgid "Base length of z-axis"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:404
-#: ../src/ui/dialog/inkscape-preferences.cpp:1016
-#: ../src/widgets/toolbox.cpp:3449
+#: ../src/ui/dialog/inkscape-preferences.cpp:1021
+#: ../src/widgets/toolbox.cpp:3452
 msgid "Angle X:"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:404
-#: ../src/ui/dialog/inkscape-preferences.cpp:1016
+#: ../src/ui/dialog/inkscape-preferences.cpp:1021
 msgid "Angle of x-axis"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:406
-#: ../src/ui/dialog/inkscape-preferences.cpp:1017
-#: ../src/widgets/toolbox.cpp:3528
+#: ../src/ui/dialog/inkscape-preferences.cpp:1022
+#: ../src/widgets/toolbox.cpp:3531
 msgid "Angle Z:"
 msgstr ""
 
 #: ../src/display/canvas-axonomgrid.cpp:406
-#: ../src/ui/dialog/inkscape-preferences.cpp:1017
+#: ../src/ui/dialog/inkscape-preferences.cpp:1022
 msgid "Angle of z-axis"
 msgstr ""
 
@@ -3923,12 +3924,12 @@ msgid "Spacing _X:"
 msgstr ""
 
 #: ../src/display/canvas-grid.cpp:676
-#: ../src/ui/dialog/inkscape-preferences.cpp:993
+#: ../src/ui/dialog/inkscape-preferences.cpp:998
 msgid "Distance between vertical grid lines"
 msgstr ""
 
 #: ../src/display/canvas-grid.cpp:678
-#: ../src/ui/dialog/inkscape-preferences.cpp:994
+#: ../src/ui/dialog/inkscape-preferences.cpp:999
 msgid "Distance between horizontal grid lines"
 msgstr ""
 
@@ -4106,7 +4107,7 @@ msgstr ""
 msgid "Quadrant point"
 msgstr ""
 
-#: ../src/display/snap-indicator.cpp:196 ../src/widgets/toolbox.cpp:6961
+#: ../src/display/snap-indicator.cpp:196 ../src/widgets/toolbox.cpp:7041
 msgid "Center"
 msgstr ""
 
@@ -4122,17 +4123,17 @@ msgstr ""
 msgid " to "
 msgstr ""
 
-#: ../src/document.cpp:457
+#: ../src/document.cpp:478
 #, c-format
 msgid "New document %d"
 msgstr ""
 
-#: ../src/document.cpp:489
+#: ../src/document.cpp:510
 #, c-format
 msgid "Memory document %d"
 msgstr ""
 
-#: ../src/document.cpp:644
+#: ../src/document.cpp:665
 #, c-format
 msgid "Unnamed document %d"
 msgstr ""
@@ -4161,35 +4162,35 @@ msgstr ""
 
 #. alpha of color under cursor, to show in the statusbar
 #. locale-sensitive printf is OK, since this goes to the UI, not into SVG
-#: ../src/dropper-context.cpp:302
+#: ../src/dropper-context.cpp:312
 #, c-format
 msgid " alpha %.3g"
 msgstr ""
 
 #. where the color is picked, to show in the statusbar
-#: ../src/dropper-context.cpp:304
+#: ../src/dropper-context.cpp:314
 #, c-format
 msgid ", averaged with radius %d"
 msgstr ""
 
-#: ../src/dropper-context.cpp:304
+#: ../src/dropper-context.cpp:314
 #, c-format
 msgid " under cursor"
 msgstr ""
 
 #. message, to show in the statusbar
-#: ../src/dropper-context.cpp:306
+#: ../src/dropper-context.cpp:316
 msgid "<b>Release mouse</b> to set color."
 msgstr ""
 
-#: ../src/dropper-context.cpp:306 ../src/tools-switch.cpp:216
+#: ../src/dropper-context.cpp:316 ../src/tools-switch.cpp:216
 msgid ""
 "<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to "
 "average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> "
 "to copy the color under mouse to clipboard"
 msgstr ""
 
-#: ../src/dropper-context.cpp:344
+#: ../src/dropper-context.cpp:354
 msgid "Set picked color"
 msgstr ""
 
@@ -4235,11 +4236,11 @@ msgid "[Unchanged]"
 msgstr ""
 
 #. Edit
-#: ../src/event-log.cpp:264 ../src/event-log.cpp:267 ../src/verbs.cpp:2286
+#: ../src/event-log.cpp:264 ../src/event-log.cpp:267 ../src/verbs.cpp:2292
 msgid "_Undo"
 msgstr ""
 
-#: ../src/event-log.cpp:274 ../src/event-log.cpp:278 ../src/verbs.cpp:2288
+#: ../src/event-log.cpp:274 ../src/event-log.cpp:278 ../src/verbs.cpp:2294
 msgid "_Redo"
 msgstr ""
 
@@ -4390,8 +4391,8 @@ msgstr ""
 #: ../src/libgdl/gdl-dock-placeholder.c:169
 #: ../src/live_effects/lpe-bendpath.cpp:56
 #: ../src/live_effects/lpe-patternalongpath.cpp:64
-#: ../src/widgets/toolbox.cpp:3122 ../src/widgets/toolbox.cpp:4151
-#: ../src/widgets/toolbox.cpp:4475 ../share/extensions/foldablebox.inx.h:9
+#: ../src/widgets/toolbox.cpp:3122 ../src/widgets/toolbox.cpp:4152
+#: ../src/widgets/toolbox.cpp:4478 ../share/extensions/foldablebox.inx.h:9
 #: ../share/extensions/interp_att_g.inx.h:26
 msgid "Width"
 msgstr ""
@@ -4726,18 +4727,18 @@ msgstr ""
 #: ../src/extension/internal/bitmap/modulate.cpp:41
 #: ../src/flood-context.cpp:250 ../src/widgets/sp-color-icc-selector.cpp:236
 #: ../src/widgets/sp-color-icc-selector.cpp:237
-#: ../src/widgets/sp-color-scales.cpp:426
-#: ../src/widgets/sp-color-scales.cpp:427 ../src/widgets/toolbox.cpp:4308
+#: ../src/widgets/sp-color-scales.cpp:438
+#: ../src/widgets/sp-color-scales.cpp:439 ../src/widgets/toolbox.cpp:4309
 #: ../share/extensions/color_randomize.inx.h:2
 msgid "Hue"
 msgstr ""
 
 #: ../src/extension/internal/bitmap/modulate.cpp:42
-#: ../src/flood-context.cpp:251 ../src/ui/dialog/inkscape-preferences.cpp:841
+#: ../src/flood-context.cpp:251 ../src/ui/dialog/inkscape-preferences.cpp:846
 #: ../src/widgets/sp-color-icc-selector.cpp:236
 #: ../src/widgets/sp-color-icc-selector.cpp:237
-#: ../src/widgets/sp-color-scales.cpp:429
-#: ../src/widgets/sp-color-scales.cpp:430 ../src/widgets/toolbox.cpp:4323
+#: ../src/widgets/sp-color-scales.cpp:441
+#: ../src/widgets/sp-color-scales.cpp:442 ../src/widgets/toolbox.cpp:4324
 #: ../share/extensions/color_randomize.inx.h:5
 msgid "Saturation"
 msgstr ""
@@ -4953,7 +4954,7 @@ msgstr ""
 #: ../src/extension/internal/cairo-ps-out.cpp:282
 #: ../src/extension/internal/cairo-ps-out.cpp:319
 #: ../src/extension/internal/cairo-renderer-pdf-out.cpp:219
-#: ../src/extension/internal/emf-win32-inout.cpp:2430
+#: ../src/extension/internal/emf-win32-inout.cpp:2431
 msgid "Convert texts to paths"
 msgstr ""
 
@@ -5018,39 +5019,39 @@ msgstr ""
 msgid "PDF 1.4"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2400
+#: ../src/extension/internal/emf-win32-inout.cpp:2401
 msgid "EMF Input"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2405
+#: ../src/extension/internal/emf-win32-inout.cpp:2406
 msgid "Enhanced Metafiles (*.emf)"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2406
+#: ../src/extension/internal/emf-win32-inout.cpp:2407
 msgid "Enhanced Metafiles"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2414
+#: ../src/extension/internal/emf-win32-inout.cpp:2415
 msgid "WMF Input"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2419
+#: ../src/extension/internal/emf-win32-inout.cpp:2420
 msgid "Windows Metafiles (*.wmf)"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2420
+#: ../src/extension/internal/emf-win32-inout.cpp:2421
 msgid "Windows Metafiles"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2428
+#: ../src/extension/internal/emf-win32-inout.cpp:2429
 msgid "EMF Output"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2434
+#: ../src/extension/internal/emf-win32-inout.cpp:2435
 msgid "Enhanced Metafile (*.emf)"
 msgstr ""
 
-#: ../src/extension/internal/emf-win32-inout.cpp:2435
+#: ../src/extension/internal/emf-win32-inout.cpp:2436
 msgid "Enhanced Metafile"
 msgstr ""
 
@@ -5086,7 +5087,7 @@ msgstr ""
 #: ../src/extension/internal/filter/filter.cpp:214
 #: ../src/extension/internal/filter/filter-file.cpp:148
 #: ../src/extension/internal/filter/snow.h:38
-#: ../src/ui/dialog/inkscape-preferences.cpp:744
+#: ../src/ui/dialog/inkscape-preferences.cpp:749
 msgid "Filters"
 msgstr ""
 
@@ -5182,9 +5183,11 @@ msgstr ""
 #: ../share/extensions/printing-marks.inx.h:14
 #: ../share/extensions/render_alphabetsoup.inx.h:3
 #: ../share/extensions/render_barcode.inx.h:5
+#: ../share/extensions/render_barcode_datamatrix.inx.h:3
 #: ../share/extensions/rtree.inx.h:4 ../share/extensions/spirograph.inx.h:6
 #: ../share/extensions/svgcalendar.inx.h:22
 #: ../share/extensions/triangle.inx.h:10
+#: ../share/extensions/wireframe_sphere.inx.h:5
 msgid "Render"
 msgstr ""
 
@@ -5328,27 +5331,27 @@ msgstr ""
 msgid "very fine"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:753
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:754
 msgid "PDF Input"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:758
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:759
 msgid "Adobe PDF (*.pdf)"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:759
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:760
 msgid "Adobe Portable Document Format"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:766
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:767
 msgid "AI Input"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:771
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:772
 msgid "Adobe Illustrator 9.0 and above (*.ai)"
 msgstr ""
 
-#: ../src/extension/internal/pdfinput/pdf-input.cpp:772
+#: ../src/extension/internal/pdfinput/pdf-input.cpp:773
 msgid "Open files saved in Adobe Illustrator 9.0 and newer versions"
 msgstr ""
 
@@ -5576,7 +5579,7 @@ msgstr ""
 msgid "Select file to export to"
 msgstr ""
 
-#: ../src/file.cpp:1473 ../src/verbs.cpp:2275
+#: ../src/file.cpp:1473 ../src/verbs.cpp:2281
 msgid "Import From Open Clip Art Library"
 msgstr ""
 
@@ -5695,7 +5698,7 @@ msgid "Luminance to Alpha"
 msgstr ""
 
 #. File
-#: ../src/filter-enums.cpp:72 ../src/verbs.cpp:2252
+#: ../src/filter-enums.cpp:72 ../src/verbs.cpp:2258
 msgid "Default"
 msgstr ""
 
@@ -5743,7 +5746,7 @@ msgstr ""
 msgid "Gamma"
 msgstr ""
 
-#: ../src/filter-enums.cpp:94 ../src/selection-chemistry.cpp:316
+#: ../src/filter-enums.cpp:94 ../src/selection-chemistry.cpp:317
 #: ../src/widgets/gradient-selector.cpp:139
 msgid "Duplicate"
 msgstr ""
@@ -5759,9 +5762,9 @@ msgstr ""
 #: ../src/ui/dialog/inkscape-preferences.cpp:259
 #: ../src/ui/dialog/inkscape-preferences.cpp:422
 #: ../src/ui/dialog/inkscape-preferences.cpp:565
-#: ../src/ui/dialog/inkscape-preferences.cpp:1162
-#: ../src/ui/dialog/inkscape-preferences.cpp:1227 ../src/verbs.cpp:2249
-#: ../src/widgets/stroke-style.cpp:765 ../src/widgets/toolbox.cpp:3914
+#: ../src/ui/dialog/inkscape-preferences.cpp:1167
+#: ../src/ui/dialog/inkscape-preferences.cpp:1232 ../src/verbs.cpp:2255
+#: ../src/widgets/stroke-style.cpp:765 ../src/widgets/toolbox.cpp:3917
 #: ../share/extensions/grid_polar.inx.h:16
 #: ../share/extensions/guides_creator.inx.h:15
 #: ../share/extensions/scour.inx.h:7
@@ -5770,22 +5773,22 @@ msgstr ""
 
 #: ../src/filter-enums.cpp:102 ../src/flood-context.cpp:247
 #: ../src/widgets/sp-color-icc-selector.cpp:234
-#: ../src/widgets/sp-color-scales.cpp:400
-#: ../src/widgets/sp-color-scales.cpp:401
+#: ../src/widgets/sp-color-scales.cpp:412
+#: ../src/widgets/sp-color-scales.cpp:413
 msgid "Red"
 msgstr ""
 
 #: ../src/filter-enums.cpp:103 ../src/flood-context.cpp:248
 #: ../src/widgets/sp-color-icc-selector.cpp:234
-#: ../src/widgets/sp-color-scales.cpp:403
-#: ../src/widgets/sp-color-scales.cpp:404
+#: ../src/widgets/sp-color-scales.cpp:415
+#: ../src/widgets/sp-color-scales.cpp:416
 msgid "Green"
 msgstr ""
 
 #: ../src/filter-enums.cpp:104 ../src/flood-context.cpp:249
 #: ../src/widgets/sp-color-icc-selector.cpp:234
-#: ../src/widgets/sp-color-scales.cpp:406
-#: ../src/widgets/sp-color-scales.cpp:407
+#: ../src/widgets/sp-color-scales.cpp:418
+#: ../src/widgets/sp-color-scales.cpp:419
 msgid "Blue"
 msgstr ""
 
@@ -5822,13 +5825,13 @@ msgid "Visible Colors"
 msgstr ""
 
 #: ../src/flood-context.cpp:252 ../src/widgets/sp-color-icc-selector.cpp:237
-#: ../src/widgets/sp-color-scales.cpp:432
-#: ../src/widgets/sp-color-scales.cpp:433 ../src/widgets/toolbox.cpp:4338
+#: ../src/widgets/sp-color-scales.cpp:444
+#: ../src/widgets/sp-color-scales.cpp:445 ../src/widgets/toolbox.cpp:4339
 #: ../share/extensions/color_randomize.inx.h:3
 msgid "Lightness"
 msgstr ""
 
-#: ../src/flood-context.cpp:265 ../src/ui/dialog/inkscape-preferences.cpp:1083
+#: ../src/flood-context.cpp:265 ../src/ui/dialog/inkscape-preferences.cpp:1088
 msgid "Small"
 msgstr ""
 
@@ -5836,7 +5839,7 @@ msgstr ""
 msgid "Medium"
 msgstr ""
 
-#: ../src/flood-context.cpp:267 ../src/ui/dialog/inkscape-preferences.cpp:1083
+#: ../src/flood-context.cpp:267 ../src/ui/dialog/inkscape-preferences.cpp:1088
 msgid "Large"
 msgstr ""
 
@@ -6064,7 +6067,7 @@ msgstr ""
 msgid "Delete gradient stop(s)"
 msgstr ""
 
-#: ../src/helper/units.cpp:37 ../src/live_effects/lpe-ruler.cpp:43
+#: ../src/helper/units.cpp:37 ../src/live_effects/lpe-ruler.cpp:44
 #: ../share/extensions/foldablebox.inx.h:8
 #: ../share/extensions/interp_att_g.inx.h:24
 #: ../share/extensions/printing-marks.inx.h:19
@@ -6074,7 +6077,7 @@ msgstr ""
 #. Add the units menu.
 #: ../src/helper/units.cpp:37 ../src/widgets/select-toolbar.cpp:504
 #: ../src/widgets/toolbox.cpp:1530 ../src/widgets/toolbox.cpp:3183
-#: ../src/widgets/toolbox.cpp:5879 ../src/widgets/toolbox.cpp:7635
+#: ../src/widgets/toolbox.cpp:5882 ../src/widgets/toolbox.cpp:7715
 msgid "Units"
 msgstr ""
 
@@ -6268,95 +6271,95 @@ msgstr ""
 
 #. sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
 #. checkitem_toggled, checkitem_update, 0);
-#: ../src/interface.cpp:868
+#: ../src/interface.cpp:870
 msgid "Commands Bar"
 msgstr ""
 
-#: ../src/interface.cpp:868
+#: ../src/interface.cpp:870
 msgid "Show or hide the Commands bar (under the menu)"
 msgstr ""
 
-#: ../src/interface.cpp:870
+#: ../src/interface.cpp:872
 msgid "Snap Controls Bar"
 msgstr ""
 
-#: ../src/interface.cpp:870
+#: ../src/interface.cpp:872
 msgid "Show or hide the snapping controls"
 msgstr ""
 
-#: ../src/interface.cpp:872
+#: ../src/interface.cpp:874
 msgid "Tool Controls Bar"
 msgstr ""
 
-#: ../src/interface.cpp:872
+#: ../src/interface.cpp:874
 msgid "Show or hide the Tool Controls bar"
 msgstr ""
 
-#: ../src/interface.cpp:874
+#: ../src/interface.cpp:876
 msgid "_Toolbox"
 msgstr ""
 
-#: ../src/interface.cpp:874
+#: ../src/interface.cpp:876
 msgid "Show or hide the main toolbox (on the left)"
 msgstr ""
 
-#: ../src/interface.cpp:880
+#: ../src/interface.cpp:882
 msgid "_Palette"
 msgstr ""
 
-#: ../src/interface.cpp:880
+#: ../src/interface.cpp:882
 msgid "Show or hide the color palette"
 msgstr ""
 
-#: ../src/interface.cpp:882
+#: ../src/interface.cpp:884
 msgid "_Statusbar"
 msgstr ""
 
-#: ../src/interface.cpp:882
+#: ../src/interface.cpp:884
 msgid "Show or hide the statusbar (at the bottom of the window)"
 msgstr ""
 
-#: ../src/interface.cpp:956
+#: ../src/interface.cpp:958
 #, c-format
 msgid "Verb \"%s\" Unknown"
 msgstr ""
 
-#: ../src/interface.cpp:998
+#: ../src/interface.cpp:1000
 msgid "Open _Recent"
 msgstr ""
 
 #. TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number.
-#: ../src/interface.cpp:1099
+#: ../src/interface.cpp:1101
 #, c-format
 msgid "Enter group #%s"
 msgstr ""
 
-#: ../src/interface.cpp:1110
+#: ../src/interface.cpp:1112
 msgid "Go to parent"
 msgstr ""
 
-#: ../src/interface.cpp:1201 ../src/interface.cpp:1287
-#: ../src/interface.cpp:1390 ../src/ui/widget/selected-style.cpp:468
+#: ../src/interface.cpp:1203 ../src/interface.cpp:1289
+#: ../src/interface.cpp:1392 ../src/ui/widget/selected-style.cpp:468
 msgid "Drop color"
 msgstr ""
 
-#: ../src/interface.cpp:1240 ../src/interface.cpp:1350
+#: ../src/interface.cpp:1242 ../src/interface.cpp:1352
 msgid "Drop color on gradient"
 msgstr ""
 
-#: ../src/interface.cpp:1403
+#: ../src/interface.cpp:1405
 msgid "Could not parse SVG data"
 msgstr ""
 
-#: ../src/interface.cpp:1442
+#: ../src/interface.cpp:1444
 msgid "Drop SVG"
 msgstr ""
 
-#: ../src/interface.cpp:1498
+#: ../src/interface.cpp:1500
 msgid "Drop bitmap image"
 msgstr ""
 
-#: ../src/interface.cpp:1590
+#: ../src/interface.cpp:1592
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do "
@@ -6365,7 +6368,7 @@ msgid ""
 "The file already exists in \"%s\". Replacing it will overwrite its contents."
 msgstr ""
 
-#: ../src/interface.cpp:1597 ../share/extensions/web-set-att.inx.h:5
+#: ../src/interface.cpp:1599 ../share/extensions/web-set-att.inx.h:5
 #: ../share/extensions/web-transmit-att.inx.h:5
 msgid "Replace"
 msgstr ""
@@ -6663,7 +6666,7 @@ msgstr ""
 #: ../src/ui/dialog/align-and-distribute.cpp:919
 #: ../src/ui/dialog/document-properties.cpp:118
 #: ../src/ui/dialog/filedialogimpl-gtkmm.cpp:1410
-#: ../src/widgets/desktop-widget.cpp:1572
+#: ../src/widgets/desktop-widget.cpp:1580
 msgid "Page"
 msgstr ""
 
@@ -6824,7 +6827,7 @@ msgstr ""
 msgid "Dockitem which 'owns' this tablabel"
 msgstr ""
 
-#: ../src/libnrtype/FontFactory.cpp:806
+#: ../src/libnrtype/FontFactory.cpp:821
 msgid "Ignoring font without family that will crash Pango"
 msgstr ""
 
@@ -7534,19 +7537,19 @@ msgstr ""
 msgid "Both"
 msgstr ""
 
-#: ../src/live_effects/lpe-ruler.cpp:35 ../src/widgets/toolbox.cpp:5387
+#: ../src/live_effects/lpe-ruler.cpp:35 ../src/widgets/toolbox.cpp:5390
 msgid "Start"
 msgstr ""
 
-#: ../src/live_effects/lpe-ruler.cpp:36 ../src/widgets/toolbox.cpp:5400
+#: ../src/live_effects/lpe-ruler.cpp:36 ../src/widgets/toolbox.cpp:5403
 msgid "End"
 msgstr ""
 
-#: ../src/live_effects/lpe-ruler.cpp:44
+#: ../src/live_effects/lpe-ruler.cpp:43
 msgid "Mark distance"
 msgstr ""
 
-#: ../src/live_effects/lpe-ruler.cpp:44
+#: ../src/live_effects/lpe-ruler.cpp:43
 msgid "Distance between successive ruler marks"
 msgstr ""
 
@@ -7686,7 +7689,7 @@ msgstr ""
 msgid "How many construction lines (tangents) to draw"
 msgstr ""
 
-#: ../src/live_effects/lpe-sketch.cpp:55 ../src/selection-chemistry.cpp:1516
+#: ../src/live_effects/lpe-sketch.cpp:55 ../src/selection-chemistry.cpp:1539
 #: ../src/seltrans.cpp:531 ../src/ui/dialog/transformation.cpp:738
 #: ../share/extensions/interp_att_g.inx.h:16
 #: ../share/extensions/render_alphabetsoup.inx.h:4
@@ -8069,7 +8072,7 @@ msgstr ""
 msgid "Start Inkscape in interactive shell mode."
 msgstr ""
 
-#: ../src/main.cpp:762 ../src/main.cpp:1088
+#: ../src/main.cpp:766 ../src/main.cpp:1092
 msgid ""
 "[OPTIONS...] [FILE...]\n"
 "\n"
@@ -8086,84 +8089,82 @@ msgstr ""
 msgid "_New"
 msgstr ""
 
-#. TODO look at some dynamic option for changing the menu tree:
-#. "       <verb verb-id=\"DialogInput2\" />\n"
-#: ../src/menus-skeleton.h:49 ../src/verbs.cpp:2498 ../src/verbs.cpp:2504
+#: ../src/menus-skeleton.h:48 ../src/verbs.cpp:2504 ../src/verbs.cpp:2510
 msgid "_Edit"
 msgstr ""
 
-#: ../src/menus-skeleton.h:59 ../src/verbs.cpp:2298
+#: ../src/menus-skeleton.h:58 ../src/verbs.cpp:2304
 msgid "Paste Si_ze"
 msgstr ""
 
-#: ../src/menus-skeleton.h:71
+#: ../src/menus-skeleton.h:70
 msgid "Clo_ne"
 msgstr ""
 
-#: ../src/menus-skeleton.h:91
+#: ../src/menus-skeleton.h:90
 msgid "_View"
 msgstr ""
 
-#: ../src/menus-skeleton.h:92
+#: ../src/menus-skeleton.h:91
 msgid "_Zoom"
 msgstr ""
 
-#: ../src/menus-skeleton.h:108
+#: ../src/menus-skeleton.h:107
 msgid "_Display mode"
 msgstr ""
 
-#: ../src/menus-skeleton.h:120
+#: ../src/menus-skeleton.h:121
 msgid "Show/Hide"
 msgstr ""
 
 #. "       <verb verb-id=\"DialogScript\" />\n"
 #. Not quite ready to be in the menus.
 #. "       <verb verb-id=\"FocusToggle\" />\n"
-#: ../src/menus-skeleton.h:139
+#: ../src/menus-skeleton.h:140
 msgid "_Layer"
 msgstr ""
 
-#: ../src/menus-skeleton.h:159
+#: ../src/menus-skeleton.h:160
 msgid "_Object"
 msgstr ""
 
-#: ../src/menus-skeleton.h:166
+#: ../src/menus-skeleton.h:167
 msgid "Cli_p"
 msgstr ""
 
-#: ../src/menus-skeleton.h:170
+#: ../src/menus-skeleton.h:171
 msgid "Mas_k"
 msgstr ""
 
-#: ../src/menus-skeleton.h:174
+#: ../src/menus-skeleton.h:175
 msgid "Patter_n"
 msgstr ""
 
-#: ../src/menus-skeleton.h:198
+#: ../src/menus-skeleton.h:199
 msgid "_Path"
 msgstr ""
 
-#: ../src/menus-skeleton.h:225
+#: ../src/menus-skeleton.h:226
 msgid "_Text"
 msgstr ""
 
-#: ../src/menus-skeleton.h:244
+#: ../src/menus-skeleton.h:245
 msgid "Filter_s"
 msgstr ""
 
-#: ../src/menus-skeleton.h:250
+#: ../src/menus-skeleton.h:251
 msgid "Exte_nsions"
 msgstr ""
 
-#: ../src/menus-skeleton.h:257
+#: ../src/menus-skeleton.h:258
 msgid "Whiteboa_rd"
 msgstr ""
 
-#: ../src/menus-skeleton.h:261
+#: ../src/menus-skeleton.h:262
 msgid "_Help"
 msgstr ""
 
-#: ../src/menus-skeleton.h:265
+#: ../src/menus-skeleton.h:266
 msgid "Tutorials"
 msgstr ""
 
@@ -8652,11 +8653,11 @@ msgstr ""
 msgid "Drawing finished"
 msgstr ""
 
-#: ../src/persp3d.cpp:335
+#: ../src/persp3d.cpp:345
 msgid "Toggle vanishing point"
 msgstr ""
 
-#: ../src/persp3d.cpp:346
+#: ../src/persp3d.cpp:356
 msgid "Toggle multiple vanishing points"
 msgstr ""
 
@@ -8990,54 +8991,54 @@ msgstr ""
 msgid "Selected object is not a group. Cannot enter."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:195
+#: ../src/selection-chemistry.cpp:196
 msgid "Delete text"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:203
+#: ../src/selection-chemistry.cpp:204
 msgid "<b>Nothing</b> was deleted."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:221 ../src/text-context.cpp:995
+#: ../src/selection-chemistry.cpp:222 ../src/text-context.cpp:1002
 #: ../src/ui/dialog/swatches.cpp:471 ../src/widgets/toolbox.cpp:1330
-#: ../src/widgets/toolbox.cpp:5971
+#: ../src/widgets/toolbox.cpp:5974
 msgid "Delete"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:249
+#: ../src/selection-chemistry.cpp:250
 msgid "Select <b>object(s)</b> to duplicate."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:341
+#: ../src/selection-chemistry.cpp:342
 msgid "Delete all"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:464
+#: ../src/selection-chemistry.cpp:465
 msgid "Select <b>some objects</b> to group."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:537 ../src/selection-describer.cpp:53
+#: ../src/selection-chemistry.cpp:538 ../src/selection-describer.cpp:53
 msgid "Group"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:551
+#: ../src/selection-chemistry.cpp:552
 msgid "Select a <b>group</b> to ungroup."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:592
+#: ../src/selection-chemistry.cpp:593
 msgid "<b>No groups</b> to ungroup in the selection."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:598 ../src/sp-item-group.cpp:516
+#: ../src/selection-chemistry.cpp:599 ../src/sp-item-group.cpp:496
 msgid "Ungroup"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:688
+#: ../src/selection-chemistry.cpp:689
 msgid "Select <b>object(s)</b> to raise."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:694 ../src/selection-chemistry.cpp:756
-#: ../src/selection-chemistry.cpp:790 ../src/selection-chemistry.cpp:854
+#: ../src/selection-chemistry.cpp:695 ../src/selection-chemistry.cpp:757
+#: ../src/selection-chemistry.cpp:791 ../src/selection-chemistry.cpp:855
 msgid ""
 "You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."
 msgstr ""
@@ -9045,302 +9046,302 @@ msgstr ""
 #. TRANSLATORS: only translate "string" in "context|string".
 #. For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
 #. "Raise" means "to raise an object" in the undo history
-#: ../src/selection-chemistry.cpp:736
+#: ../src/selection-chemistry.cpp:737
 msgid "undo_action|Raise"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:748
+#: ../src/selection-chemistry.cpp:749
 msgid "Select <b>object(s)</b> to raise to top."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:771
+#: ../src/selection-chemistry.cpp:772
 msgid "Raise to top"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:784
+#: ../src/selection-chemistry.cpp:785
 msgid "Select <b>object(s)</b> to lower."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:834
+#: ../src/selection-chemistry.cpp:835
 msgid "Lower"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:846
+#: ../src/selection-chemistry.cpp:847
 msgid "Select <b>object(s)</b> to lower to bottom."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:881
+#: ../src/selection-chemistry.cpp:882
 msgid "Lower to bottom"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:888
+#: ../src/selection-chemistry.cpp:889
 msgid "Nothing to undo."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:895
+#: ../src/selection-chemistry.cpp:896
 msgid "Nothing to redo."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:955
+#: ../src/selection-chemistry.cpp:956
 msgid "Paste"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:962
+#: ../src/selection-chemistry.cpp:963
 msgid "Paste style"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:971
+#: ../src/selection-chemistry.cpp:972
 msgid "Paste live path effect"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:991
+#: ../src/selection-chemistry.cpp:992
 msgid "Select <b>object(s)</b> to remove live path effects from."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1003
+#: ../src/selection-chemistry.cpp:1004
 msgid "Remove live path effect"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1014
+#: ../src/selection-chemistry.cpp:1015
 msgid "Select <b>object(s)</b> to remove filters from."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1024
+#: ../src/selection-chemistry.cpp:1025
 #: ../src/ui/dialog/filter-effects-dialog.cpp:1336
 msgid "Remove filter"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1033
+#: ../src/selection-chemistry.cpp:1034
 msgid "Paste size"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1041
+#: ../src/selection-chemistry.cpp:1042
 msgid "Paste size separately"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1050
+#: ../src/selection-chemistry.cpp:1051
 msgid "Select <b>object(s)</b> to move to the layer above."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1076
+#: ../src/selection-chemistry.cpp:1077
 msgid "Raise to next layer"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1083
+#: ../src/selection-chemistry.cpp:1084
 msgid "No more layers above."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1095
+#: ../src/selection-chemistry.cpp:1096
 msgid "Select <b>object(s)</b> to move to the layer below."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1121
+#: ../src/selection-chemistry.cpp:1122
 msgid "Lower to previous layer"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1128
+#: ../src/selection-chemistry.cpp:1129
 msgid "No more layers below."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1315
+#: ../src/selection-chemistry.cpp:1338
 msgid "Remove transform"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1418
+#: ../src/selection-chemistry.cpp:1441
 msgid "Rotate 90&#176; CCW"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1418
+#: ../src/selection-chemistry.cpp:1441
 msgid "Rotate 90&#176; CW"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1439 ../src/seltrans.cpp:534
+#: ../src/selection-chemistry.cpp:1462 ../src/seltrans.cpp:534
 #: ../src/ui/dialog/transformation.cpp:760
 msgid "Rotate"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1486
+#: ../src/selection-chemistry.cpp:1509
 msgid "Rotate by pixels"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1541
+#: ../src/selection-chemistry.cpp:1564
 msgid "Scale by whole factor"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1556
+#: ../src/selection-chemistry.cpp:1579
 msgid "Move vertically"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1559
+#: ../src/selection-chemistry.cpp:1582
 msgid "Move horizontally"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1562 ../src/selection-chemistry.cpp:1588
+#: ../src/selection-chemistry.cpp:1585 ../src/selection-chemistry.cpp:1611
 #: ../src/seltrans.cpp:528 ../src/ui/dialog/transformation.cpp:681
 msgid "Move"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1582
+#: ../src/selection-chemistry.cpp:1605
 msgid "Move vertically by pixels"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1585
+#: ../src/selection-chemistry.cpp:1608
 msgid "Move horizontally by pixels"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1713
+#: ../src/selection-chemistry.cpp:1736
 msgid "The selection has no applied path effect."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1760
+#: ../src/selection-chemistry.cpp:1783
 msgid "The selection has no applied clip path."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1762
+#: ../src/selection-chemistry.cpp:1785
 msgid "The selection has no applied mask."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1919
+#: ../src/selection-chemistry.cpp:1942
 msgid "action|Clone"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1935
+#: ../src/selection-chemistry.cpp:1958
 msgid "Select <b>clones</b> to relink."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1942
+#: ../src/selection-chemistry.cpp:1965
 msgid "Copy an <b>object</b> to clipboard to relink clones to."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1966
+#: ../src/selection-chemistry.cpp:1989
 msgid "<b>No clones to relink</b> in the selection."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1969
+#: ../src/selection-chemistry.cpp:1992
 msgid "Relink clone"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:1983
+#: ../src/selection-chemistry.cpp:2006
 msgid "Select <b>clones</b> to unlink."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2032
+#: ../src/selection-chemistry.cpp:2055
 msgid "<b>No clones to unlink</b> in the selection."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2036
+#: ../src/selection-chemistry.cpp:2059
 msgid "Unlink clone"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2049
+#: ../src/selection-chemistry.cpp:2072
 msgid ""
 "Select a <b>clone</b> to go to its original. Select a <b>linked offset</b> "
 "to go to its source. Select a <b>text on path</b> to go to the path. Select "
 "a <b>flowed text</b> to go to its frame."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2072
+#: ../src/selection-chemistry.cpp:2095
 msgid ""
 "<b>Cannot find</b> the object to select (orphaned clone, offset, textpath, "
 "flowed text?)"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2078
+#: ../src/selection-chemistry.cpp:2101
 msgid ""
 "The object you're trying to select is <b>not visible</b> (it is in &lt;"
 "defs&gt;)"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2124
+#: ../src/selection-chemistry.cpp:2147
 msgid "Select <b>object(s)</b> to convert to marker."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2192
+#: ../src/selection-chemistry.cpp:2215
 msgid "Objects to marker"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2220
+#: ../src/selection-chemistry.cpp:2243
 msgid "Select <b>object(s)</b> to convert to guides."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2232
+#: ../src/selection-chemistry.cpp:2255
 msgid "Objects to guides"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2248
+#: ../src/selection-chemistry.cpp:2271
 msgid "Select <b>object(s)</b> to convert to pattern."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2336
+#: ../src/selection-chemistry.cpp:2359
 msgid "Objects to pattern"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2352
+#: ../src/selection-chemistry.cpp:2375
 msgid "Select an <b>object with pattern fill</b> to extract objects from."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2405
+#: ../src/selection-chemistry.cpp:2428
 msgid "<b>No pattern fills</b> in the selection."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2408
+#: ../src/selection-chemistry.cpp:2431
 msgid "Pattern to objects"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2493
+#: ../src/selection-chemistry.cpp:2516
 msgid "Select <b>object(s)</b> to make a bitmap copy."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2497
+#: ../src/selection-chemistry.cpp:2520
 msgid "Rendering bitmap..."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2676
+#: ../src/selection-chemistry.cpp:2699
 msgid "Create bitmap"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2708
+#: ../src/selection-chemistry.cpp:2731
 msgid "Select <b>object(s)</b> to create clippath or mask from."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2711
+#: ../src/selection-chemistry.cpp:2734
 msgid "Select mask object and <b>object(s)</b> to apply clippath or mask to."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2818
+#: ../src/selection-chemistry.cpp:2841
 msgid "Set clipping path"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2820
+#: ../src/selection-chemistry.cpp:2843
 msgid "Set mask"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2833
+#: ../src/selection-chemistry.cpp:2856
 msgid "Select <b>object(s)</b> to remove clippath or mask from."
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2906
+#: ../src/selection-chemistry.cpp:2929
 msgid "Release clipping path"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2908
+#: ../src/selection-chemistry.cpp:2931
 msgid "Release mask"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2924
+#: ../src/selection-chemistry.cpp:2947
 msgid "Select <b>object(s)</b> to fit canvas to."
 msgstr ""
 
 #. Fit Page
-#: ../src/selection-chemistry.cpp:2944 ../src/verbs.cpp:2739
+#: ../src/selection-chemistry.cpp:2967 ../src/verbs.cpp:2749
 msgid "Fit Page to Selection"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2969 ../src/verbs.cpp:2741
+#: ../src/selection-chemistry.cpp:2992 ../src/verbs.cpp:2751
 msgid "Fit Page to Drawing"
 msgstr ""
 
-#: ../src/selection-chemistry.cpp:2985 ../src/verbs.cpp:2743
+#: ../src/selection-chemistry.cpp:3008 ../src/verbs.cpp:2753
 msgid "Fit Page to Selection or Drawing"
 msgstr ""
 
@@ -9357,8 +9358,8 @@ msgstr ""
 
 #. Ellipse
 #: ../src/selection-describer.cpp:49 ../src/selection-describer.cpp:76
-#: ../src/ui/dialog/inkscape-preferences.cpp:480 ../src/verbs.cpp:2522
-#: ../src/widgets/toolbox.cpp:3917
+#: ../src/ui/dialog/inkscape-preferences.cpp:480 ../src/verbs.cpp:2528
+#: ../src/widgets/toolbox.cpp:3920
 msgid "Ellipse"
 msgstr ""
 
@@ -9384,13 +9385,13 @@ msgstr ""
 
 #. Rectangle
 #: ../src/selection-describer.cpp:65
-#: ../src/ui/dialog/inkscape-preferences.cpp:470 ../src/verbs.cpp:2518
+#: ../src/ui/dialog/inkscape-preferences.cpp:470 ../src/verbs.cpp:2524
 msgid "Rectangle"
 msgstr ""
 
 #. 3D box
 #: ../src/selection-describer.cpp:67
-#: ../src/ui/dialog/inkscape-preferences.cpp:475 ../src/verbs.cpp:2520
+#: ../src/ui/dialog/inkscape-preferences.cpp:475 ../src/verbs.cpp:2526
 msgid "3D Box"
 msgstr ""
 
@@ -9407,13 +9408,13 @@ msgstr ""
 
 #. Spiral
 #: ../src/selection-describer.cpp:80
-#: ../src/ui/dialog/inkscape-preferences.cpp:488 ../src/verbs.cpp:2526
+#: ../src/ui/dialog/inkscape-preferences.cpp:488 ../src/verbs.cpp:2532
 msgid "Spiral"
 msgstr ""
 
 #. Star
 #: ../src/selection-describer.cpp:82
-#: ../src/ui/dialog/inkscape-preferences.cpp:484 ../src/verbs.cpp:2524
+#: ../src/ui/dialog/inkscape-preferences.cpp:484 ../src/verbs.cpp:2530
 #: ../src/widgets/toolbox.cpp:2760
 msgid "Star"
 msgstr ""
@@ -9484,7 +9485,8 @@ msgid "Use <b>Shift+D</b> to look up frame"
 msgstr ""
 
 #. this is only used with 2 or more objects
-#: ../src/selection-describer.cpp:211 ../src/tweak-context.cpp:202
+#: ../src/selection-describer.cpp:211 ../src/spray-context.cpp:284
+#: ../src/tweak-context.cpp:202
 #, c-format
 msgid "<b>%i</b> object selected"
 msgid_plural "<b>%i</b> objects selected"
@@ -9645,17 +9647,22 @@ msgstr ""
 msgid "Flow excluded region"
 msgstr ""
 
-#: ../src/sp-flowtext.cpp:376
+#: ../src/sp-flowtext.cpp:378 ../src/sp-text.cpp:427
+#: ../src/text-context.cpp:1604
+msgid " [truncated]"
+msgstr ""
+
+#: ../src/sp-flowtext.cpp:382
 #, c-format
-msgid "<b>Flowed text</b> (%d character)"
-msgid_plural "<b>Flowed text</b> (%d characters)"
+msgid "<b>Flowed text</b> (%d character%s)"
+msgid_plural "<b>Flowed text</b> (%d characters%s)"
 msgstr[0] ""
 msgstr[1] ""
 
-#: ../src/sp-flowtext.cpp:378
+#: ../src/sp-flowtext.cpp:384
 #, c-format
-msgid "<b>Linked flowed text</b> (%d character)"
-msgid_plural "<b>Linked flowed text</b> (%d characters)"
+msgid "<b>Linked flowed text</b> (%d character%s)"
+msgid_plural "<b>Linked flowed text</b> (%d characters%s)"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -9684,16 +9691,16 @@ msgstr ""
 msgid "at %d degrees, through (%s,%s)"
 msgstr ""
 
-#: ../src/sp-image.cpp:1128
+#: ../src/sp-image.cpp:1135
 msgid "embedded"
 msgstr ""
 
-#: ../src/sp-image.cpp:1136
+#: ../src/sp-image.cpp:1143
 #, c-format
 msgid "<b>Image with bad reference</b>: %s"
 msgstr ""
 
-#: ../src/sp-image.cpp:1137
+#: ../src/sp-image.cpp:1144
 #, c-format
 msgid "<b>Image</b> %d &#215; %d: %s"
 msgstr ""
@@ -9740,7 +9747,7 @@ msgstr ""
 msgid "%s; <i>filtered</i>"
 msgstr ""
 
-#: ../src/sp-item-group.cpp:761
+#: ../src/sp-item-group.cpp:741
 #, c-format
 msgid "<b>Group</b> of <b>%d</b> object"
 msgid_plural "<b>Group</b> of <b>%d</b> objects"
@@ -9953,14 +9960,14 @@ msgstr[1] ""
 msgid "&lt;no name found&gt;"
 msgstr ""
 
-#: ../src/sp-text.cpp:425
+#: ../src/sp-text.cpp:431
 #, c-format
-msgid "<b>Text on path</b> (%s, %s)"
+msgid "<b>Text on path</b>%s (%s, %s)"
 msgstr ""
 
-#: ../src/sp-text.cpp:426
+#: ../src/sp-text.cpp:432
 #, c-format
-msgid "<b>Text</b> (%s, %s)"
+msgid "<b>Text</b>%s (%s, %s)"
 msgstr ""
 
 #: ../src/sp-tref.cpp:368
@@ -9995,6 +10002,51 @@ msgstr ""
 msgid "<b>Orphaned clone</b>"
 msgstr ""
 
+#: ../src/spray-context.cpp:286 ../src/tweak-context.cpp:204
+#, c-format
+msgid "<b>Nothing</b> selected"
+msgstr ""
+
+#: ../src/spray-context.cpp:292
+#, c-format
+msgid ""
+"%s. Drag, click or scroll to spray <b>copies</b> of the initial selection"
+msgstr ""
+
+#: ../src/spray-context.cpp:295
+#, c-format
+msgid ""
+"%s. Drag, click or scroll to spray <b>clones</b> of the initial selection"
+msgstr ""
+
+#: ../src/spray-context.cpp:298
+#, c-format
+msgid ""
+"%s. Drag, click or scroll to spray in a <b>single path</b> of the initial "
+"selection"
+msgstr ""
+
+#: ../src/spray-context.cpp:301
+#, c-format
+msgid "%s. Modify <b>spray</b> options"
+msgstr ""
+
+#: ../src/spray-context.cpp:926
+msgid "<b>Nothing selected!</b> Select objects to spray."
+msgstr ""
+
+#: ../src/spray-context.cpp:1034 ../src/widgets/toolbox.cpp:4528
+msgid "Spray with copies"
+msgstr ""
+
+#: ../src/spray-context.cpp:1038 ../src/widgets/toolbox.cpp:4535
+msgid "Spray with clones"
+msgstr ""
+
+#: ../src/spray-context.cpp:1042
+msgid "Spray in single path"
+msgstr ""
+
 #: ../src/star-context.cpp:333
 msgid "<b>Ctrl</b>: snap angle; keep rays radial"
 msgstr ""
@@ -10035,7 +10087,7 @@ msgstr ""
 msgid "The flowed text(s) must be <b>visible</b> in order to be put on a path."
 msgstr ""
 
-#: ../src/text-chemistry.cpp:192 ../src/verbs.cpp:2374
+#: ../src/text-chemistry.cpp:192 ../src/verbs.cpp:2380
 msgid "Put text on path"
 msgstr ""
 
@@ -10047,7 +10099,7 @@ msgstr ""
 msgid "<b>No texts-on-paths</b> in the selection."
 msgstr ""
 
-#: ../src/text-chemistry.cpp:229 ../src/verbs.cpp:2376
+#: ../src/text-chemistry.cpp:229 ../src/verbs.cpp:2382
 msgid "Remove text from path"
 msgstr ""
 
@@ -10093,146 +10145,146 @@ msgstr ""
 msgid "<b>No flowed text(s)</b> to convert in the selection."
 msgstr ""
 
-#: ../src/text-context.cpp:441
+#: ../src/text-context.cpp:448
 msgid "<b>Click</b> to edit the text, <b>drag</b> to select part of the text."
 msgstr ""
 
-#: ../src/text-context.cpp:443
+#: ../src/text-context.cpp:450
 msgid ""
 "<b>Click</b> to edit the flowed text, <b>drag</b> to select part of the text."
 msgstr ""
 
-#: ../src/text-context.cpp:498
+#: ../src/text-context.cpp:505
 msgid "Create text"
 msgstr ""
 
-#: ../src/text-context.cpp:522
+#: ../src/text-context.cpp:529
 msgid "Non-printable character"
 msgstr ""
 
-#: ../src/text-context.cpp:537
+#: ../src/text-context.cpp:544
 msgid "Insert Unicode character"
 msgstr ""
 
-#: ../src/text-context.cpp:572
+#: ../src/text-context.cpp:579
 #, c-format
 msgid "Unicode (<b>Enter</b> to finish): %s: %s"
 msgstr ""
 
-#: ../src/text-context.cpp:574 ../src/text-context.cpp:849
+#: ../src/text-context.cpp:581 ../src/text-context.cpp:856
 msgid "Unicode (<b>Enter</b> to finish): "
 msgstr ""
 
-#: ../src/text-context.cpp:649
+#: ../src/text-context.cpp:656
 #, c-format
 msgid "<b>Flowed text frame</b>: %s &#215; %s"
 msgstr ""
 
-#: ../src/text-context.cpp:681
+#: ../src/text-context.cpp:688
 msgid "Type text; <b>Enter</b> to start new line."
 msgstr ""
 
-#: ../src/text-context.cpp:694
+#: ../src/text-context.cpp:701
 msgid "Flowed text is created."
 msgstr ""
 
-#: ../src/text-context.cpp:696
+#: ../src/text-context.cpp:703
 msgid "Create flowed text"
 msgstr ""
 
-#: ../src/text-context.cpp:698
+#: ../src/text-context.cpp:705
 msgid ""
 "The frame is <b>too small</b> for the current font size. Flowed text not "
 "created."
 msgstr ""
 
-#: ../src/text-context.cpp:834
+#: ../src/text-context.cpp:841
 msgid "No-break space"
 msgstr ""
 
-#: ../src/text-context.cpp:836
+#: ../src/text-context.cpp:843
 msgid "Insert no-break space"
 msgstr ""
 
-#: ../src/text-context.cpp:873
+#: ../src/text-context.cpp:880
 msgid "Make bold"
 msgstr ""
 
-#: ../src/text-context.cpp:891
+#: ../src/text-context.cpp:898
 msgid "Make italic"
 msgstr ""
 
-#: ../src/text-context.cpp:930
+#: ../src/text-context.cpp:937
 msgid "New line"
 msgstr ""
 
-#: ../src/text-context.cpp:964
+#: ../src/text-context.cpp:971
 msgid "Backspace"
 msgstr ""
 
-#: ../src/text-context.cpp:1012
+#: ../src/text-context.cpp:1019
 msgid "Kern to the left"
 msgstr ""
 
-#: ../src/text-context.cpp:1037
+#: ../src/text-context.cpp:1044
 msgid "Kern to the right"
 msgstr ""
 
-#: ../src/text-context.cpp:1062
+#: ../src/text-context.cpp:1069
 msgid "Kern up"
 msgstr ""
 
-#: ../src/text-context.cpp:1088
+#: ../src/text-context.cpp:1095
 msgid "Kern down"
 msgstr ""
 
-#: ../src/text-context.cpp:1165
+#: ../src/text-context.cpp:1172
 msgid "Rotate counterclockwise"
 msgstr ""
 
-#: ../src/text-context.cpp:1186
+#: ../src/text-context.cpp:1193
 msgid "Rotate clockwise"
 msgstr ""
 
-#: ../src/text-context.cpp:1203
+#: ../src/text-context.cpp:1210
 msgid "Contract line spacing"
 msgstr ""
 
-#: ../src/text-context.cpp:1211
+#: ../src/text-context.cpp:1218
 msgid "Contract letter spacing"
 msgstr ""
 
-#: ../src/text-context.cpp:1230
+#: ../src/text-context.cpp:1237
 msgid "Expand line spacing"
 msgstr ""
 
-#: ../src/text-context.cpp:1238
+#: ../src/text-context.cpp:1245
 msgid "Expand letter spacing"
 msgstr ""
 
-#: ../src/text-context.cpp:1368
+#: ../src/text-context.cpp:1375
 msgid "Paste text"
 msgstr ""
 
-#: ../src/text-context.cpp:1602
+#: ../src/text-context.cpp:1621
 #, c-format
 msgid ""
-"Type or edit flowed text (%d characters); <b>Enter</b> to start new "
+"Type or edit flowed text (%d characters%s); <b>Enter</b> to start new "
 "paragraph."
 msgstr ""
 
-#: ../src/text-context.cpp:1604
+#: ../src/text-context.cpp:1623
 #, c-format
-msgid "Type or edit text (%d characters); <b>Enter</b> to start new line."
+msgid "Type or edit text (%d characters%s); <b>Enter</b> to start new line."
 msgstr ""
 
-#: ../src/text-context.cpp:1612 ../src/tools-switch.cpp:198
+#: ../src/text-context.cpp:1631 ../src/tools-switch.cpp:198
 msgid ""
 "<b>Click</b> to select or create text, <b>drag</b> to create flowed text; "
 "then type."
 msgstr ""
 
-#: ../src/text-context.cpp:1722
+#: ../src/text-context.cpp:1741
 msgid "Type text"
 msgstr ""
 
@@ -10384,11 +10436,6 @@ msgstr ""
 msgid "Trace: Done. %ld nodes created"
 msgstr ""
 
-#: ../src/tweak-context.cpp:204
-#, c-format
-msgid "<b>Nothing</b> selected"
-msgstr ""
-
 #: ../src/tweak-context.cpp:210
 #, c-format
 msgid "%s. Drag to <b>move</b>."
@@ -10592,7 +10639,7 @@ msgid "Create link"
 msgstr ""
 
 #. "Ungroup"
-#: ../src/ui/context-menu.cpp:306 ../src/verbs.cpp:2370
+#: ../src/ui/context-menu.cpp:306 ../src/verbs.cpp:2376
 msgid "_Ungroup"
 msgstr ""
 
@@ -10701,12 +10748,13 @@ msgstr ""
 
 #: ../src/ui/dialog/align-and-distribute.cpp:509
 #: ../src/ui/dialog/align-and-distribute.cpp:789
-#: ../src/widgets/toolbox.cpp:7475
+#: ../src/ui/dialog/spray-option.cpp:117 ../src/ui/dialog/spray-option.cpp:195
+#: ../src/ui/dialog/spray-option.cpp:213 ../src/widgets/toolbox.cpp:7555
 msgid "Remove overlaps"
 msgstr ""
 
 #: ../src/ui/dialog/align-and-distribute.cpp:540
-#: ../src/widgets/toolbox.cpp:7265
+#: ../src/widgets/toolbox.cpp:7345
 msgid "Arrange connector network"
 msgstr ""
 
@@ -10846,7 +10894,7 @@ msgid ""
 msgstr ""
 
 #: ../src/ui/dialog/align-and-distribute.cpp:893
-#: ../src/widgets/toolbox.cpp:7436
+#: ../src/widgets/toolbox.cpp:7516
 msgid "Nicely arrange selected connector network"
 msgstr ""
 
@@ -10886,7 +10934,7 @@ msgstr ""
 #: ../src/ui/dialog/align-and-distribute.cpp:921
 #: ../src/ui/dialog/filedialogimpl-gtkmm.cpp:1414
 #: ../src/ui/dialog/icon-preview.cpp:178
-#: ../src/widgets/desktop-widget.cpp:1580
+#: ../src/widgets/desktop-widget.cpp:1588
 msgid "Selection"
 msgstr ""
 
@@ -10907,7 +10955,7 @@ msgstr ""
 #.
 #. -----------
 #: ../src/ui/dialog/calligraphic-profile-rename.cpp:52
-#: ../src/ui/dialog/inkscape-preferences.cpp:1156
+#: ../src/ui/dialog/inkscape-preferences.cpp:1161
 msgid "Save"
 msgstr ""
 
@@ -11063,12 +11111,12 @@ msgid "Guides"
 msgstr ""
 
 #: ../src/ui/dialog/document-properties.cpp:120
-#: ../src/ui/dialog/inkscape-preferences.cpp:1025
+#: ../src/ui/dialog/inkscape-preferences.cpp:1030
 #: ../src/widgets/toolbox.cpp:2190
 msgid "Grids"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:121 ../src/verbs.cpp:2601
+#: ../src/ui/dialog/document-properties.cpp:121 ../src/verbs.cpp:2607
 #: ../src/widgets/toolbox.cpp:2055
 msgid "Snap"
 msgstr ""
@@ -11196,61 +11244,61 @@ msgstr ""
 #. Inkscape::GC::release(defsRepr);
 #. inform the document, so we can undo
 #. Color Management
-#: ../src/ui/dialog/document-properties.cpp:451 ../src/verbs.cpp:2755
+#: ../src/ui/dialog/document-properties.cpp:452 ../src/verbs.cpp:2765
 msgid "Link Color Profile"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:524
+#: ../src/ui/dialog/document-properties.cpp:525
 msgid "Remove linked color profile"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:538
+#: ../src/ui/dialog/document-properties.cpp:539
 msgid "<b>Linked Color Profiles:</b>"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:540
+#: ../src/ui/dialog/document-properties.cpp:541
 msgid "<b>Available Color Profiles:</b>"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:542
+#: ../src/ui/dialog/document-properties.cpp:543
 msgid "Link Profile"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:573
+#: ../src/ui/dialog/document-properties.cpp:574
 msgid "Profile Name"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:604
+#: ../src/ui/dialog/document-properties.cpp:605
 msgid "<b>External script files:</b>"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:606
+#: ../src/ui/dialog/document-properties.cpp:607
 #: ../src/ui/dialog/swatches.cpp:463
 msgid "Add"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:629
+#: ../src/ui/dialog/document-properties.cpp:630
 msgid "Filename"
 msgstr ""
 
 #. inform the document, so we can undo
-#: ../src/ui/dialog/document-properties.cpp:669
+#: ../src/ui/dialog/document-properties.cpp:670
 msgid "Add external script..."
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:693
+#: ../src/ui/dialog/document-properties.cpp:694
 msgid "Remove external script"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:774
+#: ../src/ui/dialog/document-properties.cpp:775
 msgid "<b>Creation</b>"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:775
+#: ../src/ui/dialog/document-properties.cpp:776
 msgid "<b>Defined grids</b>"
 msgstr ""
 
-#: ../src/ui/dialog/document-properties.cpp:985
+#: ../src/ui/dialog/document-properties.cpp:986
 msgid "Remove grid"
 msgstr ""
 
@@ -11608,8 +11656,8 @@ msgid "Height of filter effects region"
 msgstr ""
 
 #: ../src/ui/dialog/filter-effects-dialog.cpp:2165
-#: ../src/widgets/toolbox.cpp:3886 ../src/widgets/toolbox.cpp:4277
-#: ../src/widgets/toolbox.cpp:4545 ../share/extensions/extrude.inx.h:4
+#: ../src/widgets/toolbox.cpp:3889 ../src/widgets/toolbox.cpp:4278
+#: ../src/widgets/toolbox.cpp:4548 ../share/extensions/extrude.inx.h:4
 msgid "Mode:"
 msgstr ""
 
@@ -11808,7 +11856,7 @@ msgid "The whole filter region will be filled with this color."
 msgstr ""
 
 #: ../src/ui/dialog/filter-effects-dialog.cpp:2214
-#: ../src/widgets/toolbox.cpp:5518
+#: ../src/widgets/toolbox.cpp:5521
 msgid "Opacity:"
 msgstr ""
 
@@ -12162,7 +12210,7 @@ msgstr ""
 
 #: ../src/ui/dialog/inkscape-preferences.cpp:204
 #: ../src/ui/dialog/tracedialog.cpp:420 ../src/ui/dialog/tracedialog.cpp:453
-#: ../src/ui/dialog/tracedialog.cpp:596 ../src/widgets/toolbox.cpp:7617
+#: ../src/ui/dialog/tracedialog.cpp:596 ../src/widgets/toolbox.cpp:7697
 msgid "Threshold:"
 msgstr ""
 
@@ -12555,7 +12603,7 @@ msgid ""
 msgstr ""
 
 #. Tweak
-#: ../src/ui/dialog/inkscape-preferences.cpp:447 ../src/verbs.cpp:2514
+#: ../src/ui/dialog/inkscape-preferences.cpp:447 ../src/verbs.cpp:2520
 msgid "Tweak"
 msgstr ""
 
@@ -12565,13 +12613,13 @@ msgid "Paint objects with:"
 msgstr ""
 
 #. Spray
-#: ../src/ui/dialog/inkscape-preferences.cpp:453 ../src/verbs.cpp:2516
+#: ../src/ui/dialog/inkscape-preferences.cpp:453 ../src/verbs.cpp:2522
 msgid "Spray"
 msgstr ""
 
 #. Zoom
 #: ../src/ui/dialog/inkscape-preferences.cpp:459
-#: ../src/ui/view/edit-widget.cpp:1068 ../src/verbs.cpp:2538
+#: ../src/ui/view/edit-widget.cpp:1068 ../src/verbs.cpp:2544
 #: ../src/widgets/desktop-widget.cpp:483
 msgid "Zoom"
 msgstr ""
@@ -12592,12 +12640,12 @@ msgid ""
 msgstr ""
 
 #. Pen
-#: ../src/ui/dialog/inkscape-preferences.cpp:501 ../src/verbs.cpp:2530
+#: ../src/ui/dialog/inkscape-preferences.cpp:501 ../src/verbs.cpp:2536
 msgid "Pen"
 msgstr ""
 
 #. Calligraphy
-#: ../src/ui/dialog/inkscape-preferences.cpp:507 ../src/verbs.cpp:2532
+#: ../src/ui/dialog/inkscape-preferences.cpp:507 ../src/verbs.cpp:2538
 msgid "Calligraphy"
 msgstr ""
 
@@ -12614,17 +12662,17 @@ msgid ""
 msgstr ""
 
 #. Paint Bucket
-#: ../src/ui/dialog/inkscape-preferences.cpp:515 ../src/verbs.cpp:2544
+#: ../src/ui/dialog/inkscape-preferences.cpp:515 ../src/verbs.cpp:2550
 msgid "Paint Bucket"
 msgstr ""
 
 #. Eraser
-#: ../src/ui/dialog/inkscape-preferences.cpp:520 ../src/verbs.cpp:2548
+#: ../src/ui/dialog/inkscape-preferences.cpp:520 ../src/verbs.cpp:2554
 msgid "Eraser"
 msgstr ""
 
 #. LPETool
-#: ../src/ui/dialog/inkscape-preferences.cpp:524 ../src/verbs.cpp:2550
+#: ../src/ui/dialog/inkscape-preferences.cpp:524 ../src/verbs.cpp:2556
 msgid "LPE Tool"
 msgstr ""
 
@@ -12638,12 +12686,12 @@ msgid ""
 msgstr ""
 
 #. Gradient
-#: ../src/ui/dialog/inkscape-preferences.cpp:539 ../src/verbs.cpp:2536
+#: ../src/ui/dialog/inkscape-preferences.cpp:539 ../src/verbs.cpp:2542
 msgid "Gradient"
 msgstr ""
 
 #. Connector
-#: ../src/ui/dialog/inkscape-preferences.cpp:543 ../src/verbs.cpp:2542
+#: ../src/ui/dialog/inkscape-preferences.cpp:543 ../src/verbs.cpp:2548
 msgid "Connector"
 msgstr ""
 
@@ -12652,7 +12700,7 @@ msgid "If on, connector attachment points will not be shown for text objects"
 msgstr ""
 
 #. Dropper
-#: ../src/ui/dialog/inkscape-preferences.cpp:548 ../src/verbs.cpp:2540
+#: ../src/ui/dialog/inkscape-preferences.cpp:548 ../src/verbs.cpp:2546
 msgid "Dropper"
 msgstr ""
 
@@ -13002,728 +13050,743 @@ msgid ""
 "filter effects dialog."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:750
+#: ../src/ui/dialog/inkscape-preferences.cpp:746
+msgid "Number of Threads:"
+msgstr ""
+
+#: ../src/ui/dialog/inkscape-preferences.cpp:746
+#: ../src/ui/dialog/inkscape-preferences.cpp:1302
+msgid "(requires restart)"
+msgstr ""
+
+#: ../src/ui/dialog/inkscape-preferences.cpp:747
+msgid ""
+"Configure number of processors/threads to use with rendering of gaussian "
+"blur."
+msgstr ""
+
+#: ../src/ui/dialog/inkscape-preferences.cpp:755
 msgid "Select in all layers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:751
+#: ../src/ui/dialog/inkscape-preferences.cpp:756
 msgid "Select only within current layer"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:752
+#: ../src/ui/dialog/inkscape-preferences.cpp:757
 msgid "Select in current layer and sublayers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:753
+#: ../src/ui/dialog/inkscape-preferences.cpp:758
 msgid "Ignore hidden objects and layers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:754
+#: ../src/ui/dialog/inkscape-preferences.cpp:759
 msgid "Ignore locked objects and layers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:755
+#: ../src/ui/dialog/inkscape-preferences.cpp:760
 msgid "Deselect upon layer change"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:757
+#: ../src/ui/dialog/inkscape-preferences.cpp:762
 msgid "Ctrl+A, Tab, Shift+Tab:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:759
+#: ../src/ui/dialog/inkscape-preferences.cpp:764
 msgid "Make keyboard selection commands work on objects in all layers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:761
+#: ../src/ui/dialog/inkscape-preferences.cpp:766
 msgid "Make keyboard selection commands work on objects in current layer only"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:763
+#: ../src/ui/dialog/inkscape-preferences.cpp:768
 msgid ""
 "Make keyboard selection commands work on objects in current layer and all "
 "its sublayers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:765
+#: ../src/ui/dialog/inkscape-preferences.cpp:770
 msgid ""
 "Uncheck this to be able to select objects that are hidden (either by "
 "themselves or by being in a hidden layer)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:767
+#: ../src/ui/dialog/inkscape-preferences.cpp:772
 msgid ""
 "Uncheck this to be able to select objects that are locked (either by "
 "themselves or by being in a locked layer)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:770
+#: ../src/ui/dialog/inkscape-preferences.cpp:775
 msgid ""
 "Uncheck this to be able to keep the current objects selected when the "
 "current layer changes"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:772
+#: ../src/ui/dialog/inkscape-preferences.cpp:777
 msgid "Selecting"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:779
+#: ../src/ui/dialog/inkscape-preferences.cpp:784
 msgid "Default export resolution:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:780
+#: ../src/ui/dialog/inkscape-preferences.cpp:785
 msgid "Default bitmap resolution (in dots per inch) in the Export dialog"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:782
+#: ../src/ui/dialog/inkscape-preferences.cpp:787
 msgid "Open Clip Art Library Server Name:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:783
+#: ../src/ui/dialog/inkscape-preferences.cpp:788
 msgid ""
 "The server name of the Open Clip Art Library webdav server. It's used by the "
 "Import and Export to OCAL function."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:785
+#: ../src/ui/dialog/inkscape-preferences.cpp:790
 msgid "Open Clip Art Library Username:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:786
+#: ../src/ui/dialog/inkscape-preferences.cpp:791
 msgid "The username used to log into Open Clip Art Library."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:788
+#: ../src/ui/dialog/inkscape-preferences.cpp:793
 msgid "Open Clip Art Library Password:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:789
+#: ../src/ui/dialog/inkscape-preferences.cpp:794
 msgid "The password used to log into Open Clip Art Library."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:791
+#: ../src/ui/dialog/inkscape-preferences.cpp:796
 msgid "Import/Export"
 msgstr ""
 
 #. TRANSLATORS: see http://www.newsandtech.com/issues/2004/03-04/pt/03-04_rendering.htm
-#: ../src/ui/dialog/inkscape-preferences.cpp:841
+#: ../src/ui/dialog/inkscape-preferences.cpp:846
 msgid "Perceptual"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:841
+#: ../src/ui/dialog/inkscape-preferences.cpp:846
 msgid "Relative Colorimetric"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:841
+#: ../src/ui/dialog/inkscape-preferences.cpp:846
 msgid "Absolute Colorimetric"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:845
+#: ../src/ui/dialog/inkscape-preferences.cpp:850
 msgid "(Note: Color management has been disabled in this build)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:849
+#: ../src/ui/dialog/inkscape-preferences.cpp:854
 msgid "Display adjustment"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:859
+#: ../src/ui/dialog/inkscape-preferences.cpp:864
 #, c-format
 msgid ""
 "The ICC profile to use to calibrate display output.\n"
 "Searched directories:%s"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:860
+#: ../src/ui/dialog/inkscape-preferences.cpp:865
 msgid "Display profile:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:865
+#: ../src/ui/dialog/inkscape-preferences.cpp:870
 msgid "Retrieve profile from display"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:868
+#: ../src/ui/dialog/inkscape-preferences.cpp:873
 msgid "Retrieve profiles from those attached to displays via XICC."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:870
+#: ../src/ui/dialog/inkscape-preferences.cpp:875
 msgid "Retrieve profiles from those attached to displays."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:875
+#: ../src/ui/dialog/inkscape-preferences.cpp:880
 msgid "Display rendering intent:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:876
-#: ../src/ui/dialog/inkscape-preferences.cpp:899
+#: ../src/ui/dialog/inkscape-preferences.cpp:881
+#: ../src/ui/dialog/inkscape-preferences.cpp:904
 msgid "The rendering intent to use to calibrate display output."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:878
+#: ../src/ui/dialog/inkscape-preferences.cpp:883
 msgid "Proofing"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:880
+#: ../src/ui/dialog/inkscape-preferences.cpp:885
 msgid "Simulate output on screen"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:882
+#: ../src/ui/dialog/inkscape-preferences.cpp:887
 msgid "Simulates output of target device."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:884
+#: ../src/ui/dialog/inkscape-preferences.cpp:889
 msgid "Mark out of gamut colors"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:886
+#: ../src/ui/dialog/inkscape-preferences.cpp:891
 msgid "Highlights colors that are out of gamut for the target device."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:891
+#: ../src/ui/dialog/inkscape-preferences.cpp:896
 msgid "Out of gamut warning color:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:892
+#: ../src/ui/dialog/inkscape-preferences.cpp:897
 msgid "Selects the color used for out of gamut warning."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:894
+#: ../src/ui/dialog/inkscape-preferences.cpp:899
 msgid "Device profile:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:895
+#: ../src/ui/dialog/inkscape-preferences.cpp:900
 msgid "The ICC profile to use to simulate device output."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:898
+#: ../src/ui/dialog/inkscape-preferences.cpp:903
 msgid "Device rendering intent:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:901
+#: ../src/ui/dialog/inkscape-preferences.cpp:906
 msgid "Black point compensation"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:903
+#: ../src/ui/dialog/inkscape-preferences.cpp:908
 msgid "Enables black point compensation."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:905
+#: ../src/ui/dialog/inkscape-preferences.cpp:910
 msgid "Preserve black"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:910
+#: ../src/ui/dialog/inkscape-preferences.cpp:915
 msgid "(LittleCMS 1.15 or later required)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:912
+#: ../src/ui/dialog/inkscape-preferences.cpp:917
 msgid "Preserve K channel in CMYK -> CMYK transforms"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:925
+#: ../src/ui/dialog/inkscape-preferences.cpp:930
 #: ../src/widgets/sp-color-icc-selector.cpp:306
 #: ../src/widgets/sp-color-icc-selector.cpp:579
 msgid "<none>"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:970
+#: ../src/ui/dialog/inkscape-preferences.cpp:975
 msgid "Color management"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:975
+#: ../src/ui/dialog/inkscape-preferences.cpp:980
 msgid "Major grid line emphasizing"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:977
+#: ../src/ui/dialog/inkscape-preferences.cpp:982
 msgid "Don't emphasize gridlines when zoomed out"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:978
+#: ../src/ui/dialog/inkscape-preferences.cpp:983
 msgid ""
 "If set and zoomed out, the gridlines will be shown in normal color instead "
 "of major grid line color."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:980
+#: ../src/ui/dialog/inkscape-preferences.cpp:985
 msgid "Default grid settings"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:986
-#: ../src/ui/dialog/inkscape-preferences.cpp:1007
+#: ../src/ui/dialog/inkscape-preferences.cpp:991
+#: ../src/ui/dialog/inkscape-preferences.cpp:1012
 msgid "Grid units:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:989
-#: ../src/ui/dialog/inkscape-preferences.cpp:1010
+#: ../src/ui/dialog/inkscape-preferences.cpp:994
+#: ../src/ui/dialog/inkscape-preferences.cpp:1015
 msgid "Origin X:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:990
-#: ../src/ui/dialog/inkscape-preferences.cpp:1011
+#: ../src/ui/dialog/inkscape-preferences.cpp:995
+#: ../src/ui/dialog/inkscape-preferences.cpp:1016
 msgid "Origin Y:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:993
+#: ../src/ui/dialog/inkscape-preferences.cpp:998
 msgid "Spacing X:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:994
-#: ../src/ui/dialog/inkscape-preferences.cpp:1013
+#: ../src/ui/dialog/inkscape-preferences.cpp:999
+#: ../src/ui/dialog/inkscape-preferences.cpp:1018
 msgid "Spacing Y:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:996
-#: ../src/ui/dialog/inkscape-preferences.cpp:997
-#: ../src/ui/dialog/inkscape-preferences.cpp:1018
-#: ../src/ui/dialog/inkscape-preferences.cpp:1019
+#: ../src/ui/dialog/inkscape-preferences.cpp:1001
+#: ../src/ui/dialog/inkscape-preferences.cpp:1002
+#: ../src/ui/dialog/inkscape-preferences.cpp:1023
+#: ../src/ui/dialog/inkscape-preferences.cpp:1024
 msgid "Grid line color:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:997
-#: ../src/ui/dialog/inkscape-preferences.cpp:1019
+#: ../src/ui/dialog/inkscape-preferences.cpp:1002
+#: ../src/ui/dialog/inkscape-preferences.cpp:1024
 msgid "Color used for normal grid lines"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:998
-#: ../src/ui/dialog/inkscape-preferences.cpp:999
-#: ../src/ui/dialog/inkscape-preferences.cpp:1020
-#: ../src/ui/dialog/inkscape-preferences.cpp:1021
+#: ../src/ui/dialog/inkscape-preferences.cpp:1003
+#: ../src/ui/dialog/inkscape-preferences.cpp:1004
+#: ../src/ui/dialog/inkscape-preferences.cpp:1025
+#: ../src/ui/dialog/inkscape-preferences.cpp:1026
 msgid "Major grid line color:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:999
-#: ../src/ui/dialog/inkscape-preferences.cpp:1021
+#: ../src/ui/dialog/inkscape-preferences.cpp:1004
+#: ../src/ui/dialog/inkscape-preferences.cpp:1026
 msgid "Color used for major (highlighted) grid lines"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1001
-#: ../src/ui/dialog/inkscape-preferences.cpp:1023
+#: ../src/ui/dialog/inkscape-preferences.cpp:1006
+#: ../src/ui/dialog/inkscape-preferences.cpp:1028
 msgid "Major grid line every:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1002
+#: ../src/ui/dialog/inkscape-preferences.cpp:1007
 msgid "Show dots instead of lines"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1003
+#: ../src/ui/dialog/inkscape-preferences.cpp:1008
 msgid "If set, display dots at gridpoints instead of gridlines"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1030
+#: ../src/ui/dialog/inkscape-preferences.cpp:1035
 msgid "Use named colors"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1031
+#: ../src/ui/dialog/inkscape-preferences.cpp:1036
 msgid ""
 "If set, write the CSS name of the color when available (e.g. 'red' or "
 "'magenta') instead of the numeric value"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1033
+#: ../src/ui/dialog/inkscape-preferences.cpp:1038
 msgid "XML formatting"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1035
+#: ../src/ui/dialog/inkscape-preferences.cpp:1040
 msgid "Inline attributes"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1036
+#: ../src/ui/dialog/inkscape-preferences.cpp:1041
 msgid "Put attributes on the same line as the element tag"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1039
+#: ../src/ui/dialog/inkscape-preferences.cpp:1044
 msgid "Indent, spaces:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1039
+#: ../src/ui/dialog/inkscape-preferences.cpp:1044
 msgid ""
 "The number of spaces to use for indenting nested elements; set to 0 for no "
 "indentation"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1041
+#: ../src/ui/dialog/inkscape-preferences.cpp:1046
 msgid "Path data"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1043
+#: ../src/ui/dialog/inkscape-preferences.cpp:1048
 msgid "Allow relative coordinates"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1044
+#: ../src/ui/dialog/inkscape-preferences.cpp:1049
 msgid "If set, relative coordinates may be used in path data"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1046
+#: ../src/ui/dialog/inkscape-preferences.cpp:1051
 msgid "Force repeat commands"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1047
+#: ../src/ui/dialog/inkscape-preferences.cpp:1052
 msgid ""
 "Force repeating of the same path command (for example, 'L 1,2 L 3,4' instead "
 "of 'L 1,2 3,4')"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1049
+#: ../src/ui/dialog/inkscape-preferences.cpp:1054
 msgid "Numbers"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1052
+#: ../src/ui/dialog/inkscape-preferences.cpp:1057
 msgid "Numeric precision:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1052
+#: ../src/ui/dialog/inkscape-preferences.cpp:1057
 msgid "How many digits to write after the decimal dot"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1055
+#: ../src/ui/dialog/inkscape-preferences.cpp:1060
 msgid "Minimum exponent:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1055
+#: ../src/ui/dialog/inkscape-preferences.cpp:1060
 msgid ""
 "The smallest number written to SVG is 10 to the power of this exponent; "
 "anything smaller is written as zero."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1057
+#: ../src/ui/dialog/inkscape-preferences.cpp:1062
 msgid "SVG output"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "System default"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Albanian (sq)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Amharic (am)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Arabic (ar)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Armenian (hy)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Azerbaijani (az)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Basque (eu)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1062
+#: ../src/ui/dialog/inkscape-preferences.cpp:1067
 msgid "Belarusian (be)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Bulgarian (bg)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Bengali (bn)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Breton (br)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Catalan (ca)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Valencian Catalan (ca@valencia)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1063
+#: ../src/ui/dialog/inkscape-preferences.cpp:1068
 msgid "Chinese/China (zh_CN)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1064
+#: ../src/ui/dialog/inkscape-preferences.cpp:1069
 msgid "Chinese/Taiwan (zh_TW)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1064
+#: ../src/ui/dialog/inkscape-preferences.cpp:1069
 msgid "Croatian (hr)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1064
+#: ../src/ui/dialog/inkscape-preferences.cpp:1069
 msgid "Czech (cs)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "Danish (da)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "Dutch (nl)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "Dzongkha (dz)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "German (de)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "Greek (el)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "English (en)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1065
+#: ../src/ui/dialog/inkscape-preferences.cpp:1070
 msgid "English/Australia (en_AU)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1066
+#: ../src/ui/dialog/inkscape-preferences.cpp:1071
 msgid "English/Canada (en_CA)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1066
+#: ../src/ui/dialog/inkscape-preferences.cpp:1071
 msgid "English/Great Britain (en_GB)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1066
+#: ../src/ui/dialog/inkscape-preferences.cpp:1071
 msgid "Pig Latin (en_US@piglatin)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1067
+#: ../src/ui/dialog/inkscape-preferences.cpp:1072
 msgid "Esperanto (eo)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1067
+#: ../src/ui/dialog/inkscape-preferences.cpp:1072
 msgid "Estonian (et)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1067
+#: ../src/ui/dialog/inkscape-preferences.cpp:1072
 msgid "Finnish (fi)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1068
+#: ../src/ui/dialog/inkscape-preferences.cpp:1073
 msgid "French (fr)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1068
+#: ../src/ui/dialog/inkscape-preferences.cpp:1073
 msgid "Irish (ga)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1068
+#: ../src/ui/dialog/inkscape-preferences.cpp:1073
 msgid "Galician (gl)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1068
+#: ../src/ui/dialog/inkscape-preferences.cpp:1073
 msgid "Hebrew (he)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1068
+#: ../src/ui/dialog/inkscape-preferences.cpp:1073
 msgid "Hungarian (hu)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Indonesian (id)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Italian (it)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Japanese (ja)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Khmer (km)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Kinyarwanda (rw)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Korean (ko)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Lithuanian (lt)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1069
+#: ../src/ui/dialog/inkscape-preferences.cpp:1074
 msgid "Macedonian (mk)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1070
+#: ../src/ui/dialog/inkscape-preferences.cpp:1075
 msgid "Mongolian (mn)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1070
+#: ../src/ui/dialog/inkscape-preferences.cpp:1075
 msgid "Nepali (ne)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1070
+#: ../src/ui/dialog/inkscape-preferences.cpp:1075
 msgid "Norwegian Bokmål (nb)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1070
+#: ../src/ui/dialog/inkscape-preferences.cpp:1075
 msgid "Norwegian Nynorsk (nn)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1070
+#: ../src/ui/dialog/inkscape-preferences.cpp:1075
 msgid "Panjabi (pa)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1071
+#: ../src/ui/dialog/inkscape-preferences.cpp:1076
 msgid "Polish (pl)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1071
+#: ../src/ui/dialog/inkscape-preferences.cpp:1076
 msgid "Portuguese (pt)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1071
+#: ../src/ui/dialog/inkscape-preferences.cpp:1076
 msgid "Portuguese/Brazil (pt_BR)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1071
+#: ../src/ui/dialog/inkscape-preferences.cpp:1076
 msgid "Romanian (ro)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1071
+#: ../src/ui/dialog/inkscape-preferences.cpp:1076
 msgid "Russian (ru)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Serbian (sr)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Serbian in Latin script (sr@latin)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Slovak (sk)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Slovenian (sl)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Spanish (es)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1072
+#: ../src/ui/dialog/inkscape-preferences.cpp:1077
 msgid "Spanish/Mexico (es_MX)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1073
+#: ../src/ui/dialog/inkscape-preferences.cpp:1078
 msgid "Swedish (sv)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1073
+#: ../src/ui/dialog/inkscape-preferences.cpp:1078
 msgid "Thai (th)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1073
+#: ../src/ui/dialog/inkscape-preferences.cpp:1078
 msgid "Turkish (tr)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1073
+#: ../src/ui/dialog/inkscape-preferences.cpp:1078
 msgid "Ukrainian (uk)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1073
+#: ../src/ui/dialog/inkscape-preferences.cpp:1078
 msgid "Vietnamese (vi)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1080
+#: ../src/ui/dialog/inkscape-preferences.cpp:1085
 msgid "Language (requires restart):"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1081
+#: ../src/ui/dialog/inkscape-preferences.cpp:1086
 msgid "Set the language for menus and number formats"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1083
+#: ../src/ui/dialog/inkscape-preferences.cpp:1088
 msgid "Smaller"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1087
+#: ../src/ui/dialog/inkscape-preferences.cpp:1092
 msgid "Toolbox icon size"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1088
+#: ../src/ui/dialog/inkscape-preferences.cpp:1093
 msgid "Set the size for the tool icons (requires restart)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1091
+#: ../src/ui/dialog/inkscape-preferences.cpp:1096
 msgid "Control bar icon size"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1092
+#: ../src/ui/dialog/inkscape-preferences.cpp:1097
 msgid ""
 "Set the size for the icons in tools' control bars to use (requires restart)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1095
+#: ../src/ui/dialog/inkscape-preferences.cpp:1100
 msgid "Secondary toolbar icon size"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1096
+#: ../src/ui/dialog/inkscape-preferences.cpp:1101
 msgid ""
 "Set the size for the icons in secondary toolbars to use (requires restart)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1099
+#: ../src/ui/dialog/inkscape-preferences.cpp:1104
 msgid "Work-around color sliders not drawing."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1101
+#: ../src/ui/dialog/inkscape-preferences.cpp:1106
 msgid ""
 "When on, will attempt to work around bugs in certain GTK themes drawing "
 "color sliders."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1107
+#: ../src/ui/dialog/inkscape-preferences.cpp:1112
 msgid "Clear list"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1112
+#: ../src/ui/dialog/inkscape-preferences.cpp:1117
 msgid "Maximum documents in Open Recent:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1113
+#: ../src/ui/dialog/inkscape-preferences.cpp:1118
 msgid ""
 "Set the maximum length of the Open Recent list in the File menu, or clear "
 "the list"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1116
+#: ../src/ui/dialog/inkscape-preferences.cpp:1121
 msgid "Zoom correction factor (in %):"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1117
+#: ../src/ui/dialog/inkscape-preferences.cpp:1122
 msgid ""
 "Adjust the slider until the length of the ruler on your screen matches its "
 "real length. This information is used when zooming to 1:1, 1:2, etc., to "
 "display objects in their true sizes"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1119
+#: ../src/ui/dialog/inkscape-preferences.cpp:1124
 msgid "Interface"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1125
+#: ../src/ui/dialog/inkscape-preferences.cpp:1130
 msgid "Use current directory for \"Save As ...\""
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1127
+#: ../src/ui/dialog/inkscape-preferences.cpp:1132
 msgid ""
 "When this option is on, the \"Save as...\" dialog will always open in the "
 "directory where the currently open document is. When it's off, it will open "
@@ -13731,237 +13794,233 @@ msgid ""
 msgstr ""
 
 #. Autosave options
-#: ../src/ui/dialog/inkscape-preferences.cpp:1131
+#: ../src/ui/dialog/inkscape-preferences.cpp:1136
 msgid "Enable autosave (requires restart)"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1132
+#: ../src/ui/dialog/inkscape-preferences.cpp:1137
 msgid ""
 "Automatically save the current document(s) at a given interval, thus "
 "minimizing loss in case of a crash"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1134
+#: ../src/ui/dialog/inkscape-preferences.cpp:1139
 msgid "Interval (in minutes):"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1134
+#: ../src/ui/dialog/inkscape-preferences.cpp:1139
 msgid "Interval (in minutes) at which document will be autosaved"
 msgstr ""
 
 #. TRANSLATORS: only translate "string" in "context|string".
 #. For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
-#: ../src/ui/dialog/inkscape-preferences.cpp:1138
+#: ../src/ui/dialog/inkscape-preferences.cpp:1143
 msgid "filesystem|Path:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1138
+#: ../src/ui/dialog/inkscape-preferences.cpp:1143
 msgid "The directory where autosaves will be written"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1140
+#: ../src/ui/dialog/inkscape-preferences.cpp:1145
 msgid "Maximum number of autosaves:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1140
+#: ../src/ui/dialog/inkscape-preferences.cpp:1145
 msgid ""
 "Maximum number of autosaved files; use this to limit the storage space used"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1162
+#: ../src/ui/dialog/inkscape-preferences.cpp:1167
 msgid "2x2"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1162
+#: ../src/ui/dialog/inkscape-preferences.cpp:1167
 msgid "4x4"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1162
+#: ../src/ui/dialog/inkscape-preferences.cpp:1167
 msgid "8x8"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1162
+#: ../src/ui/dialog/inkscape-preferences.cpp:1167
 msgid "16x16"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1166
+#: ../src/ui/dialog/inkscape-preferences.cpp:1171
 msgid "Oversample bitmaps:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1169
+#: ../src/ui/dialog/inkscape-preferences.cpp:1174
 msgid "Automatically reload bitmaps"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1171
+#: ../src/ui/dialog/inkscape-preferences.cpp:1176
 msgid "Automatically reload linked images when file is changed on disk"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1185
+#: ../src/ui/dialog/inkscape-preferences.cpp:1190
 msgid "Bitmap editor:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1191
+#: ../src/ui/dialog/inkscape-preferences.cpp:1196
 msgid "Resolution for Create Bitmap Copy:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1192
+#: ../src/ui/dialog/inkscape-preferences.cpp:1197
 msgid "Resolution used by the Create Bitmap Copy command"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1194
+#: ../src/ui/dialog/inkscape-preferences.cpp:1199
 msgid "Bitmaps"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1246
+#: ../src/ui/dialog/inkscape-preferences.cpp:1251
 msgid "Language:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1247
+#: ../src/ui/dialog/inkscape-preferences.cpp:1252
 msgid "Set the main spell check language"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1250
+#: ../src/ui/dialog/inkscape-preferences.cpp:1255
 msgid "Second language:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1251
+#: ../src/ui/dialog/inkscape-preferences.cpp:1256
 msgid ""
 "Set the second spell check language; checking will only stop on words "
 "unknown in ALL chosen languages"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1254
+#: ../src/ui/dialog/inkscape-preferences.cpp:1259
 msgid "Third language:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1255
+#: ../src/ui/dialog/inkscape-preferences.cpp:1260
 msgid ""
 "Set the third spell check language; checking will only stop on words unknown "
 "in ALL chosen languages"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1257
+#: ../src/ui/dialog/inkscape-preferences.cpp:1262
 msgid "Ignore words with digits"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1259
+#: ../src/ui/dialog/inkscape-preferences.cpp:1264
 msgid "Ignore words containing digits, such as \"R2D2\""
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1261
+#: ../src/ui/dialog/inkscape-preferences.cpp:1266
 msgid "Ignore words in ALL CAPITALS"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1263
+#: ../src/ui/dialog/inkscape-preferences.cpp:1268
 msgid "Ignore words in all capitals, such as \"IUPAC\""
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1265
+#: ../src/ui/dialog/inkscape-preferences.cpp:1270
 msgid "Spellcheck"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1284
+#: ../src/ui/dialog/inkscape-preferences.cpp:1289
 msgid "Add label comments to printing output"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1286
+#: ../src/ui/dialog/inkscape-preferences.cpp:1291
 msgid ""
 "When on, a comment will be added to the raw print output, marking the "
 "rendered output for an object with its label"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1288
+#: ../src/ui/dialog/inkscape-preferences.cpp:1293
 msgid "Prevent sharing of gradient definitions"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1290
+#: ../src/ui/dialog/inkscape-preferences.cpp:1295
 msgid ""
 "When on, shared gradient definitions are automatically forked on change; "
 "uncheck to allow sharing of gradient definitions so that editing one object "
 "may affect other objects using the same gradient"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1293
+#: ../src/ui/dialog/inkscape-preferences.cpp:1298
 msgid "Simplification threshold:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1294
+#: ../src/ui/dialog/inkscape-preferences.cpp:1299
 msgid ""
 "How strong is the Node tool's Simplify command by default. If you invoke "
 "this command several times in quick succession, it will act more and more "
 "aggressively; invoking it again after a pause restores the default threshold."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1297
+#: ../src/ui/dialog/inkscape-preferences.cpp:1302
 msgid "Latency skew:"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1297
-msgid "(requires restart)"
-msgstr ""
-
-#: ../src/ui/dialog/inkscape-preferences.cpp:1298
+#: ../src/ui/dialog/inkscape-preferences.cpp:1303
 msgid ""
 "Factor by which the event clock is skewed from the actual time (0.9766 on "
 "some systems)."
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1300
+#: ../src/ui/dialog/inkscape-preferences.cpp:1305
 msgid "Pre-render named icons"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1302
+#: ../src/ui/dialog/inkscape-preferences.cpp:1307
 msgid ""
 "When on, named icons will be rendered before displaying the ui. This is for "
 "working around bugs in GTK+ named icon notification"
 msgstr ""
 
 #. TRANSLATORS: following strings are paths in Inkscape preferences - Misc - System info
-#: ../src/ui/dialog/inkscape-preferences.cpp:1308
+#: ../src/ui/dialog/inkscape-preferences.cpp:1313
 msgid "User config: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1312
+#: ../src/ui/dialog/inkscape-preferences.cpp:1317
 msgid "User data: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1316
+#: ../src/ui/dialog/inkscape-preferences.cpp:1321
 msgid "User cache: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1320
+#: ../src/ui/dialog/inkscape-preferences.cpp:1325
 msgid "System config: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1323
+#: ../src/ui/dialog/inkscape-preferences.cpp:1328
 msgid "System data: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1326
+#: ../src/ui/dialog/inkscape-preferences.cpp:1331
 msgid "PIXMAP: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1330
+#: ../src/ui/dialog/inkscape-preferences.cpp:1335
 msgid "DATA: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1334
+#: ../src/ui/dialog/inkscape-preferences.cpp:1339
 msgid "UI: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1343
+#: ../src/ui/dialog/inkscape-preferences.cpp:1348
 msgid "Icon theme: "
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1358
+#: ../src/ui/dialog/inkscape-preferences.cpp:1363
 msgid "System info"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1358
+#: ../src/ui/dialog/inkscape-preferences.cpp:1363
 msgid "General system information"
 msgstr ""
 
-#: ../src/ui/dialog/inkscape-preferences.cpp:1360
+#: ../src/ui/dialog/inkscape-preferences.cpp:1365
 msgid "Misc"
 msgstr ""
 
@@ -14192,32 +14251,64 @@ msgstr ""
 msgid "Files found"
 msgstr ""
 
-#: ../src/ui/dialog/print.cpp:93
+#: ../src/ui/dialog/print.cpp:97
 msgid "Could not open temporary PNG for bitmap printing"
 msgstr ""
 
-#: ../src/ui/dialog/print.cpp:136
+#: ../src/ui/dialog/print.cpp:140
 msgid "Could not set up Document"
 msgstr ""
 
-#: ../src/ui/dialog/print.cpp:140
+#: ../src/ui/dialog/print.cpp:144
 msgid "Failed to set CairoRenderContext"
 msgstr ""
 
 #. set up dialog title, based on document name
-#: ../src/ui/dialog/print.cpp:180
+#: ../src/ui/dialog/print.cpp:184
 msgid "SVG Document"
 msgstr ""
 
-#: ../src/ui/dialog/print.cpp:181
+#: ../src/ui/dialog/print.cpp:185
 msgid "Print"
 msgstr ""
 
 #. build custom preferences tab
-#: ../src/ui/dialog/print.cpp:215
+#: ../src/ui/dialog/print.cpp:219
 msgid "Rendering"
 msgstr ""
 
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:61
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:466
+#: ../src/widgets/sp-color-scales.cpp:467
+msgid "Cyan"
+msgstr ""
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:66
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:469
+#: ../src/widgets/sp-color-scales.cpp:470
+msgid "Magenta"
+msgstr ""
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:71
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-icc-selector.cpp:239
+#: ../src/widgets/sp-color-scales.cpp:472
+#: ../src/widgets/sp-color-scales.cpp:473
+msgid "Yellow"
+msgstr ""
+
+#: ../src/ui/dialog/print-colors-preview-dialog.cpp:76
+#: ../src/ui/widget/selected-style.cpp:236
+#: ../src/widgets/sp-color-icc-selector.cpp:238
+#: ../src/widgets/sp-color-scales.cpp:475
+#: ../src/widgets/sp-color-scales.cpp:476
+msgid "Black"
+msgstr ""
+
 #: ../src/ui/dialog/scriptdialog.cpp:211
 msgid "_Execute Javascript"
 msgstr ""
@@ -14242,6 +14333,91 @@ msgstr ""
 msgid "Errors"
 msgstr ""
 
+#: ../src/ui/dialog/spray-option.cpp:155
+#: ../share/extensions/polyhedron_3d.inx.h:26
+msgid "Minimum"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:157
+msgid "Min"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:165
+#: ../share/extensions/polyhedron_3d.inx.h:24
+msgid "Maximum"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:167
+msgid "Max:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:245
+msgid "sprayOptions|Distribution"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:246
+msgid "sprayOptions|Cursor Options"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:247
+msgid "sprayOptions|Random Options"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:262
+msgid "sprayOptions|Distribution:"
+msgstr ""
+
+#. ComboBoxText
+#: ../src/ui/dialog/spray-option.cpp:263 ../src/ui/dialog/spray-option.cpp:276
+msgid "sprayOptions|Uniform"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:264 ../src/ui/dialog/spray-option.cpp:277
+msgid "sprayOptions|Gaussian"
+msgstr ""
+
+#. Hbox Random
+#: ../src/ui/dialog/spray-option.cpp:293
+msgid "sprayOptions|Scale:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:293
+msgid "Apply a scale factor"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:294
+msgid "sprayOptions|Rotation:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:294
+msgid "Apply rotation"
+msgstr ""
+
+#. Hbox Cursor
+#: ../src/ui/dialog/spray-option.cpp:303
+msgid "sprayOptions|Ratio:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:303
+msgid "Eccentricity of the ellipse"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:304
+msgid "sprayOptions|Angle:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:304
+msgid "Angle of the ellipse"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:305
+msgid "sprayOptions|Width:"
+msgstr ""
+
+#: ../src/ui/dialog/spray-option.cpp:305
+msgid "Size of the ellipse"
+msgstr ""
+
 #: ../src/ui/dialog/svg-fonts-dialog.cpp:121
 msgid "Set SVG Font attribute"
 msgstr ""
@@ -14670,8 +14846,8 @@ msgstr ""
 
 #. # end multiple scan
 #. ## end mode page
-#: ../src/ui/dialog/tracedialog.cpp:563 ../src/widgets/toolbox.cpp:4276
-#: ../src/widgets/toolbox.cpp:4544 ../share/extensions/triangle.inx.h:9
+#: ../src/ui/dialog/tracedialog.cpp:563 ../src/widgets/toolbox.cpp:4277
+#: ../src/widgets/toolbox.cpp:4547 ../share/extensions/triangle.inx.h:9
 msgid "Mode"
 msgstr ""
 
@@ -14951,7 +15127,7 @@ msgid ""
 "use selector (arrow) to move or transform them."
 msgstr ""
 
-#: ../src/ui/view/edit-widget.cpp:1206 ../src/widgets/desktop-widget.cpp:838
+#: ../src/ui/view/edit-widget.cpp:1206 ../src/widgets/desktop-widget.cpp:846
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">Save changes to document \"%s\" before "
@@ -14961,11 +15137,11 @@ msgid ""
 msgstr ""
 
 #: ../src/ui/view/edit-widget.cpp:1217 ../src/ui/view/edit-widget.cpp:1265
-#: ../src/widgets/desktop-widget.cpp:845 ../src/widgets/desktop-widget.cpp:902
+#: ../src/widgets/desktop-widget.cpp:853 ../src/widgets/desktop-widget.cpp:910
 msgid "Close _without saving"
 msgstr ""
 
-#: ../src/ui/view/edit-widget.cpp:1253 ../src/widgets/desktop-widget.cpp:894
+#: ../src/ui/view/edit-widget.cpp:1253 ../src/widgets/desktop-widget.cpp:902
 #, c-format
 msgid ""
 "<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a "
@@ -14974,7 +15150,7 @@ msgid ""
 "Do you want to save this file as an Inkscape SVG?"
 msgstr ""
 
-#: ../src/ui/view/edit-widget.cpp:1268 ../src/widgets/desktop-widget.cpp:905
+#: ../src/ui/view/edit-widget.cpp:1268 ../src/widgets/desktop-widget.cpp:913
 msgid "_Save as SVG"
 msgstr ""
 
@@ -15344,13 +15520,6 @@ msgstr ""
 msgid "White"
 msgstr ""
 
-#: ../src/ui/widget/selected-style.cpp:236
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-scales.cpp:463
-#: ../src/widgets/sp-color-scales.cpp:464
-msgid "Black"
-msgstr ""
-
 #: ../src/ui/widget/selected-style.cpp:240
 msgid "Copy color"
 msgstr ""
@@ -15688,1539 +15857,1547 @@ msgstr ""
 #. TRANSLATORS: If you have translated the tutorial-basic.svg file to your language,
 #. then translate this string as "tutorial-basic.LANG.svg" (where LANG is your language
 #. code); otherwise leave as "tutorial-basic.svg".
-#: ../src/verbs.cpp:1922
+#: ../src/verbs.cpp:1928
 msgid "tutorial-basic.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1926
+#: ../src/verbs.cpp:1932
 msgid "tutorial-shapes.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1930
+#: ../src/verbs.cpp:1936
 msgid "tutorial-advanced.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1934
+#: ../src/verbs.cpp:1940
 msgid "tutorial-tracing.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1938
+#: ../src/verbs.cpp:1944
 msgid "tutorial-calligraphy.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1942
+#: ../src/verbs.cpp:1948
 msgid "tutorial-elements.svg"
 msgstr ""
 
 #. TRANSLATORS: See "tutorial-basic.svg" comment.
-#: ../src/verbs.cpp:1946
+#: ../src/verbs.cpp:1952
 msgid "tutorial-tips.svg"
 msgstr ""
 
-#: ../src/verbs.cpp:2222 ../src/verbs.cpp:2747
+#: ../src/verbs.cpp:2228 ../src/verbs.cpp:2757
 msgid "Unlock all objects in the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2226 ../src/verbs.cpp:2749
+#: ../src/verbs.cpp:2232 ../src/verbs.cpp:2759
 msgid "Unlock all objects in all layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2230 ../src/verbs.cpp:2751
+#: ../src/verbs.cpp:2236 ../src/verbs.cpp:2761
 msgid "Unhide all objects in the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2234 ../src/verbs.cpp:2753
+#: ../src/verbs.cpp:2240 ../src/verbs.cpp:2763
 msgid "Unhide all objects in all layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2249
+#: ../src/verbs.cpp:2255
 msgid "Does nothing"
 msgstr ""
 
-#: ../src/verbs.cpp:2252
+#: ../src/verbs.cpp:2258
 msgid "Create new document from the default template"
 msgstr ""
 
-#: ../src/verbs.cpp:2254
+#: ../src/verbs.cpp:2260
 msgid "_Open..."
 msgstr ""
 
-#: ../src/verbs.cpp:2255
+#: ../src/verbs.cpp:2261
 msgid "Open an existing document"
 msgstr ""
 
-#: ../src/verbs.cpp:2256
+#: ../src/verbs.cpp:2262
 msgid "Re_vert"
 msgstr ""
 
-#: ../src/verbs.cpp:2257
+#: ../src/verbs.cpp:2263
 msgid "Revert to the last saved version of document (changes will be lost)"
 msgstr ""
 
-#: ../src/verbs.cpp:2258
+#: ../src/verbs.cpp:2264
 msgid "_Save"
 msgstr ""
 
-#: ../src/verbs.cpp:2258
+#: ../src/verbs.cpp:2264
 msgid "Save document"
 msgstr ""
 
-#: ../src/verbs.cpp:2260
+#: ../src/verbs.cpp:2266
 msgid "Save _As..."
 msgstr ""
 
-#: ../src/verbs.cpp:2261
+#: ../src/verbs.cpp:2267
 msgid "Save document under a new name"
 msgstr ""
 
-#: ../src/verbs.cpp:2262
+#: ../src/verbs.cpp:2268
 msgid "Save a Cop_y..."
 msgstr ""
 
-#: ../src/verbs.cpp:2263
+#: ../src/verbs.cpp:2269
 msgid "Save a copy of the document under a new name"
 msgstr ""
 
-#: ../src/verbs.cpp:2264
+#: ../src/verbs.cpp:2270
 msgid "_Print..."
 msgstr ""
 
-#: ../src/verbs.cpp:2264
+#: ../src/verbs.cpp:2270
 msgid "Print document"
 msgstr ""
 
 #. TRANSLATORS: "Vacuum Defs" means "Clean up defs" (so as to remove unused definitions)
-#: ../src/verbs.cpp:2267
+#: ../src/verbs.cpp:2273
 msgid "Vac_uum Defs"
 msgstr ""
 
-#: ../src/verbs.cpp:2267
+#: ../src/verbs.cpp:2273
 msgid ""
 "Remove unused definitions (such as gradients or clipping paths) from the &lt;"
 "defs&gt; of the document"
 msgstr ""
 
-#: ../src/verbs.cpp:2269
+#: ../src/verbs.cpp:2275
 msgid "Print Previe_w"
 msgstr ""
 
-#: ../src/verbs.cpp:2270
+#: ../src/verbs.cpp:2276
 msgid "Preview document printout"
 msgstr ""
 
-#: ../src/verbs.cpp:2271
+#: ../src/verbs.cpp:2277
 msgid "_Import..."
 msgstr ""
 
-#: ../src/verbs.cpp:2272
+#: ../src/verbs.cpp:2278
 msgid "Import a bitmap or SVG image into this document"
 msgstr ""
 
-#: ../src/verbs.cpp:2273
+#: ../src/verbs.cpp:2279
 msgid "_Export Bitmap..."
 msgstr ""
 
-#: ../src/verbs.cpp:2274
+#: ../src/verbs.cpp:2280
 msgid "Export this document or a selection as a bitmap image"
 msgstr ""
 
-#: ../src/verbs.cpp:2275
+#: ../src/verbs.cpp:2281
 msgid "Import a document from Open Clip Art Library"
 msgstr ""
 
 #. new FileVerb(SP_VERB_FILE_EXPORT_TO_OCAL, "FileExportToOCAL", N_("Export To Open Clip Art Library"), N_("Export this document to Open Clip Art Library"), INKSCAPE_ICON_DOCUMENT_EXPORT_OCAL),
-#: ../src/verbs.cpp:2277
+#: ../src/verbs.cpp:2283
 msgid "N_ext Window"
 msgstr ""
 
-#: ../src/verbs.cpp:2278
+#: ../src/verbs.cpp:2284
 msgid "Switch to the next document window"
 msgstr ""
 
-#: ../src/verbs.cpp:2279
+#: ../src/verbs.cpp:2285
 msgid "P_revious Window"
 msgstr ""
 
-#: ../src/verbs.cpp:2280
+#: ../src/verbs.cpp:2286
 msgid "Switch to the previous document window"
 msgstr ""
 
-#: ../src/verbs.cpp:2281
+#: ../src/verbs.cpp:2287
 msgid "_Close"
 msgstr ""
 
-#: ../src/verbs.cpp:2282
+#: ../src/verbs.cpp:2288
 msgid "Close this document window"
 msgstr ""
 
-#: ../src/verbs.cpp:2283
+#: ../src/verbs.cpp:2289
 msgid "_Quit"
 msgstr ""
 
-#: ../src/verbs.cpp:2283
+#: ../src/verbs.cpp:2289
 msgid "Quit Inkscape"
 msgstr ""
 
-#: ../src/verbs.cpp:2286
+#: ../src/verbs.cpp:2292
 msgid "Undo last action"
 msgstr ""
 
-#: ../src/verbs.cpp:2289
+#: ../src/verbs.cpp:2295
 msgid "Do again the last undone action"
 msgstr ""
 
-#: ../src/verbs.cpp:2290
+#: ../src/verbs.cpp:2296
 msgid "Cu_t"
 msgstr ""
 
-#: ../src/verbs.cpp:2291
+#: ../src/verbs.cpp:2297
 msgid "Cut selection to clipboard"
 msgstr ""
 
-#: ../src/verbs.cpp:2292
+#: ../src/verbs.cpp:2298
 msgid "_Copy"
 msgstr ""
 
-#: ../src/verbs.cpp:2293
+#: ../src/verbs.cpp:2299
 msgid "Copy selection to clipboard"
 msgstr ""
 
-#: ../src/verbs.cpp:2294
+#: ../src/verbs.cpp:2300
 msgid "_Paste"
 msgstr ""
 
-#: ../src/verbs.cpp:2295
+#: ../src/verbs.cpp:2301
 msgid "Paste objects from clipboard to mouse point, or paste text"
 msgstr ""
 
-#: ../src/verbs.cpp:2296
+#: ../src/verbs.cpp:2302
 msgid "Paste _Style"
 msgstr ""
 
-#: ../src/verbs.cpp:2297
+#: ../src/verbs.cpp:2303
 msgid "Apply the style of the copied object to selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2299
+#: ../src/verbs.cpp:2305
 msgid "Scale selection to match the size of the copied object"
 msgstr ""
 
-#: ../src/verbs.cpp:2300
+#: ../src/verbs.cpp:2306
 msgid "Paste _Width"
 msgstr ""
 
-#: ../src/verbs.cpp:2301
+#: ../src/verbs.cpp:2307
 msgid "Scale selection horizontally to match the width of the copied object"
 msgstr ""
 
-#: ../src/verbs.cpp:2302
+#: ../src/verbs.cpp:2308
 msgid "Paste _Height"
 msgstr ""
 
-#: ../src/verbs.cpp:2303
+#: ../src/verbs.cpp:2309
 msgid "Scale selection vertically to match the height of the copied object"
 msgstr ""
 
-#: ../src/verbs.cpp:2304
+#: ../src/verbs.cpp:2310
 msgid "Paste Size Separately"
 msgstr ""
 
-#: ../src/verbs.cpp:2305
+#: ../src/verbs.cpp:2311
 msgid "Scale each selected object to match the size of the copied object"
 msgstr ""
 
-#: ../src/verbs.cpp:2306
+#: ../src/verbs.cpp:2312
 msgid "Paste Width Separately"
 msgstr ""
 
-#: ../src/verbs.cpp:2307
+#: ../src/verbs.cpp:2313
 msgid ""
 "Scale each selected object horizontally to match the width of the copied "
 "object"
 msgstr ""
 
-#: ../src/verbs.cpp:2308
+#: ../src/verbs.cpp:2314
 msgid "Paste Height Separately"
 msgstr ""
 
-#: ../src/verbs.cpp:2309
+#: ../src/verbs.cpp:2315
 msgid ""
 "Scale each selected object vertically to match the height of the copied "
 "object"
 msgstr ""
 
-#: ../src/verbs.cpp:2310
+#: ../src/verbs.cpp:2316
 msgid "Paste _In Place"
 msgstr ""
 
-#: ../src/verbs.cpp:2311
+#: ../src/verbs.cpp:2317
 msgid "Paste objects from clipboard to the original location"
 msgstr ""
 
-#: ../src/verbs.cpp:2312
+#: ../src/verbs.cpp:2318
 msgid "Paste Path _Effect"
 msgstr ""
 
-#: ../src/verbs.cpp:2313
+#: ../src/verbs.cpp:2319
 msgid "Apply the path effect of the copied object to selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2314
+#: ../src/verbs.cpp:2320
 msgid "Remove Path _Effect"
 msgstr ""
 
-#: ../src/verbs.cpp:2315
+#: ../src/verbs.cpp:2321
 msgid "Remove any path effects from selected objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2316
+#: ../src/verbs.cpp:2322
 msgid "Remove Filters"
 msgstr ""
 
-#: ../src/verbs.cpp:2317
+#: ../src/verbs.cpp:2323
 msgid "Remove any filters from selected objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2318
+#: ../src/verbs.cpp:2324
 msgid "_Delete"
 msgstr ""
 
-#: ../src/verbs.cpp:2319
+#: ../src/verbs.cpp:2325
 msgid "Delete selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2320
+#: ../src/verbs.cpp:2326
 msgid "Duplic_ate"
 msgstr ""
 
-#: ../src/verbs.cpp:2321
+#: ../src/verbs.cpp:2327
 msgid "Duplicate selected objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2322
+#: ../src/verbs.cpp:2328
 msgid "Create Clo_ne"
 msgstr ""
 
-#: ../src/verbs.cpp:2323
+#: ../src/verbs.cpp:2329
 msgid "Create a clone (a copy linked to the original) of selected object"
 msgstr ""
 
-#: ../src/verbs.cpp:2324
+#: ../src/verbs.cpp:2330
 msgid "Unlin_k Clone"
 msgstr ""
 
-#: ../src/verbs.cpp:2325
+#: ../src/verbs.cpp:2331
 msgid ""
 "Cut the selected clones' links to the originals, turning them into "
 "standalone objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2326
+#: ../src/verbs.cpp:2332
 msgid "Relink to Copied"
 msgstr ""
 
-#: ../src/verbs.cpp:2327
+#: ../src/verbs.cpp:2333
 msgid "Relink the selected clones to the object currently on the clipboard"
 msgstr ""
 
-#: ../src/verbs.cpp:2328
+#: ../src/verbs.cpp:2334
 msgid "Select _Original"
 msgstr ""
 
-#: ../src/verbs.cpp:2329
+#: ../src/verbs.cpp:2335
 msgid "Select the object to which the selected clone is linked"
 msgstr ""
 
-#: ../src/verbs.cpp:2330
+#: ../src/verbs.cpp:2336
 msgid "Objects to _Marker"
 msgstr ""
 
-#: ../src/verbs.cpp:2331
+#: ../src/verbs.cpp:2337
 msgid "Convert selection to a line marker"
 msgstr ""
 
-#: ../src/verbs.cpp:2332
+#: ../src/verbs.cpp:2338
 msgid "Objects to Gu_ides"
 msgstr ""
 
-#: ../src/verbs.cpp:2333
+#: ../src/verbs.cpp:2339
 msgid ""
 "Convert selected objects to a collection of guidelines aligned with their "
 "edges"
 msgstr ""
 
-#: ../src/verbs.cpp:2334
+#: ../src/verbs.cpp:2340
 msgid "Objects to Patter_n"
 msgstr ""
 
-#: ../src/verbs.cpp:2335
+#: ../src/verbs.cpp:2341
 msgid "Convert selection to a rectangle with tiled pattern fill"
 msgstr ""
 
-#: ../src/verbs.cpp:2336
+#: ../src/verbs.cpp:2342
 msgid "Pattern to _Objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2337
+#: ../src/verbs.cpp:2343
 msgid "Extract objects from a tiled pattern fill"
 msgstr ""
 
-#: ../src/verbs.cpp:2338
+#: ../src/verbs.cpp:2344
 msgid "Clea_r All"
 msgstr ""
 
-#: ../src/verbs.cpp:2339
+#: ../src/verbs.cpp:2345
 msgid "Delete all objects from document"
 msgstr ""
 
-#: ../src/verbs.cpp:2340
+#: ../src/verbs.cpp:2346
 msgid "Select Al_l"
 msgstr ""
 
-#: ../src/verbs.cpp:2341
+#: ../src/verbs.cpp:2347
 msgid "Select all objects or all nodes"
 msgstr ""
 
-#: ../src/verbs.cpp:2342
+#: ../src/verbs.cpp:2348
 msgid "Select All in All La_yers"
 msgstr ""
 
-#: ../src/verbs.cpp:2343
+#: ../src/verbs.cpp:2349
 msgid "Select all objects in all visible and unlocked layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2344
+#: ../src/verbs.cpp:2350
 msgid "In_vert Selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2345
+#: ../src/verbs.cpp:2351
 msgid "Invert selection (unselect what is selected and select everything else)"
 msgstr ""
 
-#: ../src/verbs.cpp:2346
+#: ../src/verbs.cpp:2352
 msgid "Invert in All Layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2347
+#: ../src/verbs.cpp:2353
 msgid "Invert selection in all visible and unlocked layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2348
+#: ../src/verbs.cpp:2354
 msgid "Select Next"
 msgstr ""
 
-#: ../src/verbs.cpp:2349
+#: ../src/verbs.cpp:2355
 msgid "Select next object or node"
 msgstr ""
 
-#: ../src/verbs.cpp:2350
+#: ../src/verbs.cpp:2356
 msgid "Select Previous"
 msgstr ""
 
-#: ../src/verbs.cpp:2351
+#: ../src/verbs.cpp:2357
 msgid "Select previous object or node"
 msgstr ""
 
-#: ../src/verbs.cpp:2352
+#: ../src/verbs.cpp:2358
 msgid "D_eselect"
 msgstr ""
 
-#: ../src/verbs.cpp:2353
+#: ../src/verbs.cpp:2359
 msgid "Deselect any selected objects or nodes"
 msgstr ""
 
-#: ../src/verbs.cpp:2354
+#: ../src/verbs.cpp:2360
 msgid "_Guides Around Page"
 msgstr ""
 
-#: ../src/verbs.cpp:2355
+#: ../src/verbs.cpp:2361
 msgid "Create four guides aligned with the page borders"
 msgstr ""
 
-#: ../src/verbs.cpp:2356
+#: ../src/verbs.cpp:2362
 msgid "Next Path Effect Parameter"
 msgstr ""
 
-#: ../src/verbs.cpp:2357
+#: ../src/verbs.cpp:2363
 msgid "Show next Path Effect parameter for editing"
 msgstr ""
 
 #. Selection
-#: ../src/verbs.cpp:2360
+#: ../src/verbs.cpp:2366
 msgid "Raise to _Top"
 msgstr ""
 
-#: ../src/verbs.cpp:2361
+#: ../src/verbs.cpp:2367
 msgid "Raise selection to top"
 msgstr ""
 
-#: ../src/verbs.cpp:2362
+#: ../src/verbs.cpp:2368
 msgid "Lower to _Bottom"
 msgstr ""
 
-#: ../src/verbs.cpp:2363
+#: ../src/verbs.cpp:2369
 msgid "Lower selection to bottom"
 msgstr ""
 
-#: ../src/verbs.cpp:2364
+#: ../src/verbs.cpp:2370
 msgid "_Raise"
 msgstr ""
 
-#: ../src/verbs.cpp:2365
+#: ../src/verbs.cpp:2371
 msgid "Raise selection one step"
 msgstr ""
 
-#: ../src/verbs.cpp:2366
+#: ../src/verbs.cpp:2372
 msgid "_Lower"
 msgstr ""
 
-#: ../src/verbs.cpp:2367
+#: ../src/verbs.cpp:2373
 msgid "Lower selection one step"
 msgstr ""
 
-#: ../src/verbs.cpp:2368
+#: ../src/verbs.cpp:2374
 msgid "_Group"
 msgstr ""
 
-#: ../src/verbs.cpp:2369
+#: ../src/verbs.cpp:2375
 msgid "Group selected objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2371
+#: ../src/verbs.cpp:2377
 msgid "Ungroup selected groups"
 msgstr ""
 
-#: ../src/verbs.cpp:2373
+#: ../src/verbs.cpp:2379
 msgid "_Put on Path"
 msgstr ""
 
-#: ../src/verbs.cpp:2375
+#: ../src/verbs.cpp:2381
 msgid "_Remove from Path"
 msgstr ""
 
-#: ../src/verbs.cpp:2377
+#: ../src/verbs.cpp:2383
 msgid "Remove Manual _Kerns"
 msgstr ""
 
 #. TRANSLATORS: "glyph": An image used in the visual representation of characters;
 #. roughly speaking, how a character looks. A font is a set of glyphs.
-#: ../src/verbs.cpp:2380
+#: ../src/verbs.cpp:2386
 msgid "Remove all manual kerns and glyph rotations from a text object"
 msgstr ""
 
-#: ../src/verbs.cpp:2382
+#: ../src/verbs.cpp:2388
 msgid "_Union"
 msgstr ""
 
-#: ../src/verbs.cpp:2383
+#: ../src/verbs.cpp:2389
 msgid "Create union of selected paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2384
+#: ../src/verbs.cpp:2390
 msgid "_Intersection"
 msgstr ""
 
-#: ../src/verbs.cpp:2385
+#: ../src/verbs.cpp:2391
 msgid "Create intersection of selected paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2386
+#: ../src/verbs.cpp:2392
 msgid "_Difference"
 msgstr ""
 
-#: ../src/verbs.cpp:2387
+#: ../src/verbs.cpp:2393
 msgid "Create difference of selected paths (bottom minus top)"
 msgstr ""
 
-#: ../src/verbs.cpp:2388
+#: ../src/verbs.cpp:2394
 msgid "E_xclusion"
 msgstr ""
 
-#: ../src/verbs.cpp:2389
+#: ../src/verbs.cpp:2395
 msgid ""
 "Create exclusive OR of selected paths (those parts that belong to only one "
 "path)"
 msgstr ""
 
-#: ../src/verbs.cpp:2390
+#: ../src/verbs.cpp:2396
 msgid "Di_vision"
 msgstr ""
 
-#: ../src/verbs.cpp:2391
+#: ../src/verbs.cpp:2397
 msgid "Cut the bottom path into pieces"
 msgstr ""
 
 #. TRANSLATORS: "to cut a path" is not the same as "to break a path apart" - see the
 #. Advanced tutorial for more info
-#: ../src/verbs.cpp:2394
+#: ../src/verbs.cpp:2400
 msgid "Cut _Path"
 msgstr ""
 
-#: ../src/verbs.cpp:2395
+#: ../src/verbs.cpp:2401
 msgid "Cut the bottom path's stroke into pieces, removing fill"
 msgstr ""
 
 #. TRANSLATORS: "outset": expand a shape by offsetting the object's path,
 #. i.e. by displacing it perpendicular to the path in each point.
 #. See also the Advanced Tutorial for explanation.
-#: ../src/verbs.cpp:2399
+#: ../src/verbs.cpp:2405
 msgid "Outs_et"
 msgstr ""
 
-#: ../src/verbs.cpp:2400
+#: ../src/verbs.cpp:2406
 msgid "Outset selected paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2402
+#: ../src/verbs.cpp:2408
 msgid "O_utset Path by 1 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2403
+#: ../src/verbs.cpp:2409
 msgid "Outset selected paths by 1 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2405
+#: ../src/verbs.cpp:2411
 msgid "O_utset Path by 10 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2406
+#: ../src/verbs.cpp:2412
 msgid "Outset selected paths by 10 px"
 msgstr ""
 
 #. TRANSLATORS: "inset": contract a shape by offsetting the object's path,
 #. i.e. by displacing it perpendicular to the path in each point.
 #. See also the Advanced Tutorial for explanation.
-#: ../src/verbs.cpp:2410
+#: ../src/verbs.cpp:2416
 msgid "I_nset"
 msgstr ""
 
-#: ../src/verbs.cpp:2411
+#: ../src/verbs.cpp:2417
 msgid "Inset selected paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2413
+#: ../src/verbs.cpp:2419
 msgid "I_nset Path by 1 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2414
+#: ../src/verbs.cpp:2420
 msgid "Inset selected paths by 1 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2416
+#: ../src/verbs.cpp:2422
 msgid "I_nset Path by 10 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2417
+#: ../src/verbs.cpp:2423
 msgid "Inset selected paths by 10 px"
 msgstr ""
 
-#: ../src/verbs.cpp:2419
+#: ../src/verbs.cpp:2425
 msgid "D_ynamic Offset"
 msgstr ""
 
-#: ../src/verbs.cpp:2419
+#: ../src/verbs.cpp:2425
 msgid "Create a dynamic offset object"
 msgstr ""
 
-#: ../src/verbs.cpp:2421
+#: ../src/verbs.cpp:2427
 msgid "_Linked Offset"
 msgstr ""
 
-#: ../src/verbs.cpp:2422
+#: ../src/verbs.cpp:2428
 msgid "Create a dynamic offset object linked to the original path"
 msgstr ""
 
-#: ../src/verbs.cpp:2424
+#: ../src/verbs.cpp:2430
 msgid "_Stroke to Path"
 msgstr ""
 
-#: ../src/verbs.cpp:2425
+#: ../src/verbs.cpp:2431
 msgid "Convert selected object's stroke to paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2426
+#: ../src/verbs.cpp:2432
 msgid "Si_mplify"
 msgstr ""
 
-#: ../src/verbs.cpp:2427
+#: ../src/verbs.cpp:2433
 msgid "Simplify selected paths (remove extra nodes)"
 msgstr ""
 
-#: ../src/verbs.cpp:2428
+#: ../src/verbs.cpp:2434
 msgid "_Reverse"
 msgstr ""
 
-#: ../src/verbs.cpp:2429
+#: ../src/verbs.cpp:2435
 msgid "Reverse the direction of selected paths (useful for flipping markers)"
 msgstr ""
 
 #. TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
-#: ../src/verbs.cpp:2431
+#: ../src/verbs.cpp:2437
 msgid "_Trace Bitmap..."
 msgstr ""
 
-#: ../src/verbs.cpp:2432
+#: ../src/verbs.cpp:2438
 msgid "Create one or more paths from a bitmap by tracing it"
 msgstr ""
 
-#: ../src/verbs.cpp:2433
+#: ../src/verbs.cpp:2439
 msgid "_Make a Bitmap Copy"
 msgstr ""
 
-#: ../src/verbs.cpp:2434
+#: ../src/verbs.cpp:2440
 msgid "Export selection to a bitmap and insert it into document"
 msgstr ""
 
-#: ../src/verbs.cpp:2435
+#: ../src/verbs.cpp:2441
 msgid "_Combine"
 msgstr ""
 
-#: ../src/verbs.cpp:2436
+#: ../src/verbs.cpp:2442
 msgid "Combine several paths into one"
 msgstr ""
 
 #. TRANSLATORS: "to cut a path" is not the same as "to break a path apart" - see the
 #. Advanced tutorial for more info
-#: ../src/verbs.cpp:2439
+#: ../src/verbs.cpp:2445
 msgid "Break _Apart"
 msgstr ""
 
-#: ../src/verbs.cpp:2440
+#: ../src/verbs.cpp:2446
 msgid "Break selected paths into subpaths"
 msgstr ""
 
-#: ../src/verbs.cpp:2441
+#: ../src/verbs.cpp:2447
 msgid "Rows and Columns..."
 msgstr ""
 
-#: ../src/verbs.cpp:2442
+#: ../src/verbs.cpp:2448
 msgid "Arrange selected objects in a table"
 msgstr ""
 
 #. Layer
-#: ../src/verbs.cpp:2444
+#: ../src/verbs.cpp:2450
 msgid "_Add Layer..."
 msgstr ""
 
-#: ../src/verbs.cpp:2445
+#: ../src/verbs.cpp:2451
 msgid "Create a new layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2446
+#: ../src/verbs.cpp:2452
 msgid "Re_name Layer..."
 msgstr ""
 
-#: ../src/verbs.cpp:2447
+#: ../src/verbs.cpp:2453
 msgid "Rename the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2448
+#: ../src/verbs.cpp:2454
 msgid "Switch to Layer Abov_e"
 msgstr ""
 
-#: ../src/verbs.cpp:2449
+#: ../src/verbs.cpp:2455
 msgid "Switch to the layer above the current"
 msgstr ""
 
-#: ../src/verbs.cpp:2450
+#: ../src/verbs.cpp:2456
 msgid "Switch to Layer Belo_w"
 msgstr ""
 
-#: ../src/verbs.cpp:2451
+#: ../src/verbs.cpp:2457
 msgid "Switch to the layer below the current"
 msgstr ""
 
-#: ../src/verbs.cpp:2452
+#: ../src/verbs.cpp:2458
 msgid "Move Selection to Layer Abo_ve"
 msgstr ""
 
-#: ../src/verbs.cpp:2453
+#: ../src/verbs.cpp:2459
 msgid "Move selection to the layer above the current"
 msgstr ""
 
-#: ../src/verbs.cpp:2454
+#: ../src/verbs.cpp:2460
 msgid "Move Selection to Layer Bel_ow"
 msgstr ""
 
-#: ../src/verbs.cpp:2455
+#: ../src/verbs.cpp:2461
 msgid "Move selection to the layer below the current"
 msgstr ""
 
-#: ../src/verbs.cpp:2456
+#: ../src/verbs.cpp:2462
 msgid "Layer to _Top"
 msgstr ""
 
-#: ../src/verbs.cpp:2457
+#: ../src/verbs.cpp:2463
 msgid "Raise the current layer to the top"
 msgstr ""
 
-#: ../src/verbs.cpp:2458
+#: ../src/verbs.cpp:2464
 msgid "Layer to _Bottom"
 msgstr ""
 
-#: ../src/verbs.cpp:2459
+#: ../src/verbs.cpp:2465
 msgid "Lower the current layer to the bottom"
 msgstr ""
 
-#: ../src/verbs.cpp:2460
+#: ../src/verbs.cpp:2466
 msgid "_Raise Layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2461
+#: ../src/verbs.cpp:2467
 msgid "Raise the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2462
+#: ../src/verbs.cpp:2468
 msgid "_Lower Layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2463
+#: ../src/verbs.cpp:2469
 msgid "Lower the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2464
+#: ../src/verbs.cpp:2470
 msgid "Duplicate Current Layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2465
+#: ../src/verbs.cpp:2471
 msgid "Duplicate an existing layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2466
+#: ../src/verbs.cpp:2472
 msgid "_Delete Current Layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2467
+#: ../src/verbs.cpp:2473
 msgid "Delete the current layer"
 msgstr ""
 
-#: ../src/verbs.cpp:2468
+#: ../src/verbs.cpp:2474
 msgid "_Show/hide other layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2469
+#: ../src/verbs.cpp:2475
 msgid "Solo the current layer"
 msgstr ""
 
 #. Object
-#: ../src/verbs.cpp:2472
+#: ../src/verbs.cpp:2478
 msgid "Rotate _90&#176; CW"
 msgstr ""
 
 #. This is shared between tooltips and statusbar, so they
 #. must use UTF-8, not HTML entities for special characters.
-#: ../src/verbs.cpp:2475
+#: ../src/verbs.cpp:2481
 msgid "Rotate selection 90° clockwise"
 msgstr ""
 
-#: ../src/verbs.cpp:2476
+#: ../src/verbs.cpp:2482
 msgid "Rotate 9_0&#176; CCW"
 msgstr ""
 
 #. This is shared between tooltips and statusbar, so they
 #. must use UTF-8, not HTML entities for special characters.
-#: ../src/verbs.cpp:2479
+#: ../src/verbs.cpp:2485
 msgid "Rotate selection 90° counter-clockwise"
 msgstr ""
 
-#: ../src/verbs.cpp:2480
+#: ../src/verbs.cpp:2486
 msgid "Remove _Transformations"
 msgstr ""
 
-#: ../src/verbs.cpp:2481
+#: ../src/verbs.cpp:2487
 msgid "Remove transformations from object"
 msgstr ""
 
-#: ../src/verbs.cpp:2482
+#: ../src/verbs.cpp:2488
 msgid "_Object to Path"
 msgstr ""
 
-#: ../src/verbs.cpp:2483
+#: ../src/verbs.cpp:2489
 msgid "Convert selected object to path"
 msgstr ""
 
-#: ../src/verbs.cpp:2484
+#: ../src/verbs.cpp:2490
 msgid "_Flow into Frame"
 msgstr ""
 
-#: ../src/verbs.cpp:2485
+#: ../src/verbs.cpp:2491
 msgid ""
 "Put text into a frame (path or shape), creating a flowed text linked to the "
 "frame object"
 msgstr ""
 
-#: ../src/verbs.cpp:2486
+#: ../src/verbs.cpp:2492
 msgid "_Unflow"
 msgstr ""
 
-#: ../src/verbs.cpp:2487
+#: ../src/verbs.cpp:2493
 msgid "Remove text from frame (creates a single-line text object)"
 msgstr ""
 
-#: ../src/verbs.cpp:2488
+#: ../src/verbs.cpp:2494
 msgid "_Convert to Text"
 msgstr ""
 
-#: ../src/verbs.cpp:2489
+#: ../src/verbs.cpp:2495
 msgid "Convert flowed text to regular text object (preserves appearance)"
 msgstr ""
 
-#: ../src/verbs.cpp:2491
+#: ../src/verbs.cpp:2497
 msgid "Flip _Horizontal"
 msgstr ""
 
-#: ../src/verbs.cpp:2491
+#: ../src/verbs.cpp:2497
 msgid "Flip selected objects horizontally"
 msgstr ""
 
-#: ../src/verbs.cpp:2494
+#: ../src/verbs.cpp:2500
 msgid "Flip _Vertical"
 msgstr ""
 
-#: ../src/verbs.cpp:2494
+#: ../src/verbs.cpp:2500
 msgid "Flip selected objects vertically"
 msgstr ""
 
-#: ../src/verbs.cpp:2497
+#: ../src/verbs.cpp:2503
 msgid "Apply mask to selection (using the topmost object as mask)"
 msgstr ""
 
-#: ../src/verbs.cpp:2499
+#: ../src/verbs.cpp:2505
 msgid "Edit mask"
 msgstr ""
 
-#: ../src/verbs.cpp:2500 ../src/verbs.cpp:2506
+#: ../src/verbs.cpp:2506 ../src/verbs.cpp:2512
 msgid "_Release"
 msgstr ""
 
-#: ../src/verbs.cpp:2501
+#: ../src/verbs.cpp:2507
 msgid "Remove mask from selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2503
+#: ../src/verbs.cpp:2509
 msgid ""
 "Apply clipping path to selection (using the topmost object as clipping path)"
 msgstr ""
 
-#: ../src/verbs.cpp:2505 ../src/widgets/toolbox.cpp:1472
+#: ../src/verbs.cpp:2511 ../src/widgets/toolbox.cpp:1472
 msgid "Edit clipping path"
 msgstr ""
 
-#: ../src/verbs.cpp:2507
+#: ../src/verbs.cpp:2513
 msgid "Remove clipping path from selection"
 msgstr ""
 
 #. Tools
-#: ../src/verbs.cpp:2510
+#: ../src/verbs.cpp:2516
 msgid "Select"
 msgstr ""
 
-#: ../src/verbs.cpp:2511
+#: ../src/verbs.cpp:2517
 msgid "Select and transform objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2512
+#: ../src/verbs.cpp:2518
 msgid "Node Edit"
 msgstr ""
 
-#: ../src/verbs.cpp:2513
+#: ../src/verbs.cpp:2519
 msgid "Edit paths by nodes"
 msgstr ""
 
-#: ../src/verbs.cpp:2515
+#: ../src/verbs.cpp:2521
 msgid "Tweak objects by sculpting or painting"
 msgstr ""
 
-#: ../src/verbs.cpp:2517
+#: ../src/verbs.cpp:2523
 msgid "Spray objects by sculpting or painting"
 msgstr ""
 
-#: ../src/verbs.cpp:2519
+#: ../src/verbs.cpp:2525
 msgid "Create rectangles and squares"
 msgstr ""
 
-#: ../src/verbs.cpp:2521
+#: ../src/verbs.cpp:2527
 msgid "Create 3D boxes"
 msgstr ""
 
-#: ../src/verbs.cpp:2523
+#: ../src/verbs.cpp:2529
 msgid "Create circles, ellipses, and arcs"
 msgstr ""
 
-#: ../src/verbs.cpp:2525
+#: ../src/verbs.cpp:2531
 msgid "Create stars and polygons"
 msgstr ""
 
-#: ../src/verbs.cpp:2527
+#: ../src/verbs.cpp:2533
 msgid "Create spirals"
 msgstr ""
 
-#: ../src/verbs.cpp:2529
+#: ../src/verbs.cpp:2535
 msgid "Draw freehand lines"
 msgstr ""
 
-#: ../src/verbs.cpp:2531
+#: ../src/verbs.cpp:2537
 msgid "Draw Bezier curves and straight lines"
 msgstr ""
 
-#: ../src/verbs.cpp:2533
+#: ../src/verbs.cpp:2539
 msgid "Draw calligraphic or brush strokes"
 msgstr ""
 
-#: ../src/verbs.cpp:2535
+#: ../src/verbs.cpp:2541
 msgid "Create and edit text objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2537
+#: ../src/verbs.cpp:2543
 msgid "Create and edit gradients"
 msgstr ""
 
-#: ../src/verbs.cpp:2539
+#: ../src/verbs.cpp:2545
 msgid "Zoom in or out"
 msgstr ""
 
-#: ../src/verbs.cpp:2541
+#: ../src/verbs.cpp:2547
 msgid "Pick colors from image"
 msgstr ""
 
-#: ../src/verbs.cpp:2543
+#: ../src/verbs.cpp:2549
 msgid "Create diagram connectors"
 msgstr ""
 
-#: ../src/verbs.cpp:2545
+#: ../src/verbs.cpp:2551
 msgid "Fill bounded areas"
 msgstr ""
 
-#: ../src/verbs.cpp:2546
+#: ../src/verbs.cpp:2552
 msgid "LPE Edit"
 msgstr ""
 
-#: ../src/verbs.cpp:2547
+#: ../src/verbs.cpp:2553
 msgid "Edit Path Effect parameters"
 msgstr ""
 
-#: ../src/verbs.cpp:2549
+#: ../src/verbs.cpp:2555
 msgid "Erase existing paths"
 msgstr ""
 
-#: ../src/verbs.cpp:2551
+#: ../src/verbs.cpp:2557
 msgid "Do geometric constructions"
 msgstr ""
 
 #. Tool prefs
-#: ../src/verbs.cpp:2553
+#: ../src/verbs.cpp:2559
 msgid "Selector Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2554
+#: ../src/verbs.cpp:2560
 msgid "Open Preferences for the Selector tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2555
+#: ../src/verbs.cpp:2561
 msgid "Node Tool Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2556
+#: ../src/verbs.cpp:2562
 msgid "Open Preferences for the Node tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2557
+#: ../src/verbs.cpp:2563
 msgid "Tweak Tool Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2558
+#: ../src/verbs.cpp:2564
 msgid "Open Preferences for the Tweak tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2559
+#: ../src/verbs.cpp:2565
 msgid "Spray Tool Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2560
+#: ../src/verbs.cpp:2566
 msgid "Open Preferences for the Spray tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2561
+#: ../src/verbs.cpp:2567
 msgid "Rectangle Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2562
+#: ../src/verbs.cpp:2568
 msgid "Open Preferences for the Rectangle tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2563
+#: ../src/verbs.cpp:2569
 msgid "3D Box Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2564
+#: ../src/verbs.cpp:2570
 msgid "Open Preferences for the 3D Box tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2565
+#: ../src/verbs.cpp:2571
 msgid "Ellipse Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2566
+#: ../src/verbs.cpp:2572
 msgid "Open Preferences for the Ellipse tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2567
+#: ../src/verbs.cpp:2573
 msgid "Star Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2568
+#: ../src/verbs.cpp:2574
 msgid "Open Preferences for the Star tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2569
+#: ../src/verbs.cpp:2575
 msgid "Spiral Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2570
+#: ../src/verbs.cpp:2576
 msgid "Open Preferences for the Spiral tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2571
+#: ../src/verbs.cpp:2577
 msgid "Pencil Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2572
+#: ../src/verbs.cpp:2578
 msgid "Open Preferences for the Pencil tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2573
+#: ../src/verbs.cpp:2579
 msgid "Pen Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2574
+#: ../src/verbs.cpp:2580
 msgid "Open Preferences for the Pen tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2575
+#: ../src/verbs.cpp:2581
 msgid "Calligraphic Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2576
+#: ../src/verbs.cpp:2582
 msgid "Open Preferences for the Calligraphy tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2577
+#: ../src/verbs.cpp:2583
 msgid "Text Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2578
+#: ../src/verbs.cpp:2584
 msgid "Open Preferences for the Text tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2579
+#: ../src/verbs.cpp:2585
 msgid "Gradient Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2580
+#: ../src/verbs.cpp:2586
 msgid "Open Preferences for the Gradient tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2581
+#: ../src/verbs.cpp:2587
 msgid "Zoom Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2582
+#: ../src/verbs.cpp:2588
 msgid "Open Preferences for the Zoom tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2583
+#: ../src/verbs.cpp:2589
 msgid "Dropper Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2584
+#: ../src/verbs.cpp:2590
 msgid "Open Preferences for the Dropper tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2585
+#: ../src/verbs.cpp:2591
 msgid "Connector Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2586
+#: ../src/verbs.cpp:2592
 msgid "Open Preferences for the Connector tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2587
+#: ../src/verbs.cpp:2593
 msgid "Paint Bucket Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2588
+#: ../src/verbs.cpp:2594
 msgid "Open Preferences for the Paint Bucket tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2589
+#: ../src/verbs.cpp:2595
 msgid "Eraser Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2590
+#: ../src/verbs.cpp:2596
 msgid "Open Preferences for the Eraser tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2591
+#: ../src/verbs.cpp:2597
 msgid "LPE Tool Preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2592
+#: ../src/verbs.cpp:2598
 msgid "Open Preferences for the LPETool tool"
 msgstr ""
 
 #. Zoom/View
-#: ../src/verbs.cpp:2595
+#: ../src/verbs.cpp:2601
 msgid "Zoom In"
 msgstr ""
 
-#: ../src/verbs.cpp:2595
+#: ../src/verbs.cpp:2601
 msgid "Zoom in"
 msgstr ""
 
-#: ../src/verbs.cpp:2596
+#: ../src/verbs.cpp:2602
 msgid "Zoom Out"
 msgstr ""
 
-#: ../src/verbs.cpp:2596
+#: ../src/verbs.cpp:2602
 msgid "Zoom out"
 msgstr ""
 
-#: ../src/verbs.cpp:2597
+#: ../src/verbs.cpp:2603
 msgid "_Rulers"
 msgstr ""
 
-#: ../src/verbs.cpp:2597
+#: ../src/verbs.cpp:2603
 msgid "Show or hide the canvas rulers"
 msgstr ""
 
-#: ../src/verbs.cpp:2598
+#: ../src/verbs.cpp:2604
 msgid "Scroll_bars"
 msgstr ""
 
-#: ../src/verbs.cpp:2598
+#: ../src/verbs.cpp:2604
 msgid "Show or hide the canvas scrollbars"
 msgstr ""
 
-#: ../src/verbs.cpp:2599
+#: ../src/verbs.cpp:2605
 msgid "_Grid"
 msgstr ""
 
-#: ../src/verbs.cpp:2599
+#: ../src/verbs.cpp:2605
 msgid "Show or hide the grid"
 msgstr ""
 
-#: ../src/verbs.cpp:2600
+#: ../src/verbs.cpp:2606
 msgid "G_uides"
 msgstr ""
 
-#: ../src/verbs.cpp:2600
+#: ../src/verbs.cpp:2606
 msgid "Show or hide guides (drag from a ruler to create a guide)"
 msgstr ""
 
-#: ../src/verbs.cpp:2601
+#: ../src/verbs.cpp:2607
 msgid "Toggle snapping on or off"
 msgstr ""
 
-#: ../src/verbs.cpp:2602
+#: ../src/verbs.cpp:2608
 msgid "Nex_t Zoom"
 msgstr ""
 
-#: ../src/verbs.cpp:2602
+#: ../src/verbs.cpp:2608
 msgid "Next zoom (from the history of zooms)"
 msgstr ""
 
-#: ../src/verbs.cpp:2604
+#: ../src/verbs.cpp:2610
 msgid "Pre_vious Zoom"
 msgstr ""
 
-#: ../src/verbs.cpp:2604
+#: ../src/verbs.cpp:2610
 msgid "Previous zoom (from the history of zooms)"
 msgstr ""
 
-#: ../src/verbs.cpp:2606
+#: ../src/verbs.cpp:2612
 msgid "Zoom 1:_1"
 msgstr ""
 
-#: ../src/verbs.cpp:2606
+#: ../src/verbs.cpp:2612
 msgid "Zoom to 1:1"
 msgstr ""
 
-#: ../src/verbs.cpp:2608
+#: ../src/verbs.cpp:2614
 msgid "Zoom 1:_2"
 msgstr ""
 
-#: ../src/verbs.cpp:2608
+#: ../src/verbs.cpp:2614
 msgid "Zoom to 1:2"
 msgstr ""
 
-#: ../src/verbs.cpp:2610
+#: ../src/verbs.cpp:2616
 msgid "_Zoom 2:1"
 msgstr ""
 
-#: ../src/verbs.cpp:2610
+#: ../src/verbs.cpp:2616
 msgid "Zoom to 2:1"
 msgstr ""
 
-#: ../src/verbs.cpp:2613
+#: ../src/verbs.cpp:2619
 msgid "_Fullscreen"
 msgstr ""
 
-#: ../src/verbs.cpp:2613
+#: ../src/verbs.cpp:2619
 msgid "Stretch this document window to full screen"
 msgstr ""
 
-#: ../src/verbs.cpp:2616
+#: ../src/verbs.cpp:2622
 msgid "Toggle _Focus Mode"
 msgstr ""
 
-#: ../src/verbs.cpp:2616
+#: ../src/verbs.cpp:2622
 msgid "Remove excess toolbars to focus on drawing"
 msgstr ""
 
-#: ../src/verbs.cpp:2618
+#: ../src/verbs.cpp:2624
 msgid "Duplic_ate Window"
 msgstr ""
 
-#: ../src/verbs.cpp:2618
+#: ../src/verbs.cpp:2624
 msgid "Open a new window with the same document"
 msgstr ""
 
-#: ../src/verbs.cpp:2620
+#: ../src/verbs.cpp:2626
 msgid "_New View Preview"
 msgstr ""
 
-#: ../src/verbs.cpp:2621
+#: ../src/verbs.cpp:2627
 msgid "New View Preview"
 msgstr ""
 
 #. "view_new_preview"
-#: ../src/verbs.cpp:2623
+#: ../src/verbs.cpp:2629
 msgid "_Normal"
 msgstr ""
 
-#: ../src/verbs.cpp:2624
+#: ../src/verbs.cpp:2630
 msgid "Switch to normal display mode"
 msgstr ""
 
-#: ../src/verbs.cpp:2625
+#: ../src/verbs.cpp:2631
 msgid "No _Filters"
 msgstr ""
 
-#: ../src/verbs.cpp:2626
+#: ../src/verbs.cpp:2632
 msgid "Switch to normal display without filters"
 msgstr ""
 
-#: ../src/verbs.cpp:2627
+#: ../src/verbs.cpp:2633
 msgid "_Outline"
 msgstr ""
 
-#: ../src/verbs.cpp:2628
+#: ../src/verbs.cpp:2634
 msgid "Switch to outline (wireframe) display mode"
 msgstr ""
 
-#: ../src/verbs.cpp:2629
+#: ../src/verbs.cpp:2635
+msgid "_Print Colors Preview"
+msgstr ""
+
+#: ../src/verbs.cpp:2636
+msgid "Switch to print colors preview mode"
+msgstr ""
+
+#: ../src/verbs.cpp:2637
 msgid "_Toggle"
 msgstr ""
 
-#: ../src/verbs.cpp:2630
+#: ../src/verbs.cpp:2638
 msgid "Toggle between normal and outline display modes"
 msgstr ""
 
-#: ../src/verbs.cpp:2632
+#: ../src/verbs.cpp:2640
 msgid "Color-managed view"
 msgstr ""
 
-#: ../src/verbs.cpp:2633
+#: ../src/verbs.cpp:2641
 msgid "Toggle color-managed display for this document window"
 msgstr ""
 
-#: ../src/verbs.cpp:2635
+#: ../src/verbs.cpp:2643
 msgid "Ico_n Preview..."
 msgstr ""
 
-#: ../src/verbs.cpp:2636
+#: ../src/verbs.cpp:2644
 msgid "Open a window to preview objects at different icon resolutions"
 msgstr ""
 
-#: ../src/verbs.cpp:2638
+#: ../src/verbs.cpp:2646
 msgid "Zoom to fit page in window"
 msgstr ""
 
-#: ../src/verbs.cpp:2639
+#: ../src/verbs.cpp:2647
 msgid "Page _Width"
 msgstr ""
 
-#: ../src/verbs.cpp:2640
+#: ../src/verbs.cpp:2648
 msgid "Zoom to fit page width in window"
 msgstr ""
 
-#: ../src/verbs.cpp:2642
+#: ../src/verbs.cpp:2650
 msgid "Zoom to fit drawing in window"
 msgstr ""
 
-#: ../src/verbs.cpp:2644
+#: ../src/verbs.cpp:2652
 msgid "Zoom to fit selection in window"
 msgstr ""
 
 #. Dialogs
-#: ../src/verbs.cpp:2647
+#: ../src/verbs.cpp:2655
 msgid "In_kscape Preferences..."
 msgstr ""
 
-#: ../src/verbs.cpp:2648
+#: ../src/verbs.cpp:2656
 msgid "Edit global Inkscape preferences"
 msgstr ""
 
-#: ../src/verbs.cpp:2649
+#: ../src/verbs.cpp:2657
 msgid "_Document Properties..."
 msgstr ""
 
-#: ../src/verbs.cpp:2650
+#: ../src/verbs.cpp:2658
 msgid "Edit properties of this document (to be saved with the document)"
 msgstr ""
 
-#: ../src/verbs.cpp:2651
+#: ../src/verbs.cpp:2659
 msgid "Document _Metadata..."
 msgstr ""
 
-#: ../src/verbs.cpp:2652
+#: ../src/verbs.cpp:2660
 msgid "Edit document metadata (to be saved with the document)"
 msgstr ""
 
-#: ../src/verbs.cpp:2653
+#: ../src/verbs.cpp:2661
 msgid "_Fill and Stroke..."
 msgstr ""
 
-#: ../src/verbs.cpp:2654
+#: ../src/verbs.cpp:2662
 msgid ""
 "Edit objects' colors, gradients, stroke width, arrowheads, dash patterns..."
 msgstr ""
 
 #. TRANSLATORS: "Swatches" means: color samples
-#: ../src/verbs.cpp:2656
+#: ../src/verbs.cpp:2664
 msgid "S_watches..."
 msgstr ""
 
-#: ../src/verbs.cpp:2657
+#: ../src/verbs.cpp:2665
 msgid "Select colors from a swatches palette"
 msgstr ""
 
-#: ../src/verbs.cpp:2658
+#: ../src/verbs.cpp:2666
 msgid "Transfor_m..."
 msgstr ""
 
-#: ../src/verbs.cpp:2659
+#: ../src/verbs.cpp:2667
 msgid "Precisely control objects' transformations"
 msgstr ""
 
-#: ../src/verbs.cpp:2660
+#: ../src/verbs.cpp:2668
 msgid "_Align and Distribute..."
 msgstr ""
 
-#: ../src/verbs.cpp:2661
+#: ../src/verbs.cpp:2669
 msgid "Align and distribute objects"
 msgstr ""
 
-#: ../src/verbs.cpp:2662
+#: ../src/verbs.cpp:2670
 msgid "_Spray options..."
 msgstr ""
 
-#: ../src/verbs.cpp:2663
+#: ../src/verbs.cpp:2671
 msgid "Some options for the spray"
 msgstr ""
 
-#: ../src/verbs.cpp:2664
+#: ../src/verbs.cpp:2672
 msgid "Undo _History..."
 msgstr ""
 
-#: ../src/verbs.cpp:2665
+#: ../src/verbs.cpp:2673
 msgid "Undo History"
 msgstr ""
 
-#: ../src/verbs.cpp:2666
+#: ../src/verbs.cpp:2674
 msgid "_Text and Font..."
 msgstr ""
 
-#: ../src/verbs.cpp:2667
+#: ../src/verbs.cpp:2675
 msgid "View and select font family, font size and other text properties"
 msgstr ""
 
-#: ../src/verbs.cpp:2668
+#: ../src/verbs.cpp:2676
 msgid "_XML Editor..."
 msgstr ""
 
-#: ../src/verbs.cpp:2669
+#: ../src/verbs.cpp:2677
 msgid "View and edit the XML tree of the document"
 msgstr ""
 
-#: ../src/verbs.cpp:2670
+#: ../src/verbs.cpp:2678
 msgid "_Find..."
 msgstr ""
 
-#: ../src/verbs.cpp:2671
+#: ../src/verbs.cpp:2679
 msgid "Find objects in document"
 msgstr ""
 
-#: ../src/verbs.cpp:2672
+#: ../src/verbs.cpp:2680
 msgid "Find and _Replace Text..."
 msgstr ""
 
-#: ../src/verbs.cpp:2673
+#: ../src/verbs.cpp:2681
 msgid "Find and replace text in document"
 msgstr ""
 
-#: ../src/verbs.cpp:2674
+#: ../src/verbs.cpp:2682
 msgid "Check Spellin_g..."
 msgstr ""
 
-#: ../src/verbs.cpp:2675
+#: ../src/verbs.cpp:2683
 msgid "Check spelling of text in document"
 msgstr ""
 
-#: ../src/verbs.cpp:2676
+#: ../src/verbs.cpp:2684
 msgid "_Messages..."
 msgstr ""
 
-#: ../src/verbs.cpp:2677
+#: ../src/verbs.cpp:2685
 msgid "View debug messages"
 msgstr ""
 
-#: ../src/verbs.cpp:2678
+#: ../src/verbs.cpp:2686
 msgid "S_cripts..."
 msgstr ""
 
-#: ../src/verbs.cpp:2679
+#: ../src/verbs.cpp:2687
 msgid "Run scripts"
 msgstr ""
 
-#: ../src/verbs.cpp:2680
+#: ../src/verbs.cpp:2688
 msgid "Show/Hide D_ialogs"
 msgstr ""
 
-#: ../src/verbs.cpp:2681
+#: ../src/verbs.cpp:2689
 msgid "Show or hide all open dialogs"
 msgstr ""
 
-#: ../src/verbs.cpp:2682
+#: ../src/verbs.cpp:2690
 msgid "Create Tiled Clones..."
 msgstr ""
 
-#: ../src/verbs.cpp:2683
+#: ../src/verbs.cpp:2691
 msgid ""
 "Create multiple clones of selected object, arranging them into a pattern or "
 "scattering"
 msgstr ""
 
-#: ../src/verbs.cpp:2684
+#: ../src/verbs.cpp:2692
 msgid "_Object Properties..."
 msgstr ""
 
-#: ../src/verbs.cpp:2685
+#: ../src/verbs.cpp:2693
 msgid "Edit the ID, locked and visible status, and other object properties"
 msgstr ""
 
@@ -17228,204 +17405,213 @@ msgstr ""
 #. new DialogVerb(SP_VERB_XMPP_CLIENT, "DialogXmppClient",
 #. N_("_Instant Messaging..."), N_("Jabber Instant Messaging Client"), NULL),
 #. #endif
-#: ../src/verbs.cpp:2690
+#: ../src/verbs.cpp:2698
 msgid "_Input Devices..."
 msgstr ""
 
-#: ../src/verbs.cpp:2691 ../src/verbs.cpp:2693
+#: ../src/verbs.cpp:2699 ../src/verbs.cpp:2701
 msgid "Configure extended input devices, such as a graphics tablet"
 msgstr ""
 
-#: ../src/verbs.cpp:2692
+#: ../src/verbs.cpp:2700
 msgid "_Input Devices (new)..."
 msgstr ""
 
-#: ../src/verbs.cpp:2694
+#: ../src/verbs.cpp:2702
 msgid "_Extensions..."
 msgstr ""
 
-#: ../src/verbs.cpp:2695
+#: ../src/verbs.cpp:2703
 msgid "Query information about extensions"
 msgstr ""
 
-#: ../src/verbs.cpp:2696
+#: ../src/verbs.cpp:2704
 msgid "Layer_s..."
 msgstr ""
 
-#: ../src/verbs.cpp:2697
+#: ../src/verbs.cpp:2705
 msgid "View Layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2698
+#: ../src/verbs.cpp:2706
 msgid "Path Effect Editor..."
 msgstr ""
 
-#: ../src/verbs.cpp:2699
+#: ../src/verbs.cpp:2707
 msgid "Manage, edit, and apply path effects"
 msgstr ""
 
-#: ../src/verbs.cpp:2700
+#: ../src/verbs.cpp:2708
 msgid "Filter Editor..."
 msgstr ""
 
-#: ../src/verbs.cpp:2701
+#: ../src/verbs.cpp:2709
 msgid "Manage, edit, and apply SVG filters"
 msgstr ""
 
-#: ../src/verbs.cpp:2702
+#: ../src/verbs.cpp:2710
 msgid "SVG Font Editor..."
 msgstr ""
 
-#: ../src/verbs.cpp:2703
+#: ../src/verbs.cpp:2711
 msgid "Edit SVG fonts"
 msgstr ""
 
+#: ../src/verbs.cpp:2712
+msgid "Print Colors..."
+msgstr ""
+
+#: ../src/verbs.cpp:2713
+msgid ""
+"Select which color separations to render in Print Colors Preview rendermode"
+msgstr ""
+
 #. Help
-#: ../src/verbs.cpp:2706
+#: ../src/verbs.cpp:2716
 msgid "About E_xtensions"
 msgstr ""
 
-#: ../src/verbs.cpp:2707
+#: ../src/verbs.cpp:2717
 msgid "Information on Inkscape extensions"
 msgstr ""
 
-#: ../src/verbs.cpp:2708
+#: ../src/verbs.cpp:2718
 msgid "About _Memory"
 msgstr ""
 
-#: ../src/verbs.cpp:2709
+#: ../src/verbs.cpp:2719
 msgid "Memory usage information"
 msgstr ""
 
-#: ../src/verbs.cpp:2710
+#: ../src/verbs.cpp:2720
 msgid "_About Inkscape"
 msgstr ""
 
-#: ../src/verbs.cpp:2711
+#: ../src/verbs.cpp:2721
 msgid "Inkscape version, authors, license"
 msgstr ""
 
 #. new HelpVerb(SP_VERB_SHOW_LICENSE, "ShowLicense", N_("_License"),
 #. N_("Distribution terms"), /*"show_license"*/"inkscape_options"),
 #. Tutorials
-#: ../src/verbs.cpp:2716
+#: ../src/verbs.cpp:2726
 msgid "Inkscape: _Basic"
 msgstr ""
 
-#: ../src/verbs.cpp:2717
+#: ../src/verbs.cpp:2727
 msgid "Getting started with Inkscape"
 msgstr ""
 
 #. "tutorial_basic"
-#: ../src/verbs.cpp:2718
+#: ../src/verbs.cpp:2728
 msgid "Inkscape: _Shapes"
 msgstr ""
 
-#: ../src/verbs.cpp:2719
+#: ../src/verbs.cpp:2729
 msgid "Using shape tools to create and edit shapes"
 msgstr ""
 
-#: ../src/verbs.cpp:2720
+#: ../src/verbs.cpp:2730
 msgid "Inkscape: _Advanced"
 msgstr ""
 
-#: ../src/verbs.cpp:2721
+#: ../src/verbs.cpp:2731
 msgid "Advanced Inkscape topics"
 msgstr ""
 
 #. "tutorial_advanced"
 #. TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
-#: ../src/verbs.cpp:2723
+#: ../src/verbs.cpp:2733
 msgid "Inkscape: T_racing"
 msgstr ""
 
-#: ../src/verbs.cpp:2724
+#: ../src/verbs.cpp:2734
 msgid "Using bitmap tracing"
 msgstr ""
 
 #. "tutorial_tracing"
-#: ../src/verbs.cpp:2725
+#: ../src/verbs.cpp:2735
 msgid "Inkscape: _Calligraphy"
 msgstr ""
 
-#: ../src/verbs.cpp:2726
+#: ../src/verbs.cpp:2736
 msgid "Using the Calligraphy pen tool"
 msgstr ""
 
-#: ../src/verbs.cpp:2727
+#: ../src/verbs.cpp:2737
 msgid "_Elements of Design"
 msgstr ""
 
-#: ../src/verbs.cpp:2728
+#: ../src/verbs.cpp:2738
 msgid "Principles of design in the tutorial form"
 msgstr ""
 
 #. "tutorial_design"
-#: ../src/verbs.cpp:2729
+#: ../src/verbs.cpp:2739
 msgid "_Tips and Tricks"
 msgstr ""
 
-#: ../src/verbs.cpp:2730
+#: ../src/verbs.cpp:2740
 msgid "Miscellaneous tips and tricks"
 msgstr ""
 
 #. "tutorial_tips"
 #. Effect -- renamed Extension
-#: ../src/verbs.cpp:2733
+#: ../src/verbs.cpp:2743
 msgid "Previous Extension"
 msgstr ""
 
-#: ../src/verbs.cpp:2734
+#: ../src/verbs.cpp:2744
 msgid "Repeat the last extension with the same settings"
 msgstr ""
 
-#: ../src/verbs.cpp:2735
+#: ../src/verbs.cpp:2745
 msgid "Previous Extension Settings..."
 msgstr ""
 
-#: ../src/verbs.cpp:2736
+#: ../src/verbs.cpp:2746
 msgid "Repeat the last extension with new settings"
 msgstr ""
 
-#: ../src/verbs.cpp:2740
+#: ../src/verbs.cpp:2750
 msgid "Fit the page to the current selection"
 msgstr ""
 
-#: ../src/verbs.cpp:2742
+#: ../src/verbs.cpp:2752
 msgid "Fit the page to the drawing"
 msgstr ""
 
-#: ../src/verbs.cpp:2744
+#: ../src/verbs.cpp:2754
 msgid ""
 "Fit the page to the current selection or the drawing if there is no selection"
 msgstr ""
 
 #. LockAndHide
-#: ../src/verbs.cpp:2746
+#: ../src/verbs.cpp:2756
 msgid "Unlock All"
 msgstr ""
 
-#: ../src/verbs.cpp:2748
+#: ../src/verbs.cpp:2758
 msgid "Unlock All in All Layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2750
+#: ../src/verbs.cpp:2760
 msgid "Unhide All"
 msgstr ""
 
-#: ../src/verbs.cpp:2752
+#: ../src/verbs.cpp:2762
 msgid "Unhide All in All Layers"
 msgstr ""
 
-#: ../src/verbs.cpp:2756
+#: ../src/verbs.cpp:2766
 msgid "Link an ICC color profile"
 msgstr ""
 
-#: ../src/verbs.cpp:2757
+#: ../src/verbs.cpp:2767
 msgid "Remove Color Profile"
 msgstr ""
 
-#: ../src/verbs.cpp:2758
+#: ../src/verbs.cpp:2768
 msgid "Remove a linked ICC color profile"
 msgstr ""
 
@@ -17451,15 +17637,35 @@ msgstr ""
 
 #: ../src/widgets/desktop-widget.cpp:617
 #, c-format
-msgid "%s: %d - Inkscape"
+msgid "%s: %d (no filters) - Inkscape"
+msgstr ""
+
+#: ../src/widgets/desktop-widget.cpp:619
+#, c-format
+msgid "%s: %d (print colors preview) - Inkscape"
 msgstr ""
 
 #: ../src/widgets/desktop-widget.cpp:621
 #, c-format
+msgid "%s: %d - Inkscape"
+msgstr ""
+
+#: ../src/widgets/desktop-widget.cpp:625
+#, c-format
 msgid "%s (outline) - Inkscape"
 msgstr ""
 
-#: ../src/widgets/desktop-widget.cpp:623
+#: ../src/widgets/desktop-widget.cpp:627
+#, c-format
+msgid "%s (no filters) - Inkscape"
+msgstr ""
+
+#: ../src/widgets/desktop-widget.cpp:629
+#, c-format
+msgid "%s (print colors preview) - Inkscape"
+msgstr ""
+
+#: ../src/widgets/desktop-widget.cpp:631
 #, c-format
 msgid "%s - Inkscape"
 msgstr ""
@@ -17560,9 +17766,9 @@ msgstr ""
 
 #: ../src/widgets/gradient-toolbar.cpp:527 ../src/widgets/toolbox.cpp:2657
 #: ../src/widgets/toolbox.cpp:2735 ../src/widgets/toolbox.cpp:3066
-#: ../src/widgets/toolbox.cpp:3104 ../src/widgets/toolbox.cpp:3719
-#: ../src/widgets/toolbox.cpp:3743 ../src/widgets/toolbox.cpp:5349
-#: ../src/widgets/toolbox.cpp:5378
+#: ../src/widgets/toolbox.cpp:3104 ../src/widgets/toolbox.cpp:3722
+#: ../src/widgets/toolbox.cpp:3746 ../src/widgets/toolbox.cpp:5352
+#: ../src/widgets/toolbox.cpp:5381
 msgid "<b>New:</b>"
 msgstr ""
 
@@ -17591,8 +17797,8 @@ msgstr ""
 #. gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
 #: ../src/widgets/gradient-toolbar.cpp:610 ../src/widgets/toolbox.cpp:2659
 #: ../src/widgets/toolbox.cpp:3074 ../src/widgets/toolbox.cpp:3092
-#: ../src/widgets/toolbox.cpp:3721 ../src/widgets/toolbox.cpp:3732
-#: ../src/widgets/toolbox.cpp:5352 ../src/widgets/toolbox.cpp:5363
+#: ../src/widgets/toolbox.cpp:3724 ../src/widgets/toolbox.cpp:3735
+#: ../src/widgets/toolbox.cpp:5355 ../src/widgets/toolbox.cpp:5366
 msgid "<b>Change:</b>"
 msgstr ""
 
@@ -17849,58 +18055,58 @@ msgid "CMS"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:220
-#: ../src/widgets/sp-color-scales.cpp:399
+#: ../src/widgets/sp-color-scales.cpp:411
 msgid "_R"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:220
 #: ../src/widgets/sp-color-icc-selector.cpp:221
-#: ../src/widgets/sp-color-scales.cpp:402
+#: ../src/widgets/sp-color-scales.cpp:414
 msgid "_G"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:220
-#: ../src/widgets/sp-color-scales.cpp:405
+#: ../src/widgets/sp-color-scales.cpp:417
 msgid "_B"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:222
 #: ../src/widgets/sp-color-icc-selector.cpp:223
-#: ../src/widgets/sp-color-scales.cpp:425
+#: ../src/widgets/sp-color-scales.cpp:437
 msgid "_H"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:222
 #: ../src/widgets/sp-color-icc-selector.cpp:223
-#: ../src/widgets/sp-color-scales.cpp:428
+#: ../src/widgets/sp-color-scales.cpp:440
 msgid "_S"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:223
-#: ../src/widgets/sp-color-scales.cpp:431
+#: ../src/widgets/sp-color-scales.cpp:443
 msgid "_L"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:224
 #: ../src/widgets/sp-color-icc-selector.cpp:225
-#: ../src/widgets/sp-color-scales.cpp:453
+#: ../src/widgets/sp-color-scales.cpp:465
 msgid "_C"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:224
 #: ../src/widgets/sp-color-icc-selector.cpp:225
-#: ../src/widgets/sp-color-scales.cpp:456
+#: ../src/widgets/sp-color-scales.cpp:468
 msgid "_M"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:224
 #: ../src/widgets/sp-color-icc-selector.cpp:225
-#: ../src/widgets/sp-color-scales.cpp:459
+#: ../src/widgets/sp-color-scales.cpp:471
 msgid "_Y"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:224
-#: ../src/widgets/sp-color-scales.cpp:462
+#: ../src/widgets/sp-color-scales.cpp:474
 msgid "_K"
 msgstr ""
 
@@ -17908,27 +18114,6 @@ msgstr ""
 msgid "Gray"
 msgstr ""
 
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:454
-#: ../src/widgets/sp-color-scales.cpp:455
-msgid "Cyan"
-msgstr ""
-
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:457
-#: ../src/widgets/sp-color-scales.cpp:458
-msgid "Magenta"
-msgstr ""
-
-#: ../src/widgets/sp-color-icc-selector.cpp:238
-#: ../src/widgets/sp-color-icc-selector.cpp:239
-#: ../src/widgets/sp-color-scales.cpp:460
-#: ../src/widgets/sp-color-scales.cpp:461
-msgid "Yellow"
-msgstr ""
-
 #: ../src/widgets/sp-color-icc-selector.cpp:296
 msgid "Fix"
 msgstr ""
@@ -17939,43 +18124,56 @@ msgstr ""
 
 #. Label
 #: ../src/widgets/sp-color-icc-selector.cpp:380
-#: ../src/widgets/sp-color-scales.cpp:408
-#: ../src/widgets/sp-color-scales.cpp:434
-#: ../src/widgets/sp-color-scales.cpp:465
-#: ../src/widgets/sp-color-wheel-selector.cpp:134
+#: ../src/widgets/sp-color-scales.cpp:420
+#: ../src/widgets/sp-color-scales.cpp:446
+#: ../src/widgets/sp-color-scales.cpp:477
+#: ../src/widgets/sp-color-wheel-selector.cpp:135
 msgid "_A"
 msgstr ""
 
 #: ../src/widgets/sp-color-icc-selector.cpp:390
 #: ../src/widgets/sp-color-icc-selector.cpp:402
-#: ../src/widgets/sp-color-scales.cpp:409
-#: ../src/widgets/sp-color-scales.cpp:410
-#: ../src/widgets/sp-color-scales.cpp:435
-#: ../src/widgets/sp-color-scales.cpp:436
-#: ../src/widgets/sp-color-scales.cpp:466
-#: ../src/widgets/sp-color-scales.cpp:467
-#: ../src/widgets/sp-color-wheel-selector.cpp:144
-#: ../src/widgets/sp-color-wheel-selector.cpp:156
+#: ../src/widgets/sp-color-scales.cpp:421
+#: ../src/widgets/sp-color-scales.cpp:422
+#: ../src/widgets/sp-color-scales.cpp:447
+#: ../src/widgets/sp-color-scales.cpp:448
+#: ../src/widgets/sp-color-scales.cpp:478
+#: ../src/widgets/sp-color-scales.cpp:479
+#: ../src/widgets/sp-color-wheel-selector.cpp:145
+#: ../src/widgets/sp-color-wheel-selector.cpp:157
 msgid "Alpha (opacity)"
 msgstr ""
 
-#: ../src/widgets/sp-color-notebook.cpp:330
+#: ../src/widgets/sp-color-notebook.cpp:339
+msgid "Color Managed"
+msgstr ""
+
+#: ../src/widgets/sp-color-notebook.cpp:347
+msgid "Out of gamut!"
+msgstr ""
+
+#: ../src/widgets/sp-color-notebook.cpp:355
+msgid "Too much ink!"
+msgstr ""
+
+#. Create RGBA entry and color preview
+#: ../src/widgets/sp-color-notebook.cpp:362
 msgid "RGBA_:"
 msgstr ""
 
-#: ../src/widgets/sp-color-notebook.cpp:338
+#: ../src/widgets/sp-color-notebook.cpp:370
 msgid "Hexadecimal RGBA value of the color"
 msgstr ""
 
-#: ../src/widgets/sp-color-scales.cpp:79
+#: ../src/widgets/sp-color-scales.cpp:81
 msgid "RGB"
 msgstr ""
 
-#: ../src/widgets/sp-color-scales.cpp:79
+#: ../src/widgets/sp-color-scales.cpp:81
 msgid "HSL"
 msgstr ""
 
-#: ../src/widgets/sp-color-scales.cpp:79
+#: ../src/widgets/sp-color-scales.cpp:81
 msgid "CMYK"
 msgstr ""
 
@@ -17983,7 +18181,7 @@ msgstr ""
 msgid "Unnamed"
 msgstr ""
 
-#: ../src/widgets/sp-color-wheel-selector.cpp:61
+#: ../src/widgets/sp-color-wheel-selector.cpp:62
 msgid "Wheel"
 msgstr ""
 
@@ -18613,12 +18811,12 @@ msgstr ""
 msgid "Scatter randomly the corners and angles"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:2855 ../src/widgets/toolbox.cpp:3794
-#: ../src/widgets/toolbox.cpp:4054 ../src/widgets/toolbox.cpp:7681
+#: ../src/widgets/toolbox.cpp:2855 ../src/widgets/toolbox.cpp:3797
+#: ../src/widgets/toolbox.cpp:4055 ../src/widgets/toolbox.cpp:7761
 msgid "Defaults"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:2856 ../src/widgets/toolbox.cpp:3795
+#: ../src/widgets/toolbox.cpp:2856 ../src/widgets/toolbox.cpp:3798
 msgid ""
 "Reset shape parameters to defaults (use Inkscape Preferences > Tools to "
 "change defaults)"
@@ -18681,1154 +18879,1154 @@ msgid "Make corners sharp"
 msgstr ""
 
 #. TODO: use the correct axis here, too
-#: ../src/widgets/toolbox.cpp:3379
+#: ../src/widgets/toolbox.cpp:3382
 msgid "3D Box: Change perspective (angle of infinite axis)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3449
+#: ../src/widgets/toolbox.cpp:3452
 msgid "Angle in X direction"
 msgstr ""
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3451
+#: ../src/widgets/toolbox.cpp:3454
 msgid "Angle of PLs in X direction"
 msgstr ""
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3473
+#: ../src/widgets/toolbox.cpp:3476
 msgid "State of VP in X direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3474
+#: ../src/widgets/toolbox.cpp:3477
 msgid "Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3489
+#: ../src/widgets/toolbox.cpp:3492
 msgid "Angle in Y direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3489
+#: ../src/widgets/toolbox.cpp:3492
 msgid "Angle Y:"
 msgstr ""
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3491
+#: ../src/widgets/toolbox.cpp:3494
 msgid "Angle of PLs in Y direction"
 msgstr ""
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3512
+#: ../src/widgets/toolbox.cpp:3515
 msgid "State of VP in Y direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3513
+#: ../src/widgets/toolbox.cpp:3516
 msgid "Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3528
+#: ../src/widgets/toolbox.cpp:3531
 msgid "Angle in Z direction"
 msgstr ""
 
 #. Translators: PL is short for 'perspective line'
-#: ../src/widgets/toolbox.cpp:3530
+#: ../src/widgets/toolbox.cpp:3533
 msgid "Angle of PLs in Z direction"
 msgstr ""
 
 #. Translators: VP is short for 'vanishing point'
-#: ../src/widgets/toolbox.cpp:3551
+#: ../src/widgets/toolbox.cpp:3554
 msgid "State of VP in Z direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3552
+#: ../src/widgets/toolbox.cpp:3555
 msgid "Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3610
+#: ../src/widgets/toolbox.cpp:3613
 msgid "Change spiral"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3751
+#: ../src/widgets/toolbox.cpp:3754
 msgid "just a curve"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3751
+#: ../src/widgets/toolbox.cpp:3754
 msgid "one full revolution"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Number of turns"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Turns:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3754
+#: ../src/widgets/toolbox.cpp:3757
 msgid "Number of revolutions"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "circle"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "edge is much denser"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "edge is denser"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "even"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "center is denser"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3765
+#: ../src/widgets/toolbox.cpp:3768
 msgid "center is much denser"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "Divergence"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "Divergence:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3768
+#: ../src/widgets/toolbox.cpp:3771
 msgid "How much denser/sparser are outer revolutions; 1 = uniform"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts from center"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts mid-way"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3779
+#: ../src/widgets/toolbox.cpp:3782
 msgid "starts near edge"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Inner radius"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Inner radius:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3782
+#: ../src/widgets/toolbox.cpp:3785
 msgid "Radius of the innermost revolution (relative to the spiral size)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3855
+#: ../src/widgets/toolbox.cpp:3858
 msgid "Bezier"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3856
+#: ../src/widgets/toolbox.cpp:3859
 msgid "Create regular Bezier path"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3862
+#: ../src/widgets/toolbox.cpp:3865
 msgid "Spiro"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3863
+#: ../src/widgets/toolbox.cpp:3866
 msgid "Create Spiro path"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3870
+#: ../src/widgets/toolbox.cpp:3873
 msgid "Zigzag"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3871
+#: ../src/widgets/toolbox.cpp:3874
 msgid "Create a sequence of straight line segments"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3877
+#: ../src/widgets/toolbox.cpp:3880
 msgid "Paraxial"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3878
+#: ../src/widgets/toolbox.cpp:3881
 msgid "Create a sequence of paraxial line segments"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3886
+#: ../src/widgets/toolbox.cpp:3889
 msgid "Mode of new lines drawn by this tool"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3915
+#: ../src/widgets/toolbox.cpp:3918
 msgid "Triangle in"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3916
+#: ../src/widgets/toolbox.cpp:3919
 msgid "Triangle out"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3918
+#: ../src/widgets/toolbox.cpp:3921
 msgid "From clipboard"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3943 ../src/widgets/toolbox.cpp:3944
+#: ../src/widgets/toolbox.cpp:3946 ../src/widgets/toolbox.cpp:3947
 msgid "Shape:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:3943
+#: ../src/widgets/toolbox.cpp:3946
 msgid "Shape of new paths drawn by this tool"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4028
+#: ../src/widgets/toolbox.cpp:4032
 msgid "(many nodes, rough)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4028 ../src/widgets/toolbox.cpp:4148
-#: ../src/widgets/toolbox.cpp:4165 ../src/widgets/toolbox.cpp:4368
-#: ../src/widgets/toolbox.cpp:4472 ../src/widgets/toolbox.cpp:4488
-#: ../src/widgets/toolbox.cpp:4504 ../src/widgets/toolbox.cpp:4564
-#: ../src/widgets/toolbox.cpp:4931 ../src/widgets/toolbox.cpp:4964
-#: ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4032 ../src/widgets/toolbox.cpp:4149
+#: ../src/widgets/toolbox.cpp:4166 ../src/widgets/toolbox.cpp:4369
+#: ../src/widgets/toolbox.cpp:4475 ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4507 ../src/widgets/toolbox.cpp:4567
+#: ../src/widgets/toolbox.cpp:4934 ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:5953
 msgid "(default)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4028
+#: ../src/widgets/toolbox.cpp:4032
 msgid "(few nodes, smooth)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4031
+#: ../src/widgets/toolbox.cpp:4035
 msgid "Smoothing:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4031
+#: ../src/widgets/toolbox.cpp:4035
 msgid "Smoothing: "
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4032
+#: ../src/widgets/toolbox.cpp:4036
 msgid "How much smoothing (simplifying) is applied to the line"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4055
+#: ../src/widgets/toolbox.cpp:4056
 msgid ""
 "Reset pencil parameters to defaults (use Inkscape Preferences > Tools to "
 "change defaults)"
 msgstr ""
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4148
+#: ../src/widgets/toolbox.cpp:4149
 msgid "(pinch tweak)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4148
+#: ../src/widgets/toolbox.cpp:4149
 msgid "(broad tweak)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4151
+#: ../src/widgets/toolbox.cpp:4152
 msgid "The width of the tweak area (relative to the visible canvas area)"
 msgstr ""
 
 #. Force
-#: ../src/widgets/toolbox.cpp:4165
+#: ../src/widgets/toolbox.cpp:4166
 msgid "(minimum force)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4165
+#: ../src/widgets/toolbox.cpp:4166
 msgid "(maximum force)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "Force"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "Force:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4168
+#: ../src/widgets/toolbox.cpp:4169
 msgid "The force of the tweak action"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4186
+#: ../src/widgets/toolbox.cpp:4187
 msgid "Move mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4187
+#: ../src/widgets/toolbox.cpp:4188
 msgid "Move objects in any direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4193
+#: ../src/widgets/toolbox.cpp:4194
 msgid "Move in/out mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4194
+#: ../src/widgets/toolbox.cpp:4195
 msgid "Move objects towards cursor; with Shift from cursor"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4200
+#: ../src/widgets/toolbox.cpp:4201
 msgid "Move jitter mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4201
+#: ../src/widgets/toolbox.cpp:4202
 msgid "Move objects in random directions"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4207
+#: ../src/widgets/toolbox.cpp:4208
 msgid "Scale mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4208
+#: ../src/widgets/toolbox.cpp:4209
 msgid "Shrink objects, with Shift enlarge"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4214
+#: ../src/widgets/toolbox.cpp:4215
 msgid "Rotate mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4215
+#: ../src/widgets/toolbox.cpp:4216
 msgid "Rotate objects, with Shift counterclockwise"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4221
+#: ../src/widgets/toolbox.cpp:4222
 msgid "Duplicate/delete mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4222
+#: ../src/widgets/toolbox.cpp:4223
 msgid "Duplicate objects, with Shift delete"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4228
+#: ../src/widgets/toolbox.cpp:4229
 msgid "Push mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4229
+#: ../src/widgets/toolbox.cpp:4230
 msgid "Push parts of paths in any direction"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4235
+#: ../src/widgets/toolbox.cpp:4236
 msgid "Shrink/grow mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4236
+#: ../src/widgets/toolbox.cpp:4237
 msgid "Shrink (inset) parts of paths; with Shift grow (outset)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4242
+#: ../src/widgets/toolbox.cpp:4243
 msgid "Attract/repel mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4243
+#: ../src/widgets/toolbox.cpp:4244
 msgid "Attract parts of paths towards cursor; with Shift from cursor"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4249
+#: ../src/widgets/toolbox.cpp:4250
 msgid "Roughen mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4250
+#: ../src/widgets/toolbox.cpp:4251
 msgid "Roughen parts of paths"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4256
+#: ../src/widgets/toolbox.cpp:4257
 msgid "Color paint mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4257
+#: ../src/widgets/toolbox.cpp:4258
 msgid "Paint the tool's color upon selected objects"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4263
+#: ../src/widgets/toolbox.cpp:4264
 msgid "Color jitter mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4264
+#: ../src/widgets/toolbox.cpp:4265
 msgid "Jitter the colors of selected objects"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4270
+#: ../src/widgets/toolbox.cpp:4271
 msgid "Blur mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4271
+#: ../src/widgets/toolbox.cpp:4272
 msgid "Blur selected objects more; with Shift, blur less"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4298
+#: ../src/widgets/toolbox.cpp:4299
 msgid "Channels:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4309
+#: ../src/widgets/toolbox.cpp:4310
 msgid "In color mode, act on objects' hue"
 msgstr ""
 
 #. TRANSLATORS:  "H" here stands for hue
-#: ../src/widgets/toolbox.cpp:4313
+#: ../src/widgets/toolbox.cpp:4314
 msgid "H"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4324
+#: ../src/widgets/toolbox.cpp:4325
 msgid "In color mode, act on objects' saturation"
 msgstr ""
 
 #. TRANSLATORS: "S" here stands for Saturation
-#: ../src/widgets/toolbox.cpp:4328
+#: ../src/widgets/toolbox.cpp:4329
 msgid "S"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4339
+#: ../src/widgets/toolbox.cpp:4340
 msgid "In color mode, act on objects' lightness"
 msgstr ""
 
 #. TRANSLATORS: "L" here stands for Lightness
-#: ../src/widgets/toolbox.cpp:4343
+#: ../src/widgets/toolbox.cpp:4344
 msgid "L"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4354
+#: ../src/widgets/toolbox.cpp:4355
 msgid "In color mode, act on objects' opacity"
 msgstr ""
 
 #. TRANSLATORS: "O" here stands for Opacity
-#: ../src/widgets/toolbox.cpp:4358
+#: ../src/widgets/toolbox.cpp:4359
 msgid "O"
 msgstr ""
 
 #. Fidelity
-#. Population
-#: ../src/widgets/toolbox.cpp:4368 ../src/widgets/toolbox.cpp:4564
+#: ../src/widgets/toolbox.cpp:4369
 msgid "(rough, simplified)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4368 ../src/widgets/toolbox.cpp:4564
+#: ../src/widgets/toolbox.cpp:4369
 msgid "(fine, but many nodes)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4371
+#: ../src/widgets/toolbox.cpp:4372
 msgid "Fidelity"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4371
+#: ../src/widgets/toolbox.cpp:4372
 msgid "Fidelity:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4372
+#: ../src/widgets/toolbox.cpp:4373
 msgid ""
 "Low fidelity simplifies paths; high fidelity preserves path features but may "
 "generate a lot of new nodes"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4389 ../src/widgets/toolbox.cpp:4582
-#: ../src/widgets/toolbox.cpp:5082
+#: ../src/widgets/toolbox.cpp:4390 ../src/widgets/toolbox.cpp:4585
+#: ../src/widgets/toolbox.cpp:5085
 msgid "Pressure"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4390
+#: ../src/widgets/toolbox.cpp:4391
 msgid "Use the pressure of the input device to alter the force of tweak action"
 msgstr ""
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4472
-msgid "(pinch spray)"
+#: ../src/widgets/toolbox.cpp:4475
+msgid "(narrow spray)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4472
+#: ../src/widgets/toolbox.cpp:4475
 msgid "(broad spray)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4475
+#: ../src/widgets/toolbox.cpp:4478
 msgid "The width of the spray area (relative to the visible canvas area)"
 msgstr ""
 
 #. Mean
-#: ../src/widgets/toolbox.cpp:4488
+#: ../src/widgets/toolbox.cpp:4491
 msgid "(minimum mean)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4488
+#: ../src/widgets/toolbox.cpp:4491
 msgid "(maximum mean)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4491 ../share/extensions/polyhedron_3d.inx.h:25
+#: ../src/widgets/toolbox.cpp:4494 ../share/extensions/polyhedron_3d.inx.h:25
 msgid "Mean"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4494
 msgid "Mean:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4491
+#: ../src/widgets/toolbox.cpp:4494
 msgid "The mean of the spray action"
 msgstr ""
 
 #. Standard_deviation
-#: ../src/widgets/toolbox.cpp:4504
+#: ../src/widgets/toolbox.cpp:4507
 msgid "(minimum standard_deviation)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4504
+#: ../src/widgets/toolbox.cpp:4507
 msgid "(maximum standard_deviation)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "SD"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "SD:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4507
+#: ../src/widgets/toolbox.cpp:4510
 msgid "The standard deviation of the spray action"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4525
-msgid "Spray with copies"
-msgstr ""
-
-#: ../src/widgets/toolbox.cpp:4526
+#: ../src/widgets/toolbox.cpp:4529
 msgid "Spray copies of the initial selection"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4532
-msgid "Spray with clones"
-msgstr ""
-
-#: ../src/widgets/toolbox.cpp:4533
+#: ../src/widgets/toolbox.cpp:4536
 msgid "Spray clones of the initial selection"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4539
+#: ../src/widgets/toolbox.cpp:4542
 msgid "Spray single path"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4540
+#: ../src/widgets/toolbox.cpp:4543
 msgid "Spray objects in a single path"
 msgstr ""
 
+#. Population
 #: ../src/widgets/toolbox.cpp:4567
-msgid "Population"
+msgid "(low population)"
 msgstr ""
 
 #: ../src/widgets/toolbox.cpp:4567
+msgid "(high population)"
+msgstr ""
+
+#: ../src/widgets/toolbox.cpp:4570
+msgid "Population"
+msgstr ""
+
+#: ../src/widgets/toolbox.cpp:4570
 msgid "Population:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4568
+#: ../src/widgets/toolbox.cpp:4571
 msgid "This setting adjusts the number of items sprayed"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4583
+#: ../src/widgets/toolbox.cpp:4586
 msgid "Use the pressure of the input device to alter the force of spray action"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4762
+#: ../src/widgets/toolbox.cpp:4765
 msgid "No preset"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4780
+#: ../src/widgets/toolbox.cpp:4783
 msgid "Save..."
 msgstr ""
 
 #. Width
-#: ../src/widgets/toolbox.cpp:4931 ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4934 ../src/widgets/toolbox.cpp:5953
 msgid "(hairline)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4931 ../src/widgets/toolbox.cpp:5950
+#: ../src/widgets/toolbox.cpp:4934 ../src/widgets/toolbox.cpp:5953
 msgid "(broad stroke)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4934 ../src/widgets/toolbox.cpp:5953
+#: ../src/widgets/toolbox.cpp:4937 ../src/widgets/toolbox.cpp:5956
 msgid "Pen Width"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4935
+#: ../src/widgets/toolbox.cpp:4938
 msgid "The width of the calligraphic pen (relative to the visible canvas area)"
 msgstr ""
 
 #. Thinning
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(speed blows up stroke)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(slight widening)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(constant width)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(slight thinning, default)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4948
+#: ../src/widgets/toolbox.cpp:4951
 msgid "(speed deflates stroke)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4951
+#: ../src/widgets/toolbox.cpp:4954
 msgid "Stroke Thinning"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4951
+#: ../src/widgets/toolbox.cpp:4954
 msgid "Thinning:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4952
+#: ../src/widgets/toolbox.cpp:4955
 msgid ""
 "How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 "
 "makes them broader, 0 makes width independent of velocity)"
 msgstr ""
 
 #. Angle
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(left edge up)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(horizontal)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4964
+#: ../src/widgets/toolbox.cpp:4967
 msgid "(right edge up)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:4970
 msgid "Pen Angle"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4967
+#: ../src/widgets/toolbox.cpp:4970
 msgid "Angle:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4968
+#: ../src/widgets/toolbox.cpp:4971
 msgid ""
 "The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if "
 "fixation = 0)"
 msgstr ""
 
 #. Fixation
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(perpendicular to stroke, \"brush\")"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(almost fixed, default)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4982
+#: ../src/widgets/toolbox.cpp:4985
 msgid "(fixed by Angle, \"pen\")"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4985
+#: ../src/widgets/toolbox.cpp:4988
 msgid "Fixation"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4985
+#: ../src/widgets/toolbox.cpp:4988
 msgid "Fixation:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4986
+#: ../src/widgets/toolbox.cpp:4989
 msgid ""
 "Angle behavior (0 = nib always perpendicular to stroke direction, 100 = "
 "fixed angle)"
 msgstr ""
 
 #. Cap Rounding
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(blunt caps, default)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(slightly bulging)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(approximately round)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:4998
+#: ../src/widgets/toolbox.cpp:5001
 msgid "(long protruding caps)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5002
+#: ../src/widgets/toolbox.cpp:5005
 msgid "Cap rounding"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5002
+#: ../src/widgets/toolbox.cpp:5005
 msgid "Caps:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5003
+#: ../src/widgets/toolbox.cpp:5006
 msgid ""
 "Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = "
 "round caps)"
 msgstr ""
 
 #. Tremor
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(smooth line)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(slight tremor)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(noticeable tremor)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5015
+#: ../src/widgets/toolbox.cpp:5018
 msgid "(maximum tremor)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5018
+#: ../src/widgets/toolbox.cpp:5021
 msgid "Stroke Tremor"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5018
+#: ../src/widgets/toolbox.cpp:5021
 msgid "Tremor:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5019
+#: ../src/widgets/toolbox.cpp:5022
 msgid "Increase to make strokes rugged and trembling"
 msgstr ""
 
 #. Wiggle
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(no wiggle)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(slight deviation)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5033
+#: ../src/widgets/toolbox.cpp:5036
 msgid "(wild waves and curls)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5036
+#: ../src/widgets/toolbox.cpp:5039
 msgid "Pen Wiggle"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5036
+#: ../src/widgets/toolbox.cpp:5039
 msgid "Wiggle:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5037
+#: ../src/widgets/toolbox.cpp:5040
 msgid "Increase to make the pen waver and wiggle"
 msgstr ""
 
 #. Mass
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(no inertia)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(slight smoothing, default)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(noticeable lagging)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5050
+#: ../src/widgets/toolbox.cpp:5053
 msgid "(maximum inertia)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5053
+#: ../src/widgets/toolbox.cpp:5056
 msgid "Pen Mass"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5053
+#: ../src/widgets/toolbox.cpp:5056
 msgid "Mass:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5054
+#: ../src/widgets/toolbox.cpp:5057
 msgid "Increase to make the pen drag behind, as if slowed by inertia"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5069
+#: ../src/widgets/toolbox.cpp:5072
 msgid "Trace Background"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5070
+#: ../src/widgets/toolbox.cpp:5073
 msgid ""
 "Trace the lightness of the background by the width of the pen (white - "
 "minimum width, black - maximum width)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5083
+#: ../src/widgets/toolbox.cpp:5086
 msgid "Use the pressure of the input device to alter the width of the pen"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5095
+#: ../src/widgets/toolbox.cpp:5098
 msgid "Tilt"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5096
+#: ../src/widgets/toolbox.cpp:5099
 msgid "Use the tilt of the input device to alter the angle of the pen's nib"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5109
+#: ../src/widgets/toolbox.cpp:5112
 msgid "Choose a preset"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5197
+#: ../src/widgets/toolbox.cpp:5200
 msgid "Arc: Change start/end"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5261
+#: ../src/widgets/toolbox.cpp:5264
 msgid "Arc: Change open/closed"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5387
+#: ../src/widgets/toolbox.cpp:5390
 msgid "Start:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5388
+#: ../src/widgets/toolbox.cpp:5391
 msgid "The angle (in degrees) from the horizontal to the arc's start point"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5400
+#: ../src/widgets/toolbox.cpp:5403
 msgid "End:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5401
+#: ../src/widgets/toolbox.cpp:5404
 msgid "The angle (in degrees) from the horizontal to the arc's end point"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5417
+#: ../src/widgets/toolbox.cpp:5420
 msgid "Closed arc"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5418
+#: ../src/widgets/toolbox.cpp:5421
 msgid "Switch to segment (closed shape with two radii)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5424
+#: ../src/widgets/toolbox.cpp:5427
 msgid "Open Arc"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5425
+#: ../src/widgets/toolbox.cpp:5428
 msgid "Switch to arc (unclosed shape)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5448
+#: ../src/widgets/toolbox.cpp:5451
 msgid "Make whole"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5449
+#: ../src/widgets/toolbox.cpp:5452
 msgid "Make the shape a whole ellipse, not arc or segment"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5525
+#: ../src/widgets/toolbox.cpp:5528
 msgid "Pick opacity"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5526
+#: ../src/widgets/toolbox.cpp:5529
 msgid ""
 "Pick both the color and the alpha (transparency) under cursor; otherwise, "
 "pick only the visible color premultiplied by alpha"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5529
+#: ../src/widgets/toolbox.cpp:5532
 msgid "Pick"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5538
+#: ../src/widgets/toolbox.cpp:5541
 msgid "Assign opacity"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5539
+#: ../src/widgets/toolbox.cpp:5542
 msgid ""
 "If alpha was picked, assign it to selection as fill or stroke transparency"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5542
+#: ../src/widgets/toolbox.cpp:5545
 msgid "Assign"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5728
+#: ../src/widgets/toolbox.cpp:5731
 msgid "Closed"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5730
+#: ../src/widgets/toolbox.cpp:5733
 msgid "Open start"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5732
+#: ../src/widgets/toolbox.cpp:5735
 msgid "Open end"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5734
+#: ../src/widgets/toolbox.cpp:5737
 msgid "Open both"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5793
+#: ../src/widgets/toolbox.cpp:5796
 msgid "All inactive"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5794
+#: ../src/widgets/toolbox.cpp:5797
 msgid "No geometric tool is active"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5827
+#: ../src/widgets/toolbox.cpp:5830
 msgid "Show limiting bounding box"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5828
+#: ../src/widgets/toolbox.cpp:5831
 msgid "Show bounding box (used to cut infinite lines)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5839
+#: ../src/widgets/toolbox.cpp:5842
 msgid "Get limiting bounding box from selection"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5840
+#: ../src/widgets/toolbox.cpp:5843
 msgid ""
 "Set limiting bounding box (used to cut infinite lines) to the bounding box "
 "of current selection"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5852
+#: ../src/widgets/toolbox.cpp:5855
 msgid "Choose a line segment type"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5868
+#: ../src/widgets/toolbox.cpp:5871
 msgid "Display measuring info"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5869
+#: ../src/widgets/toolbox.cpp:5872
 msgid "Display measuring info for selected items"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5889
+#: ../src/widgets/toolbox.cpp:5892
 msgid "Open LPE dialog"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5890
+#: ../src/widgets/toolbox.cpp:5893
 msgid "Open LPE dialog (to adapt parameters numerically)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5954
+#: ../src/widgets/toolbox.cpp:5957
 msgid "The width of the eraser pen (relative to the visible canvas area)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5972
+#: ../src/widgets/toolbox.cpp:5975
 msgid "Delete objects touched by the eraser"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5978
+#: ../src/widgets/toolbox.cpp:5981
 msgid "Cut"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:5979
+#: ../src/widgets/toolbox.cpp:5982
 msgid "Cut out from objects"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6323
+#: ../src/widgets/toolbox.cpp:6326
 msgid "Text: Change font family"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6393
+#: ../src/widgets/toolbox.cpp:6473
 msgid "Text: Change alignment"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6497
+#: ../src/widgets/toolbox.cpp:6577
 msgid "Text: Change font style"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6544
+#: ../src/widgets/toolbox.cpp:6624
 msgid "Text: Change orientation"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6658
+#: ../src/widgets/toolbox.cpp:6738
 msgid "Text: Change font size"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6877
+#: ../src/widgets/toolbox.cpp:6957
 msgid "Select font family (Alt+X to access)"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6914
+#: ../src/widgets/toolbox.cpp:6994
 msgid ""
 "This font is currently not installed on your system. Inkscape will use the "
 "default font instead."
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6950
+#: ../src/widgets/toolbox.cpp:7030
 msgid "Align left"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6972
+#: ../src/widgets/toolbox.cpp:7052
 msgid "Align right"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6983
+#: ../src/widgets/toolbox.cpp:7063
 msgid "Justify"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:6998
+#: ../src/widgets/toolbox.cpp:7078
 msgid "Bold"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7009
+#: ../src/widgets/toolbox.cpp:7089
 msgid "Italic"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7148
+#: ../src/widgets/toolbox.cpp:7228
 msgid "Set connector type: orthogonal"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7148
+#: ../src/widgets/toolbox.cpp:7228
 msgid "Set connector type: polyline"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7198
+#: ../src/widgets/toolbox.cpp:7278
 msgid "Change connector curvature"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7247
+#: ../src/widgets/toolbox.cpp:7327
 msgid "Change connector spacing"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7361
+#: ../src/widgets/toolbox.cpp:7441
 msgid "EditMode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7362
+#: ../src/widgets/toolbox.cpp:7442
 msgid "Switch between connection point editing and connector drawing mode"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7376
+#: ../src/widgets/toolbox.cpp:7456
 msgid "Avoid"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7386
+#: ../src/widgets/toolbox.cpp:7466
 msgid "Ignore"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7397
+#: ../src/widgets/toolbox.cpp:7477
 msgid "Orthogonal"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7398
+#: ../src/widgets/toolbox.cpp:7478
 msgid "Make connector orthogonal or polyline"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7412
+#: ../src/widgets/toolbox.cpp:7492
 msgid "Connector Curvature"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7412
+#: ../src/widgets/toolbox.cpp:7492
 msgid "Curvature:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7413
+#: ../src/widgets/toolbox.cpp:7493
 msgid "The amount of connectors curvature"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7423
+#: ../src/widgets/toolbox.cpp:7503
 msgid "Connector Spacing"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7423
+#: ../src/widgets/toolbox.cpp:7503
 msgid "Spacing:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7424
+#: ../src/widgets/toolbox.cpp:7504
 msgid "The amount of space left around objects by auto-routing connectors"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7435
+#: ../src/widgets/toolbox.cpp:7515
 msgid "Graph"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7445
+#: ../src/widgets/toolbox.cpp:7525
 msgid "Connector Length"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7445
+#: ../src/widgets/toolbox.cpp:7525
 msgid "Length:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7446
+#: ../src/widgets/toolbox.cpp:7526
 msgid "Ideal length for connectors when layout is applied"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7458
+#: ../src/widgets/toolbox.cpp:7538
 msgid "Downwards"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7459
+#: ../src/widgets/toolbox.cpp:7539
 msgid "Make connectors with end-markers (arrows) point downwards"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7476
+#: ../src/widgets/toolbox.cpp:7556
 msgid "Do not allow overlapping shapes"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7491
+#: ../src/widgets/toolbox.cpp:7571
 msgid "New connection point"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7492
+#: ../src/widgets/toolbox.cpp:7572
 msgid "Add a new connection point to the currently selected item"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7503
+#: ../src/widgets/toolbox.cpp:7583
 msgid "Remove connection point"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7504
+#: ../src/widgets/toolbox.cpp:7584
 msgid "Remove the currently selected connection point"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7604
+#: ../src/widgets/toolbox.cpp:7684
 msgid "Fill by"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7605
+#: ../src/widgets/toolbox.cpp:7685
 msgid "Fill by:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7617
+#: ../src/widgets/toolbox.cpp:7697
 msgid "Fill Threshold"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7618
+#: ../src/widgets/toolbox.cpp:7698
 msgid ""
 "The maximum allowed difference between the clicked pixel and the neighboring "
 "pixels to be counted in the fill"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7643
+#: ../src/widgets/toolbox.cpp:7723
 msgid "Grow/shrink by"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7643
+#: ../src/widgets/toolbox.cpp:7723
 msgid "Grow/shrink by:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7644
+#: ../src/widgets/toolbox.cpp:7724
 msgid ""
 "The amount to grow (positive) or shrink (negative) the created fill path"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7669
+#: ../src/widgets/toolbox.cpp:7749
 msgid "Close gaps"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7670
+#: ../src/widgets/toolbox.cpp:7750
 msgid "Close gaps:"
 msgstr ""
 
-#: ../src/widgets/toolbox.cpp:7682
+#: ../src/widgets/toolbox.cpp:7762
 msgid ""
 "Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools "
 "to change defaults)"
@@ -19877,18 +20075,18 @@ msgid ""
 "required by this extension. Please install them and try again."
 msgstr ""
 
-#: ../share/extensions/embedimage.py:74
+#: ../share/extensions/embedimage.py:75
 msgid ""
 "No xlink:href or sodipodi:absref attributes found, or they do not point to "
 "an existing file! Unable to embed image."
 msgstr ""
 
-#: ../share/extensions/embedimage.py:76
+#: ../share/extensions/embedimage.py:77
 #, python-format
 msgid "Sorry we could not locate %s"
 msgstr ""
 
-#: ../share/extensions/embedimage.py:101
+#: ../share/extensions/embedimage.py:102
 #, python-format
 msgid ""
 "%s is not of type image/png, image/jpeg, image/bmp, image/gif, image/tiff, "
@@ -19905,7 +20103,7 @@ msgstr ""
 msgid "Unable to find image data."
 msgstr ""
 
-#: ../share/extensions/inkex.py:66
+#: ../share/extensions/inkex.py:67
 msgid ""
 "The fantastic lxml wrapper for libxml2 is required by inkex.py and therefore "
 "this extension. Please download and install the latest version from http://"
@@ -19913,7 +20111,7 @@ msgid ""
 "by a command like: sudo apt-get install python-lxml"
 msgstr ""
 
-#: ../share/extensions/inkex.py:222
+#: ../share/extensions/inkex.py:223
 #, python-format
 msgid "No matching node for expression: %s"
 msgstr ""
@@ -21655,14 +21853,6 @@ msgstr ""
 msgid "Load from file"
 msgstr ""
 
-#: ../share/extensions/polyhedron_3d.inx.h:24
-msgid "Maximum"
-msgstr ""
-
-#: ../share/extensions/polyhedron_3d.inx.h:26
-msgid "Minimum"
-msgstr ""
-
 #: ../share/extensions/polyhedron_3d.inx.h:27
 msgid "Model file"
 msgstr ""
@@ -21890,6 +22080,22 @@ msgstr ""
 msgid "Barcode Type:"
 msgstr ""
 
+#: ../share/extensions/render_barcode_datamatrix.inx.h:1
+msgid "Barcode - Datamatrix"
+msgstr ""
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:2
+msgid "Cols"
+msgstr ""
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:4
+msgid "Rows"
+msgstr ""
+
+#: ../share/extensions/render_barcode_datamatrix.inx.h:5
+msgid "Square Size / px"
+msgstr ""
+
 #: ../share/extensions/restack.inx.h:2
 msgid "Arbitrary Angle:"
 msgstr ""
@@ -22556,6 +22762,34 @@ msgstr ""
 msgid "Whirl"
 msgstr ""
 
+#: ../share/extensions/wireframe_sphere.inx.h:1
+msgid "Hide lines behind the sphere"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:2
+msgid "Lines of latitude"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:3
+msgid "Lines of longitude"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:4
+msgid "Radius [px]"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:6
+msgid "Rotation [deg]"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:7
+msgid "Tilt [deg]"
+msgstr ""
+
+#: ../share/extensions/wireframe_sphere.inx.h:8
+msgid "Wireframe Sphere"
+msgstr ""
+
 #: ../share/extensions/wmf_input.inx.h:1
 #: ../share/extensions/wmf_output.inx.h:1
 msgid "A popular graphics file format for clipart"
diff --git a/share/extensions/Barcode/EAN5.py b/share/extensions/Barcode/EAN5.py
new file mode 100644 (file)
index 0000000..9113566
--- /dev/null
@@ -0,0 +1,67 @@
+''' 
+Copyright (C) 2007 Martin Owens 
+Copyright (C) 2009 Aaron C Spike 
+
+Thanks to Lineaire Chez of Inkbar ( www.inkbar.lineaire.net ) 
+
+This program is free software; you can redistribute it and/or modify 
+it under the terms of the GNU General Public License as published by 
+the Free Software Foundation; either version 2 of the License, or 
+(at your option) any later version. 
+
+This program is distributed in the hope that it will be useful, 
+but WITHOUT ANY WARRANTY; without even the implied warranty of 
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+GNU General Public License for more details. 
+
+You should have received a copy of the GNU General Public License 
+along with this program; if not, write to the Free Software 
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+'''
+
+from Base import Barcode
+import sys
+
+mapLeftFamily = [
+    [ "0001101","0011001","0010011","0111101","0100011","0110001","0101111","0111011","0110111","0001011" ], #L
+    [ "0100111","0110011","0011011","0100001","0011101","0111001","0000101","0010001","0001001","0010111" ], #G
+]
+mapFamily  = [ '11000','10100','10010','10001','01100','00110','00011','01010','01001','00101' ]
+
+startBar = '01011';
+sepBar = '01';
+
+class Object(Barcode):
+    def encode(self, number):
+        result = []
+        self.x += 110.0             # horizontal offset so it does not overlap EAN13
+        self.y -= self.height + 5   # move the text to the top
+        if len(number) != 5 or not number.isdigit():
+            sys.stderr.write("Can not encode '" + number + "' into EAN5 Barcode, Size must be 5 numbers only\n")
+            return
+
+        check = self.getChecksum(number)
+        family = mapFamily[check]
+
+        for i in range(5):
+            mapLeft = mapLeftFamily[int(family[i])]
+            result.append(mapLeft[int(number[i])])
+
+        self.label = number[0]
+        for i in range(1,5):
+            self.label += ' ' + number[i]
+        self.inclabel = self.label
+        return startBar + '01'.join(result)
+
+    def getChecksum(self, number):
+        return sum([int(n)*int(m) for n,m in zip(number, '39393')]) % 10
+
+    def getStyle(self, index):
+        result = { 'width' : '1', 'top' : int(self.y) + self.height + 5 + int(self.fontSize()), 'write' : True }
+        if index==0: # White Space
+            result['write'] = False
+        elif index==1: # Black Bar
+            result['height'] = int(self.height)
+        elif index==2: # Guide Bar
+            result['height'] = int(self.height) + 5
+        return result
index 338c01c10545b4b5470e0cd512e011285c21ac62..fd5f1663b9fe3547c070ca9956964d3acf09f876 100644 (file)
@@ -9,6 +9,7 @@ barcode_SCRIPTS = \
        Code93.py \
        EAN13.py \
        EAN8.py \
+       EAN5.py \
        __init__.py \
        RM4CC.py \
        UPCA.py \
index a455c3b7c9ee10c6ca37bf929f25ab69910456ed..b2257ebcbdb84b737ac79608ea5443e5c74d6863 100644 (file)
@@ -74,6 +74,9 @@ def getBarcode(format, param={}):
                elif format in ['ean13', 'ucc13','jan']:
                        import EAN13
                        return EAN13.Object(param)
+               elif format == 'ean5':
+                       import EAN5
+                       return EAN5.Object(param)
                elif format in ['ean8', 'ucc8']:
                        import EAN8
                        return EAN8.Object(param)
index 14238ad31f61c838e7969f55d76edd98cb7f7747..1650923e07350b9afad5c7afa1f91d5e08bf7507 100644 (file)
@@ -96,6 +96,7 @@ extensions = \
        radiusrand.py \
        restack.py \
        render_barcode.py \
+       render_barcode_datamatrix.py \
        render_alphabetsoup.py \
        render_alphabetsoup_config.py \
        rtree.py \
@@ -131,6 +132,7 @@ extensions = \
        web-set-att.py \
        web-transmit-att.py \
        whirl.py \
+       wireframe_sphere.py \
        wmf_output.py \
        yocto_css.py
 
@@ -222,6 +224,7 @@ modules = \
        ps_input.inx \
        radiusrand.inx \
        render_barcode.inx \
+       render_barcode_datamatrix.inx \
        render_alphabetsoup.inx \
        restack.inx \
        rubberstretch.inx \
@@ -249,6 +252,7 @@ modules = \
        web-set-att.inx \
        web-transmit-att.inx \
        whirl.inx \
+       wireframe_sphere.inx \
        wmf_input.inx \
        wmf_output.inx \
        xaml2svg.inx
index 610c8bf19fcca24d178f575150ca05845c40e71b..91dd1bbe434cdf60e8a6b2fb4724d40bb0f117be 100644 (file)
@@ -1,29 +1,30 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
-  <_name>Barcode</_name>
-  <id>org.inkscape.render.barcode</id>
-  <dependency type="executable" location="extensions">inkex.py</dependency>
-  <dependency type="executable" location="extensions">render_barcode.py</dependency>
-  <param name="type" type="enum" _gui-text="Barcode Type:">
-    <item value="ean8">EAN8</item>
-    <item value="ean13">EAN13</item>
-    <item value="upca">UPC-A</item>
-    <item value="upce">UPC-E</item>
-    <item value="code39">Code39</item>
-    <item value="code39ext">Code39Ext</item>
-    <item value="code93">Code93</item>
-    <item value="code128">Code128</item>
-    <item value="rm4scc">RM4CC / RM4SCC</item>
-  </param>
-  <param name="text" type="string" _gui-text="Barcode Data:"></param>
-  <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param>
-  <effect>
-    <object-type>all</object-type>
-    <effects-menu>
-      <submenu _name="Render"/>
-    </effects-menu>
-  </effect>
-  <script>
-    <command reldir="extensions" interpreter="python">render_barcode.py</command>
-  </script>
+       <_name>Barcode</_name>
+       <id>org.inkscape.render.barcode</id>
+       <dependency type="executable" location="extensions">inkex.py</dependency>
+       <dependency type="executable" location="extensions">render_barcode.py</dependency>
+       <param name="type" type="enum" _gui-text="Barcode Type:">
+               <item value="ean8">EAN8</item>
+               <item value="ean13">EAN13</item>
+               <item value="ean5">EAN5</item>
+               <item value="upca">UPC-A</item>
+               <item value="upce">UPC-E</item>
+               <item value="code39">Code39</item>
+               <item value="code39ext">Code39Ext</item>
+               <item value="code93">Code93</item>
+               <item value="code128">Code128</item>
+               <item value="rm4scc">RM4CC / RM4SCC</item>
+       </param>
+       <param name="text" type="string" _gui-text="Barcode Data:"></param>
+       <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param>
+       <effect>
+               <object-type>all</object-type>
+               <effects-menu>
+                       <submenu _name="Render"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">render_barcode.py</command>
+       </script>
 </inkscape-extension>
diff --git a/share/extensions/render_barcode_datamatrix.inx b/share/extensions/render_barcode_datamatrix.inx
new file mode 100644 (file)
index 0000000..ea2aa47
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+       <_name>Barcode - Datamatrix</_name>
+       <id>il.datamatrix</id>
+       <dependency type="executable" location="extensions">render_barcode_datamatrix.py</dependency>
+       <dependency type="executable" location="extensions">inkex.py</dependency>
+       <param name="text" type="string" _gui-text="Text">Inkscape</param>
+       <param name="rows" type="int" min="8" max="144" _gui-text="Rows">10</param>
+       <param name="cols" type="int" min="10" max="144" _gui-text="Cols">10</param>
+       <param name="size" type="int" min="1" max="1000" _gui-text="Square Size / px">4</param>
+       <effect>
+               <object-type>all</object-type>
+               <effects-menu>
+                       <submenu _name="Render"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">render_barcode_datamatrix.py</command>
+       </script>
+</inkscape-extension>
diff --git a/share/extensions/render_barcode_datamatrix.py b/share/extensions/render_barcode_datamatrix.py
new file mode 100644 (file)
index 0000000..5db552d
--- /dev/null
@@ -0,0 +1,654 @@
+#!/usr/bin/env python 
+# -*- coding: UTF-8 -*-
+'''
+Copyright (C) 2009 John Beard john.j.beard@gmail.com
+
+######DESCRIPTION######
+
+This extension renders a DataMatrix 2D barcode, as specified in
+BS ISO/IEC 16022:2006. Only ECC200 codes are considered, as these are the only
+ones recommended for an "open" system.
+
+The size of the DataMatrix is variable between 10x10 to 144x144
+
+The absolute size of the DataMatrix modules (the little squares) is also
+variable.
+
+If more data is given than can be contained in one DataMatrix,
+more than one DataMatrices will be produced.
+
+Text is encoded as ASCII (the standard provides for other options, but these are
+not implemented). Consecutive digits are encoded in a compressed form, halving 
+the space required to store them.
+
+The basis processing flow is;
+    * Convert input string to codewords (modified ASCII and compressed digits)
+    * Split codewords into blocks of the right size for Reed-Solomon coding
+    * Interleave the blocks if required
+    * Apply Reed-Solomon coding
+    * De-interleave the blocks if required
+    * Place the codewords into the matrix bit by bit
+    * Render the modules in the matrix as squares
+
+######LICENCE#######
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+######VERSION HISTORY#####
+    Ver.       Date                       Notes
+    
+    0.50    2009-10-25  Full functionality, up to 144x144.
+                        ASCII and compressed digit encoding only.
+'''
+
+import inkex, simplestyle
+
+import gettext
+_ = gettext.gettext
+    
+#ENCODING ROUTINES ===================================================
+#   Take an input string and convert it to a sequence (or sequences)
+#   of codewords as specified in ISO/IEC 16022:2006 (section 5.2.3)
+#=====================================================================
+    
+#create a 2d list corresponding to the 1's and 0s of the DataMatrix
+def encode(text, (nrow, ncol) ):
+    #retreive the parameters of this size of DataMatrix
+    data_nrow, data_ncol, reg_row, reg_col, nd, nc, inter = get_parameters( nrow, ncol )
+
+    if not ((nrow == 144) and (ncol == 144)):   #we have a regular datamatrix
+        size144 = False
+    else: #special handling will be required by get_codewords()
+        size144 = True
+        
+    #generate the codewords including padding and ECC
+    codewords = get_codewords( text, nd, nc, inter, size144 )
+    
+    # break up into separate arrays if more than one DataMatrix is needed
+    module_arrays = []
+    for codeword_stream in codewords:  #for each datamatrix
+        bit_array = place_bits(codeword_stream, (data_nrow*reg_row, data_ncol*reg_col)) #place the codewords' bits across the array as modules
+        module_arrays.append(add_finder_pattern( bit_array, data_nrow, data_ncol, reg_row, reg_col )) #add finder patterns around the modules
+    
+    return module_arrays
+
+#return parameters for the selected datamatrix size
+#   data_nrow   number of rows in each data region
+#   data_ncol   number of cols in each data region
+#   reg_row     number of rows of data regions
+#   reg_col     number of cols of data regions
+#   nd          number of data codewords per reed-solomon block
+#   nc          number of ECC codewords per reed-solomon block
+#   inter       number of interleaved Reed-Solomon blocks
+def get_parameters(nrow, ncol):
+
+    #SQUARE SYMBOLS
+    if ( nrow ==  10 and ncol ==  10 ):
+        return  8,  8, 1, 1, 3, 5, 1
+    elif ( nrow ==  12 and ncol ==  12 ):
+        return 10, 10, 1, 1, 5, 7, 1
+    elif ( nrow ==  14 and ncol ==  14 ):
+        return 12, 12, 1, 1, 8, 10, 1
+    elif ( nrow ==  16 and ncol ==  16 ):
+        return 14, 14, 1, 1, 12, 12, 1
+    elif ( nrow ==  18 and ncol ==  18 ):
+        return 16, 16, 1, 1, 18, 14, 1
+    elif ( nrow ==  20 and ncol ==  20 ):
+        return 18, 18, 1, 1, 22, 18, 1
+    elif ( nrow ==  22 and ncol ==  22 ):
+        return 18, 18, 1, 1, 30, 20, 1
+    elif ( nrow ==  24 and ncol ==  24 ):
+        return 22, 22, 1, 1, 36, 24, 1
+    elif ( nrow ==  26 and ncol ==  26 ):
+        return 24, 24, 1, 1, 44, 28, 1
+    elif ( nrow ==  32 and ncol ==  32 ):
+        return 14, 14, 2, 2, 62, 36, 1
+    elif ( nrow ==  36 and ncol ==  36 ):
+        return 16, 16, 2, 2, 86, 42, 1
+    elif ( nrow ==  40 and ncol ==  40):
+        return 18, 18, 2, 2, 114, 48, 1
+    elif ( nrow ==  44 and ncol ==  44):
+        return 20, 20, 2, 2, 144, 56, 1
+    elif ( nrow ==  48 and ncol ==  48 ):
+        return 22, 22, 2, 2, 174, 68, 1
+        
+    elif ( nrow ==  52 and ncol ==  52 ):
+        return 24, 24, 2, 2, 102, 42, 2
+    elif ( nrow ==  64 and ncol ==  64 ):
+        return 16, 16, 4, 4, 140, 56, 2
+        
+    elif ( nrow ==  72 and ncol ==  72 ):
+        return 16, 16, 4, 4, 92, 36, 4
+    elif ( nrow ==  80 and ncol ==  80 ):
+        return 18, 18, 4, 4, 114, 48, 4
+    elif ( nrow ==  88 and ncol ==  88 ):
+        return 20, 20, 4, 4, 144, 56, 4
+    elif ( nrow ==  96 and ncol ==  96 ):
+        return 22, 22, 4, 4, 174, 68, 4
+        
+    elif ( nrow ==  104 and ncol ==  104 ):
+        return 24, 24, 4, 4, 136, 56, 6    
+    elif ( nrow ==  120 and ncol ==  120):
+        return 18, 18, 6, 6, 175, 68, 6
+        
+    elif ( nrow ==  132 and ncol ==  132):
+        return 20, 20, 6, 6, 163, 62, 8
+        
+    elif (nrow == 144 and ncol == 144):
+        return 22, 22, 6, 6, 0, 0, 0        #there are two separate sections of the data matrix with
+                                            #different interleaving and reed-solomon parameters.
+                                            #this will be handled separately
+    
+    #RECTANGULAR SYMBOLS
+    elif ( nrow ==  8 and ncol ==  18 ):
+        return  6, 16, 1, 1, 5, 7, 1
+    elif ( nrow ==  8 and ncol ==  32 ):
+        return  6, 14, 1, 2, 10, 11, 1
+    elif ( nrow ==  12 and ncol ==  26 ):
+        return  10, 24, 1, 1, 16, 14, 1
+    elif ( nrow ==  12 and ncol ==  36 ):
+        return  10, 16, 1, 2, 22, 18, 1
+    elif ( nrow ==  16 and ncol ==  36 ):
+        return  14, 16, 1, 2, 32, 24, 1
+    elif ( nrow ==  16 and ncol ==  48 ):
+        return  14, 22, 1, 2, 49, 28, 1
+    
+    #RETURN ERROR
+    else:
+        inkex.errormsg(_('Unrecognised DataMatrix size'))
+    
+    return None
+    
+# CODEWORD STREAM GENERATION =========================================
+#take the text input and return the codewords,
+#including the Reed-Solomon error-correcting codes.
+#=====================================================================
+
+def get_codewords( text, nd, nc, inter, size144 ):
+    #convert the data to the codewords
+    data = encode_to_ascii( text )
+    
+    if not size144:    #render a "normal" datamatrix
+        data_blocks = partition_data(data, nd*inter)  #partition into data blocks of length nd*inter -> inter Reed-Solomon block
+    
+        data_blocks = interleave( data_blocks, inter)   # interleave consecutive inter blocks if required
+    
+        data_blocks = reed_solomon(data_blocks, nd, nc) #generate and append the Reed-Solomon codewords
+    
+        data_blocks = combine_interleaved(data_blocks, inter, nd, nc, False)  #concatenate Reed-Solomon blocks bound for the same datamatrix
+        
+    else: #we have a 144x144 datamatrix
+        data_blocks = partition_data(data, 1558) #partition the data into datamtrix-sized chunks (1558 =156*8 + 155*2 )
+        
+        for i in range(len(data_blocks)):  #for each datamtrix
+            
+            
+            inter = 8
+            nd = 156
+            nc = 62
+            block1 = data_blocks[i][0:156*8]
+            block1 = interleave( [block1], inter)   # interleave into 8 blocks
+            block1 = reed_solomon(block1, nd, nc) #generate and append the Reed-Solomon codewords
+            
+            inter = 2
+            nd = 155
+            nc = 62
+            block2 = data_blocks[i][156*8:]
+            block2 = interleave( [block2], inter)   # interleave into 2 blocks
+            block2 = reed_solomon(block2, nd, nc) #generate and append the Reed-Solomon codewords
+            
+            blocks = block1
+            blocks.extend(block2)
+                
+            blocks = combine_interleaved(blocks, 10, nd, nc, True)  
+            
+            data_blocks[i] = blocks[0]
+
+        
+    return data_blocks
+    
+
+#Takes a codeword stream and splits up into "inter" blocks.
+#eg interleave( [1,2,3,4,5,6], 2 ) -> [1,3,5], [2,4,6]
+def interleave( blocks, inter):
+
+    if inter == 1:       # if we don't have to interleave, just return the blocks
+        return blocks
+    else:
+        result = []
+        for block in blocks:    #for each codeword block in the stream
+            block_length = len(block)/inter    #length of each interleaved block
+            inter_blocks = [[0] * block_length for i in xrange(inter)]   #the interleaved blocks
+            
+            for i in range(block_length):   #for each element in the interleaved blocks
+                for j in range(inter):       #for each interleaved block
+                    inter_blocks[j][i] = block[ i*inter + j ]
+            
+            result.extend(inter_blocks) #add the interleaved blocks to the output
+        
+        return result
+        
+#Combine interleaved blocks into the groups for the same datamatrix
+#
+#e.g combine_interleaved( [[d1, d3, d5, e1, e3, e5], [d2, d4, d6, e2, e4, e6]], 2, 3, 3 )
+#   --> [[d1, d2, d3, d4, d5, d6, e1, e2, e3, e4, e5, e6]]
+def combine_interleaved( blocks, inter, nd, nc, size144):
+    if inter == 1:  #the blocks aren't interleaved
+        return blocks
+    else:
+        result = []
+        for i in range( len(blocks) / inter ):  #for each group of "inter" blocks -> one full datamatrix
+            data_codewords = [] #interleaved data blocks
+            
+            if size144:
+                nd_range = 1558 #1558 = 156*8 + 155*2
+                nc_range = 620   #620 = 62*8 + 62*2
+            else:
+                nd_range = nd*inter
+                nc_range = nc*inter
+            
+            for j in range(nd_range):  #for each codeword in the final list
+                data_codewords.append( blocks[i*inter + j%inter][j/inter] )
+
+            for j in range(nc_range):  #for each block, add the ecc codewords
+                data_codewords.append( blocks[i*inter + j%inter][nd + j/inter] )
+
+            result.append(data_codewords)
+        return result
+    
+#checks if an ASCII character is a digit from 0 - 9
+def is_digit( char ):
+    
+    if ord(char) >= 48 and ord(char) <= 57:
+        return True
+    else:
+        return False
+    
+def encode_to_ascii( text):
+
+    ascii = []
+    i = 0
+    while i < len(text):
+        #check for double digits
+        if is_digit( text[i] ) and ( i < len(text)-1) and is_digit( text[i+1] ):   #if the next char is also a digit
+            
+            codeword = int( text[i] + text[i+1] ) + 130
+            ascii.append( codeword )
+            i = i + 2   #move on 2 characters
+        else: #encode as a normal ascii, 
+            ascii.append( ord(text[i] ) + 1 ) #codeword is ASCII value + 1 (ISO 16022:2006 5.2.3)
+            i = i + 1   #next character
+            
+    return ascii
+
+    
+#partition data into blocks of the appropriate size to suit the
+#Reed-Solomon block being used.
+#e.g. partition_data([1,2,3,4,5], 3) -> [[1,2,3],[4,5,PAD]]
+def partition_data( data , rs_data):
+
+    PAD_VAL = 129        # PAD codeword (ISO 16022:2006 5.2.3)
+    data_blocks = []
+    i = 0
+    while i < len(data):
+        if len(data) >= i+rs_data:  #we have a whole block in our data
+            data_blocks.append( data[i:i+rs_data] )
+            i = i + rs_data
+        else:   #pad out with the pad codeword
+            data_block = data[i:len(data)] #add any remaining data
+            pad_pos = len(data)
+            padded = False
+            while len(data_block) < rs_data:#and then pad with randomised pad codewords
+                if not padded:
+                    data_block.append( PAD_VAL ) #add a normal pad codeword
+                    padded = True
+                else:
+                    data_block.append( randomise_pad_253( PAD_VAL, pad_pos) )
+                pad_pos = pad_pos + 1
+            data_blocks.append( data_block)
+            break
+            
+    return data_blocks
+    
+#Pad character randomisation, to prevent regular patterns appearing
+#in the data matrix
+def randomise_pad_253(pad_value, pad_position ):
+    pseudo_random_number = ( ( 149 * pad_position ) % 253 )+ 1 
+    randomised = pad_value + pseudo_random_number
+    if ( randomised <= 254 ):
+        return randomised
+    else:
+        return randomised - 254
+        
+# REED-SOLOMON ENCODING ROUTINES =====================================
+    
+# "prod(x,y,log,alog,gf)" returns the product "x" times "y"
+def prod(x, y, log, alog, gf):
+    
+    if ( x==0 or y==0):
+        return 0
+    else:
+        result = alog[ ( log[x] + log[y] ) % (gf - 1) ]
+        return result
+
+# generate the log & antilog lists:
+def gen_log_alog(gf, pp):
+    log = [0]*gf
+    alog = [0]*gf
+
+    log[0] = 1-gf
+    alog[0] = 1
+    
+    for i in range(1,gf):
+        alog[i] = alog[i-1] * 2
+        
+        if (alog[i] >= gf):
+            alog[i] = alog[i] ^ pp
+            
+        log[alog[i]] = i 
+        
+    return log, alog
+    
+# generate the generator polynomial coefficients:
+def gen_poly_coeffs(nc, log, alog, gf):
+    c = [0] * (nc+1)
+    c[0] = 1
+
+    for i in range(1,nc+1):
+        c[i] = c[i-1] 
+        
+        j = i-1
+        while j >= 1:
+            c[j] = c[j-1] ^ prod(c[j],alog[i],log,alog,gf)
+            j = j - 1
+        
+        c[0] = prod(c[0],alog[i],log,alog,gf)
+        
+    return c
+    
+# "ReedSolomon(wd,nd,nc)" takes "nd" data codeword values in wd[]
+# and adds on "nc" check codewords, all within GF(gf) where "gf" is a
+# power of 2 and "pp" is the value of its prime modulus polynomial */ 
+def reed_solomon(data, nd, nc):
+    #parameters of the polynomial arithmetic
+    gf = 256  #operating on 8-bit codewords -> Galois field = 2^8 = 256
+    pp = 301  #prime modulus polynomial for ECC-200 is 0b100101101 = 301 (ISO 16022:2006 5.7.1)
+    
+    log, alog = gen_log_alog(gf,pp)
+    c = gen_poly_coeffs(nc, log, alog, gf)
+
+    for block in data: #for each block of data codewords
+
+        block.extend( [0]*(nc+1) ) #extend to make space for the error codewords
+        
+        #generate "nc" checkwords in the list block
+        for i in range(0, nd):
+            k = block[nd] ^ block[i]
+            
+            for j in range(0,nc):
+                block[nd+j] = block[nd+j+1] ^ prod(k,c[nc-j-1],log, alog,gf)
+                
+        block.pop()
+
+    return data
+    
+#MODULE PLACEMENT ROUTINES===========================================
+#   These routines take a steam of codewords, and place them into the
+#   DataMatrix in accordance with Annex F of BS ISO/IEC 16022:2006
+
+# bit() returns the bit'th bit of the byte
+def bit(byte, bit):
+    #the MSB is bit 1, LSB is bit 8
+    return ( byte >> (8-bit) ) %2
+    
+# "module" places a given bit with appropriate wrapping within array
+def module(array, nrow, ncol, row, col, bit) :
+    if (row < 0) :
+        row = row + nrow
+        col = col + 4 - ((nrow+4)%8)
+        
+    if (col < 0):
+        col = col + ncol
+        row = row + 4 - ((ncol+4)%8) 
+
+    array[row][col] = bit
+
+def corner1(array, nrow, ncol, char): 
+    module(array, nrow, ncol, nrow-1, 0,      bit(char,1)); 
+    module(array, nrow, ncol, nrow-1, 1,      bit(char,2)); 
+    module(array, nrow, ncol, nrow-1, 2,      bit(char,3)); 
+    module(array, nrow, ncol, 0,      ncol-2, bit(char,4)); 
+    module(array, nrow, ncol, 0,      ncol-1, bit(char,5)); 
+    module(array, nrow, ncol, 1,      ncol-1, bit(char,6)); 
+    module(array, nrow, ncol, 2,      ncol-1, bit(char,7)); 
+    module(array, nrow, ncol, 3,      ncol-1, bit(char,8)); 
+
+def corner2(array, nrow, ncol, char):
+    module(array, nrow, ncol, nrow-3, 0,      bit(char,1)); 
+    module(array, nrow, ncol, nrow-2, 0,      bit(char,2)); 
+    module(array, nrow, ncol, nrow-1, 0,      bit(char,3)); 
+    module(array, nrow, ncol, 0,      ncol-4, bit(char,4)); 
+    module(array, nrow, ncol, 0,      ncol-3, bit(char,5)); 
+    module(array, nrow, ncol, 0,      ncol-2, bit(char,6)); 
+    module(array, nrow, ncol, 0,      ncol-1, bit(char,7)); 
+    module(array, nrow, ncol, 1,      ncol-1, bit(char,8)); 
+
+def corner3(array, nrow, ncol, char):
+    module(array, nrow, ncol, nrow-3, 0,      bit(char,1)); 
+    module(array, nrow, ncol, nrow-2, 0,      bit(char,2)); 
+    module(array, nrow, ncol, nrow-1, 0,      bit(char,3)); 
+    module(array, nrow, ncol, 0,      ncol-2, bit(char,4)); 
+    module(array, nrow, ncol, 0,      ncol-1, bit(char,5)); 
+    module(array, nrow, ncol, 1,      ncol-1, bit(char,6)); 
+    module(array, nrow, ncol, 2,      ncol-1, bit(char,7)); 
+    module(array, nrow, ncol, 3,      ncol-1, bit(char,8)); 
+
+def corner4(array, nrow, ncol, char):
+    module(array, nrow, ncol, nrow-1, 0,      bit(char,1)); 
+    module(array, nrow, ncol, nrow-1, ncol-1, bit(char,2)); 
+    module(array, nrow, ncol, 0,      ncol-3, bit(char,3)); 
+    module(array, nrow, ncol, 0,      ncol-2, bit(char,4)); 
+    module(array, nrow, ncol, 0,      ncol-1, bit(char,5)); 
+    module(array, nrow, ncol, 1,      ncol-3, bit(char,6)); 
+    module(array, nrow, ncol, 1,      ncol-2, bit(char,7)); 
+    module(array, nrow, ncol, 1,      ncol-1, bit(char,8));
+    
+#"utah" places the 8 bits of a utah-shaped symbol character in ECC200
+def utah(array, nrow, ncol, row, col, char):
+    module(array, nrow, ncol,row-2, col-2, bit(char,1))
+    module(array, nrow, ncol,row-2, col-1, bit(char,2))
+    module(array, nrow, ncol,row-1, col-2, bit(char,3))
+    module(array, nrow, ncol,row-1, col-1, bit(char,4))
+    module(array, nrow, ncol,row-1, col,   bit(char,5))
+    module(array, nrow, ncol,row,   col-2, bit(char,6))
+    module(array, nrow, ncol,row,   col-1, bit(char,7))
+    module(array, nrow, ncol,row,   col,   bit(char,8))
+
+#"place_bits" fills an nrow x ncol array with the bits from the 
+# codewords in data. 
+def place_bits(data, (nrow, ncol)): 
+# First, fill the array[] with invalid entries */ 
+    INVALID = 2
+    array = [[INVALID] * ncol for i in xrange(nrow)]   #initialise and fill with -1's (invalid value)
+# Starting in the correct location for character #1, bit 8,...
+    char = 0
+    row = 4
+    col = 0
+    while True:
+    
+    #first check for one of the special corner cases, then... 
+        if ((row == nrow) and (col == 0)):
+            corner1(array, nrow, ncol, data[char])
+            char = char + 1
+        if ((row == nrow-2) and (col == 0) and (ncol%4)) :
+            corner2(array, nrow, ncol, data[char])
+            char = char + 1
+        if ((row == nrow-2) and (col == 0) and (ncol%8 == 4)):
+            corner3(array, nrow, ncol, data[char])
+            char = char + 1
+        if ((row == nrow+4) and (col == 2) and ((ncol%8) == 0)):
+            corner4(array, nrow, ncol, data[char])
+            char = char + 1
+        
+        #sweep upward diagonally, inserting successive characters,...
+        while True:
+            if ((row < nrow) and (col >= 0) and (array[row][col] == INVALID)) :
+                utah(array, nrow, ncol,row,col,data[char])
+                char = char+1
+            row = row - 2
+            col = col + 2
+            
+            if not((row >= 0) and (col < ncol)):
+                break
+            
+        row = row + 1
+        col = col + 3 
+                
+        # & then sweep downward diagonally, inserting successive characters,...
+        while True:
+            if ((row >= 0) and (col < ncol) and (array[row][col] == INVALID)) :
+                utah(array, nrow, ncol,row,col,data[char])
+                char = char + 1
+            row = row + 2
+            col = col - 2 
+        
+            if not((row < nrow) and (col >= 0)):
+                break
+        
+        row = row + 3
+        col = col + 1
+        
+        #... until the entire array is scanned
+        if not((row < nrow) or (col < ncol)):
+            break
+
+    # Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ 
+    if (array[nrow-1][ncol-1] == INVALID): 
+        array[nrow-1][ncol-2] = 0
+        array[nrow-1][ncol-1] = 1
+        array[nrow-2][ncol-1] = 0
+        array[nrow-2][ncol-2] = 1
+
+    return array    #return the array of 1's and 0's
+    
+    
+def add_finder_pattern( array, data_nrow, data_ncol, reg_row, reg_col ):
+
+    #get the total size of the datamatrix
+    nrow = (data_nrow+2) * reg_row
+    ncol = (data_ncol+2) * reg_col
+
+    datamatrix = [[0] * ncol for i in xrange(nrow)]   #initialise and fill with 0's
+    
+    for i in range( reg_col ):    #for each column of data regions
+        for j in range(nrow):
+            datamatrix[j][i*(data_ncol+2)] = 1  #vertical black bar on left
+            datamatrix[j][i*(data_ncol+2)+data_ncol+1] = (j)%2 # alternating blocks
+            
+    for i in range( reg_row):   # for each row of data regions
+        for j in range(ncol):
+            datamatrix[i*(data_nrow+2)+data_nrow+1][j] = 1  #horizontal black bar at bottom
+            datamatrix[i*(data_nrow+2)][j] = (j+1)%2 # alternating blocks
+            
+    for i in range( data_nrow*reg_row ):
+        for j in range( data_ncol* reg_col ):
+            dest_col = j + 1 + 2*(j/(data_ncol)) #offset by 1, plus two for every addition block
+            dest_row = i + 1 + 2*(i/(data_nrow))
+            
+            datamatrix[dest_row][dest_col] = array[i][j]    #transfer from the plain bit array
+            
+    return datamatrix
+    
+#RENDERING ROUTINES ==================================================
+#   Take the array of 1's and 0's and render as a series of black
+#   squares. A binary 1 is a filled square
+#=====================================================================
+
+#SVG element generation routine
+def draw_SVG_square((w,h), (x,y), parent):
+
+    style = {   'stroke'        : 'none',
+                'width'         : '1',
+                'fill'          : '#000000'
+            }
+                
+    attribs = {
+        'style'     :simplestyle.formatStyle(style),
+        'height'    : str(h),
+        'width'     : str(w),
+        'x'         : str(x),
+        'y'         : str(y)
+            }
+    circ = inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), attribs )
+    
+#turn a 2D array of 1's and 0's into a set of black squares
+def render_data_matrix( module_arrays, size, spacing, parent):
+    
+    for i in range(len(module_arrays)): #for each data matrix
+    
+        height = len(module_arrays[i])
+        width  = len(module_arrays[i][0] )
+        
+        for y in range(height):     #loop over all the modules in the datamatrix
+            for x in range(width):
+                
+                if module_arrays[i][y][x] == 1: #A binary 1 is a filled square
+                    draw_SVG_square((size,size), (x*size + i*spacing,y*size), parent)
+                elif module_arrays[i][y][x] != 0: #we have an invalid bit value
+                    inkex.errormsg(_('Invalid bit value, this is a bug!'))
+    
+class DataMatrix(inkex.Effect):
+    def __init__(self):
+        inkex.Effect.__init__(self)
+        
+        #PARSE OPTIONS
+        self.OptionParser.add_option("--text",
+            action="store", type="string",
+            dest="TEXT", default='Inkscape')
+        self.OptionParser.add_option("--rows",
+            action="store", type="int",
+            dest="ROWS", default=10)
+        self.OptionParser.add_option("--cols",
+            action="store", type="int",
+            dest="COLS", default=10)
+        self.OptionParser.add_option("--size",
+            action="store", type="int",
+            dest="SIZE", default=4)
+            
+    def effect(self):
+        
+        so = self.options
+        
+        if so.TEXT == '':  #abort if converting blank text
+            inkex.errormsg(_('Please enter an input string'))
+        else:
+        
+            #INKSCAPE GROUP TO CONTAIN EVERYTHING
+            
+            centre = self.view_center   #Put in in the centre of the current view
+            grp_transform = 'translate' + str( centre )
+            grp_name = 'DataMatrix'
+            grp_attribs = {inkex.addNS('label','inkscape'):grp_name,
+                           'transform':grp_transform }
+            grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in
+            
+            #GENERATE THE DATAMATRIX
+            encoded = encode( so.TEXT, (so.ROWS, so.COLS) ) #get the pattern of squares
+            render_data_matrix( encoded, so.SIZE, so.COLS*so.SIZE*1.5, grp )    # generate the SVG elements
+            
+if __name__ == '__main__':
+    e = DataMatrix()
+    e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
diff --git a/share/extensions/wireframe_sphere.inx b/share/extensions/wireframe_sphere.inx
new file mode 100644 (file)
index 0000000..733ba8e
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
+       <_name>Wireframe Sphere</_name>
+       <id>il.wireframesphere</id>
+       <dependency type="executable" location="extensions">wireframe_sphere.py</dependency>
+       <dependency type="executable" location="extensions">inkex.py</dependency>
+       <dependency type="executable" location="extensions">simplestyle.py</dependency>
+       <dependency type="executable" location="extensions">simpletransform.py</dependency>
+       <param name="num_lat" type="int" min="0" max="1000" _gui-text="Lines of latitude">19</param>
+       <param name="num_long" type="int" min="0" max="1000" _gui-text="Lines of longitude">24</param>
+       <param name="tilt" type="float" min="-90" max="90" _gui-text="Tilt [deg]">35</param>
+       <param name="rotation" type="float" min="0" max="360" _gui-text="Rotation [deg]">4</param>
+       <param name="radius" type="float" min="1" max="1000" _gui-text="Radius [px]">100.0</param>
+       <param name="hide_back" type="boolean" _gui-text="Hide lines behind the sphere">false</param>
+       <effect>
+               <object-type>all</object-type>
+               <effects-menu>
+                       <submenu _name="Render"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">wireframe_sphere.py</command>
+       </script>
+</inkscape-extension>
diff --git a/share/extensions/wireframe_sphere.py b/share/extensions/wireframe_sphere.py
new file mode 100644 (file)
index 0000000..8fbd4d3
--- /dev/null
@@ -0,0 +1,221 @@
+#!/usr/bin/env python 
+# -*- coding: UTF-8 -*-
+'''
+Copyright (C) 2009 John Beard john.j.beard@gmail.com
+
+######DESCRIPTION######
+
+This extension renders a wireframe sphere constructed from lines of latitude
+and lines of longitude.
+
+The number of lines of latitude and longitude is independently variable. Lines 
+of latitude and longtude are in separate subgroups. The whole figure is also in
+its own group.
+
+The whole sphere can be tilted towards or away from the veiwer by a given 
+number of degrees. If the whole sphere is then rotated normally in Inkscape,
+any position can be acheived.
+
+There is an option to hide the lines at the back of the sphere, as if the 
+sphere were opaque.
+    #FIXME: Lines of latitude only have an approximation of the function needed
+            to hide the back portion. If you can derive the proper equation,
+            please add it in.
+            Line of longitude have the exact method already.
+            Workaround: Use the Inkscape ellipse tool to edit the start and end
+            points of the lines of latitude to end at the horizon circle.
+            
+           
+#TODO:  Add support for odd numbers of lines of longitude. This means breaking
+        the line at the poles, and having two half ellipses for each line.
+        The angles at which the ellipse arcs pass the poles are not constant and
+        need to be derived before this can be implemented.
+#TODO:  Add support for prolate and oblate spheroids
+
+######LICENCE#######
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+######VERSION HISTORY#####
+    Ver.       Date                       Notes
+    
+    0.10    2009-10-25  First version. Basic spheres supported.
+                        Hidden lines of latitude still not properly calculated.
+                        Prolate and oblate spheroids not considered.
+'''
+
+import inkex, simplestyle
+
+import gettext
+_ = gettext.gettext
+
+from math import *
+
+#SVG OUTPUT FUNCTIONS ================================================
+def draw_SVG_ellipse((rx, ry), (cx, cy), parent, start_end=(0,2*pi),transform='' ):
+
+    style = {   'stroke'        : '#000000',
+                'width'         : '1',
+                'fill'          : 'none'            }
+    circ_attribs = {'style':simplestyle.formatStyle(style),
+        inkex.addNS('cx','sodipodi')        :str(cx),
+        inkex.addNS('cy','sodipodi')        :str(cy),
+        inkex.addNS('rx','sodipodi')        :str(rx),
+        inkex.addNS('ry','sodipodi')        :str(ry),
+        inkex.addNS('start','sodipodi')     :str(start_end[0]),
+        inkex.addNS('end','sodipodi')       :str(start_end[1]),
+        inkex.addNS('open','sodipodi')      :'true',    #all ellipse sectors we will draw are open
+        inkex.addNS('type','sodipodi')      :'arc',
+        'transform'                         :transform
+        
+            }
+    circ = inkex.etree.SubElement(parent, inkex.addNS('path','svg'), circ_attribs )
+    
+class Wireframe_Sphere(inkex.Effect):
+    def __init__(self):
+        inkex.Effect.__init__(self)
+        
+        #PARSE OPTIONS
+        self.OptionParser.add_option("--num_lat",
+            action="store", type="int",
+            dest="NUM_LAT", default=19)
+        self.OptionParser.add_option("--num_long",
+            action="store", type="int",
+            dest="NUM_LONG", default=24)
+        self.OptionParser.add_option("--radius",
+            action="store", type="float", 
+            dest="RADIUS", default=100.0)
+        self.OptionParser.add_option("--tilt",
+            action="store", type="float",
+            dest="TILT", default=35.0)
+        self.OptionParser.add_option("--rotation",
+            action="store", type="float",
+            dest="ROT_OFFSET", default=4)
+        self.OptionParser.add_option("--hide_back",
+            action="store", type="inkbool", 
+            dest="HIDE_BACK", default=False)
+            
+    def effect(self):
+        
+        so = self.options
+        
+        #PARAMETER PROCESSING
+        
+        if so.NUM_LONG % 2 != 0: #lines of longitude are odd : abort
+            inkex.errormsg(_('Please enter an even number of lines of longitude.'))
+        else:
+            if so.TILT < 0:            # if the tilt is backwards
+                flip = ' scale(1, -1)' # apply a vertical flip to the whole sphere
+            else:
+                flip = '' #no flip
+
+            so.TILT       =  abs(so.TILT)*(pi/180)  #Convert to radians
+            so.ROT_OFFSET = so.ROT_OFFSET*(pi/180)  #Convert to radians
+            
+            EPSILON = 0.001 #add a tiny value to the ellipse radii, so that if we get a zero radius, the ellipse still shows up as a line
+
+            #INKSCAPE GROUP TO CONTAIN EVERYTHING
+            
+            centre = self.view_center   #Put in in the centre of the current view
+            grp_transform = 'translate' + str( centre ) + flip
+            grp_name = 'WireframeSphere'
+            grp_attribs = {inkex.addNS('label','inkscape'):grp_name,
+                           'transform':grp_transform }
+            grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs)#the group to put everything in
+            
+            #LINES OF LONGITUDE
+            
+            if so.NUM_LONG > 0:      #only process longitudes if we actually want some
+                
+                #GROUP FOR THE LINES OF LONGITUDE
+                grp_name = 'Lines of Longitude'
+                grp_attribs = {inkex.addNS('label','inkscape'):grp_name}
+                grp_long = inkex.etree.SubElement(grp, 'g', grp_attribs)
+                
+                delta_long = 360.0/so.NUM_LONG      #angle between neighbouring lines of longitude in degrees
+                
+                for i in range(0,so.NUM_LONG/2):
+                    long_angle = so.ROT_OFFSET + (i*delta_long)*(pi/180.0); #The longitude of this particular line in radians
+                    if long_angle > pi:
+                        long_angle -= 2*pi
+                    width      = so.RADIUS * cos(long_angle)
+                    height     = so.RADIUS * sin(long_angle) * sin(so.TILT)       #the rise is scaled by the sine of the tilt
+                    # length     = sqrt(width*width+height*height)  #by pythagorean theorem
+                    # inverse    = sin(acos(length/so.RADIUS))
+                    inverse    = abs(sin(long_angle)) * cos(so.TILT)
+                    
+                    minorRad   = so.RADIUS * inverse
+                    minorRad=minorRad + EPSILON
+                    
+                    #calculate the rotation of the ellipse to get it to pass through the pole (in degrees)
+                    rotation = atan(height/width)*(180.0/pi)
+                    transform = "rotate("+str(rotation)+')' #generate the transform string
+                    #the rotation will be applied about the group centre (the centre of the sphere)
+                    
+                    # remove the hidden side of the ellipses if required
+                    # this is always exactly half the ellipse, but we need to find out which half
+                    start_end = (0, 2*pi)   #Default start and end angles -> full ellipse
+                    if so.HIDE_BACK:
+                        if long_angle <= pi/2:           #cut out the half ellispse that is hidden
+                            start_end = (pi/2, 3*pi/2)
+                        else:
+                            start_end = (3*pi/2, pi/2)
+                    
+                    #finally, draw the line of longitude
+                    #the centre is always at the centre of the sphere
+                    draw_SVG_ellipse( ( minorRad, so.RADIUS ), (0,0), grp_long , start_end,transform)
+                
+            # LINES OF LATITUDE
+            if so.NUM_LAT > 0:
+            
+                #GROUP FOR THE LINES OF LATITUDE
+                grp_name = 'Lines of Latitude'
+                grp_attribs = {inkex.addNS('label','inkscape'):grp_name}
+                grp_lat = inkex.etree.SubElement(grp, 'g', grp_attribs)
+                
+                
+                so.NUM_LAT = so.NUM_LAT + 1     #Account for the fact that we loop over N-1 elements
+                delta_lat = 180.0/so.NUM_LAT    #Angle between the line of latitude (subtended at the centre)
+                
+                for i in range(1,so.NUM_LAT):
+                    lat_angle=((delta_lat*i)*(pi/180))            #The angle of this line of latitude (from a pole)
+                    
+                    majorRad=so.RADIUS*sin(lat_angle)                 #The width of the LoLat (no change due to projection)
+                    minorRad=so.RADIUS*sin(lat_angle) * sin(so.TILT)     #The projected height of the line of latitude
+                    minorRad=minorRad + EPSILON
+                    
+                    cy=so.RADIUS*cos(lat_angle) * cos(so.TILT) #The projected y position of the LoLat
+                    cx=0                                    #The x position is just the center of the sphere
+                    
+                    if so.HIDE_BACK:
+                        if lat_angle > so.TILT:                     #this LoLat is partially or fully visible
+                            if lat_angle > pi-so.TILT:               #this LoLat is fully visible
+                                draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat)
+                            else: #this LoLat is partially visible
+                                proportion = -(acos( tan(lat_angle - pi/2)/tan(pi/2 - so.TILT)) )/pi + 1
+                                start_end = ( pi/2 - proportion*pi, pi/2 + proportion*pi ) #make the start and end angles (mirror image around pi/2)
+                                draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat, start_end)
+                            
+                    else: #just draw the full lines of latitude
+                        draw_SVG_ellipse((majorRad, minorRad), (cx,cy), grp_lat)
+            
+        
+            #THE HORIZON CIRCLE
+            draw_SVG_ellipse((so.RADIUS, so.RADIUS), (0,0), grp) #circle, centred on the sphere centre
+            
+if __name__ == '__main__':
+    e = Wireframe_Sphere()
+    e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
index a064496ce4893b6bd0795a1fb8f16e7ac83a1ff5..9d51775194b1d535f19fe3f3ec6c1b86e81f3b42 100644 (file)
@@ -234,20 +234,18 @@ inkview_LDADD = $(all_libs)
 libinkversion_a_SOURCES = inkscape-version.cpp inkscape-version.h
 
 if USE_SVN_VERSION
-inkscape_version_deps = $(top_srcdir)/.svn/entries
+inkscape_version_deps = $(top_srcdir)/.bzr/branch/last-revision
 endif
 
-# If this is an SVN snapshot build, regenerate this file every time
-# someone updates the SVN working directory.
+# If this is an BZR snapshot build, regenerate this file every time
+# someone updates the BZR working directory.
 inkscape-version.cpp: $(inkscape_version_deps)
-       VER_PREFIX="$(VERSION)"; \
-       if test -x "$(srcdir)/.svn" -a ! -z `which svn`; then \
-           VER_SVNREV=" r`LANG=en svn info $(srcdir) | sed -n -e '/^Revision:/s/Revision: \(.*\)/\1/p'`"; \
-           if test ! -z "`svn status -q $(srcdir)`"; then \
-                VER_CUSTOM=" custom"; \
-           fi; \
+       VER_PREFIX="$(VERSION)";\
+       VER_BZRREV=" r`bzr log -r '-1..' | sed -n -e '/^revno:/s/revno: \(.*\)/\1/p'`"; \
+       if test ! -z "`bzr status -S -V $(srcdir)`"; then \
+           VER_CUSTOM=" custom"; \
        fi; \
-       VERSION="$$VER_PREFIX$$VER_SVNREV$$VER_CUSTOM"; \
+       VERSION="$$VER_PREFIX$$VER_BZRREV$$VER_CUSTOM"; \
        echo "namespace Inkscape { " \
             "char const *version_string = \"$$VERSION\"; " \
             "}" > inkscape-version.new.cpp; \
index e3476deb3a00aec82ab547d3c56a08e73a504fd0..c8fbfa8779ff27500679337568fa9df97b53de25 100644 (file)
@@ -123,16 +123,17 @@ static void sp_box3d_context_init(Box3DContext *box3d_context)
 
 static void sp_box3d_context_finish(SPEventContext *ec)
 {
-       Box3DContext *bc = SP_BOX3D_CONTEXT(ec);
-       SPDesktop *desktop = ec->desktop;
+    Box3DContext *bc = SP_BOX3D_CONTEXT(ec);
+    SPDesktop *desktop = ec->desktop;
 
-       sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME);
-       sp_box3d_finish(bc);
+    sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME);
+    sp_box3d_finish(bc);
     bc->sel_changed_connection.disconnect();
+//    sp_repr_remove_listener_by_data(cc->active_shape_repr, cc);
 
     if (((SPEventContextClass *) parent_class)->finish) {
-               ((SPEventContextClass *) parent_class)->finish(ec);
-       }
+        ((SPEventContextClass *) parent_class)->finish(ec);
+    }
 }
 
 
@@ -179,13 +180,14 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g
 
     if (selection->perspList().size() == 1) {
         // selecting a single box changes the current perspective
-        ec->desktop->doc()->current_persp3d = selection->perspList().front();
+        ec->desktop->doc()->setCurrentPersp3D(selection->perspList().front());
     }
 }
 
-/* create a default perspective in document defs if none is present
-   (can happen after 'vacuum defs' or when a pre-0.46 file is opened) */
-static void sp_box3d_context_check_for_persp_in_defs(SPDocument *document) {
+/* Create a default perspective in document defs if none is present (which can happen, among other
+ * circumstances, after 'vacuum defs' or when a pre-0.46 file is opened).
+ */
+static void sp_box3d_context_ensure_persp_in_defs(SPDocument *document) {
     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
 
     bool has_persp = false;
@@ -197,7 +199,7 @@ static void sp_box3d_context_check_for_persp_in_defs(SPDocument *document) {
     }
 
     if (!has_persp) {
-        document->current_persp3d = persp3d_create_xml_element (document);
+        document->setCurrentPersp3D(persp3d_create_xml_element (document));
     }
 }
 
@@ -209,8 +211,6 @@ static void sp_box3d_context_setup(SPEventContext *ec)
         ((SPEventContextClass *) parent_class)->setup(ec);
     }
 
-    sp_box3d_context_check_for_persp_in_defs(sp_desktop_document (ec->desktop));
-
     ec->shape_editor = new ShapeEditor(ec->desktop);
 
     SPItem *item = sp_desktop_selection(ec->desktop)->singleItem();
@@ -267,13 +267,13 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
     static bool dragging;
 
     SPDesktop *desktop = event_context->desktop;
+    SPDocument *document = sp_desktop_document (desktop);
     Inkscape::Selection *selection = sp_desktop_selection (desktop);
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12);
 
     Box3DContext *bc = SP_BOX3D_CONTEXT(event_context);
-    g_assert (SP_ACTIVE_DOCUMENT->current_persp3d);
-    Persp3D *cur_persp = SP_ACTIVE_DOCUMENT->current_persp3d;
+    Persp3D *cur_persp = document->getCurrentPersp3D();
 
     event_context->tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
 
@@ -300,8 +300,14 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
             bc->drag_ptB = from_2geom(button_dt);
             bc->drag_ptC = from_2geom(button_dt);
 
+            // This can happen after saving when the last remaining perspective was purged and must be recreated.
+            if (!cur_persp) {
+                sp_box3d_context_ensure_persp_in_defs(document);
+                cur_persp = document->getCurrentPersp3D();
+            }
+
             /* Projective preimages of clicked point under current perspective */
-            bc->drag_origin_proj = cur_persp->tmat.preimage (from_2geom(button_dt), 0, Proj::Z);
+            bc->drag_origin_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(button_dt), 0, Proj::Z);
             bc->drag_ptB_proj = bc->drag_origin_proj;
             bc->drag_ptC_proj = bc->drag_origin_proj;
             bc->drag_ptC_proj.normalize();
@@ -355,7 +361,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
                bc->drag_ptB = from_2geom(motion_dt);
                bc->drag_ptC = from_2geom(motion_dt);
 
-                bc->drag_ptB_proj = cur_persp->tmat.preimage (from_2geom(motion_dt), 0, Proj::Z);
+                bc->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(motion_dt), 0, Proj::Z);
                 bc->drag_ptC_proj = bc->drag_ptB_proj;
                 bc->drag_ptC_proj.normalize();
                 bc->drag_ptC_proj[Proj::Z] = 0.25;
@@ -364,16 +370,16 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
                 // perspective line from drag_ptB to vanishing point Y.
                 if (!bc->ctrl_dragged) {
                     /* snapping */
-                    Box3D::PerspectiveLine pline (bc->drag_ptB, Proj::Z, SP_ACTIVE_DOCUMENT->current_persp3d);
+                    Box3D::PerspectiveLine pline (bc->drag_ptB, Proj::Z, document->getCurrentPersp3D());
                     bc->drag_ptC = pline.closest_to (from_2geom(motion_dt));
 
                     bc->drag_ptB_proj.normalize();
-                    bc->drag_ptC_proj = cur_persp->tmat.preimage (bc->drag_ptC, bc->drag_ptB_proj[Proj::X], Proj::X);
+                    bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (bc->drag_ptC, bc->drag_ptB_proj[Proj::X], Proj::X);
                 } else {
                     bc->drag_ptC = from_2geom(motion_dt);
 
                     bc->drag_ptB_proj.normalize();
-                    bc->drag_ptC_proj = cur_persp->tmat.preimage (from_2geom(motion_dt), bc->drag_ptB_proj[Proj::X], Proj::X);
+                    bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(motion_dt), bc->drag_ptB_proj[Proj::X], Proj::X);
                 }
                 Geom::Point pt2g = to_2geom(bc->drag_ptC);
                 m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g, Inkscape::SNAPSOURCE_HANDLE);
@@ -424,43 +430,43 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
             break;
 
         case GDK_bracketright:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::X, -180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::X, -180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
 
         case GDK_bracketleft:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::X, 180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::X, 180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
 
         case GDK_parenright:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::Y, -180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::Y, -180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
 
         case GDK_parenleft:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::Y, 180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::Y, 180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
 
         case GDK_braceright:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::Z, -180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::Z, -180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
 
         case GDK_braceleft:
-            persp3d_rotate_VP (inkscape_active_document()->current_persp3d, Proj::Z, 180/snaps, MOD__ALT);
-            sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+            persp3d_rotate_VP (document->getCurrentPersp3D(), Proj::Z, 180/snaps, MOD__ALT);
+            sp_document_done(document, SP_VERB_CONTEXT_3DBOX,
                              _("Change perspective (angle of PLs)"));
             ret = true;
             break;
@@ -468,7 +474,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
         /* TODO: what is this???
         case GDK_O:
             if (MOD__CTRL && MOD__SHIFT) {
-                Box3D::create_canvas_point(persp3d_get_VP(inkscape_active_document()->current_persp3d, Proj::W).affine(),
+                Box3D::create_canvas_point(persp3d_get_VP(document()->getCurrentPersp3D(), Proj::W).affine(),
                                            6, 0xff00ff00);
             }
             ret = true;
@@ -483,6 +489,16 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
             }
             break;
 
+        case GDK_p:
+        case GDK_P:
+            if (MOD__SHIFT_ONLY) {
+                if (document->getCurrentPersp3D()) {
+                    persp3d_print_debugging_info (document->getCurrentPersp3D());
+                }
+                ret = true;
+            }
+            break;
+
         case GDK_x:
         case GDK_X:
             if (MOD__ALT_ONLY) {
@@ -598,7 +614,7 @@ static void sp_box3d_drag(Box3DContext &bc, guint /*state*/)
 
         // TODO: It would be nice to show the VPs during dragging, but since there is no selection
         //       at this point (only after finishing the box), we must do this "manually"
-        /**** bc._vpdrag->updateDraggers(); ****/
+        /* bc._vpdrag->updateDraggers(); */
 
         sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5);
     }
@@ -631,7 +647,7 @@ static void sp_box3d_finish(Box3DContext *bc)
     if ( bc->item != NULL ) {
         SPDesktop * desktop = SP_EVENT_CONTEXT_DESKTOP(bc);
         SPDocument *doc = sp_desktop_document(desktop);
-        if (!doc || !doc->current_persp3d)
+        if (!doc || !doc->getCurrentPersp3D())
             return;
 
         SPBox3D *box = SP_BOX3D(bc->item);
index 93efa5c35183589ea7e604066d7afb9d93e8b52d..aa2dc55e36cad3b833b26d9c1a17108f68d68c13 100644 (file)
@@ -127,10 +127,8 @@ box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
     // TODO: Create/link to the correct perspective
 
     SPDocument *doc = SP_OBJECT_DOCUMENT(box);
-    if (!doc) {
-        g_print ("No document for the box!!!!\n");
+    if (!doc)
         return;
-    }
 
     box->persp_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(box3d_ref_changed), box));
 
@@ -150,13 +148,33 @@ box3d_release(SPObject *object)
     if (box->persp_href) {
         g_free(box->persp_href);
     }
+
+    // We have to store this here because the Persp3DReference gets destroyed below, but we need to
+    // access it to call persp3d_remove_box(), which cannot be called earlier because the reference
+    // needs to be destroyed first.
+    Persp3D *persp = box3d_get_perspective(box);
+
     if (box->persp_ref) {
         box->persp_ref->detach();
         delete box->persp_ref;
         box->persp_ref = NULL;
     }
 
-    //persp3d_remove_box (box3d_get_perspective(box), box);
+    if (persp) {
+        persp3d_remove_box (persp, box);
+        /*
+        // TODO: This deletes a perspective when the last box referring to it is gone. Eventually,
+        // it would be nice to have this but currently it crashes when undoing/redoing box deletion
+        // Reason: When redoing a box deletion, the associated perspective is deleted twice, first
+        // by the following code and then again by the redo mechanism! Perhaps we should perform
+        // deletion of the perspective from another location "outside" the undo/redo mechanism?
+        if (persp->perspective_impl->boxes.empty()) {
+            SPDocument *doc = SP_OBJECT_DOCUMENT(box);
+            persp->deleteObject();
+            doc->setCurrentPersp3D(persp3d_document_first_persp(doc));
+        }
+        */
+    }
 
     if (((SPObjectClass *) parent_class)->release)
         ((SPObjectClass *) parent_class)->release(object);
@@ -226,16 +244,10 @@ box3d_ref_changed(SPObject *old_ref, SPObject *ref, SPBox3D *box)
     if (old_ref) {
         sp_signal_disconnect_by_data(old_ref, box);
         persp3d_remove_box (SP_PERSP3D(old_ref), box);
-        /* Note: This sometimes leads to attempts to remove boxes twice from the list of selected/transformed
-           boxes in a perspectives, but this should be uncritical. */
-        persp3d_remove_box_transform (SP_PERSP3D(old_ref), box);
     }
     if ( SP_IS_PERSP3D(ref) && ref != box ) // FIXME: Comparisons sane?
     {
         persp3d_add_box (SP_PERSP3D(ref), box);
-        /* Note: This sometimes leads to attempts to add boxes twice to the list of selected/transformed
-           boxes in a perspectives, but this should be uncritical. */
-        persp3d_add_box_transform (SP_PERSP3D(ref), box);
     }
 }
 
@@ -278,7 +290,7 @@ static Inkscape::XML::Node *box3d_write(SPObject *object, Inkscape::XML::Documen
                 repr->setAttribute("inkscape:perspectiveID", uri_string);
                 g_free(uri_string);
             } else {
-                Inkscape::XML::Node *persp_repr = SP_OBJECT_REPR(doc->current_persp3d);
+                Inkscape::XML::Node *persp_repr = SP_OBJECT_REPR(doc->getCurrentPersp3D());
                 const gchar *persp_id = persp_repr->attribute("id");
                 gchar *href = g_strdup_printf("#%s", persp_id);
                 repr->setAttribute("inkscape:perspectiveID", href);
@@ -331,37 +343,8 @@ box3d_set_transform(SPItem *item, Geom::Matrix const &xform)
 {
     SPBox3D *box = SP_BOX3D(item);
 
-    /* check whether we need to unlink any boxes from their perspectives */
-    Persp3D *persp = box3d_get_perspective(box);
-    Persp3D *transf_persp;
-
-    if (sp_desktop_document(inkscape_active_desktop()) == SP_OBJECT_DOCUMENT(item) && 
-        !persp3d_has_all_boxes_in_selection (persp)) {
-        std::list<SPBox3D *> selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList();
-
-        /* create a new perspective as a copy of the current one and link the selected boxes to it */
-        transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp);
-
-        for (std::list<SPBox3D *>::iterator b = selboxes.begin(); b != selboxes.end(); ++b) {
-            box3d_switch_perspectives(*b, persp, transf_persp);
-        }
-    } else {
-        transf_persp = persp;
-    }
-
-    /* only transform the perspective once, even if it has several selected boxes */
-    if(!persp3d_was_transformed (transf_persp)) {
-        /* concatenate the affine transformation with the perspective mapping; this
-           function also triggers repr updates of boxes and the perspective itself */
-        persp3d_apply_affine_transformation(transf_persp, xform);
-    }
-
-    box3d_mark_transformed(box);
-
-    if (persp3d_all_transformed(transf_persp)) {
-        /* all boxes were transformed; make perspective sensitive for further transformations */
-        persp3d_unset_transforms(transf_persp);
-    }
+    // We don't apply the transform to the box directly but instead to its perspective (which is
+    // done in sp_selection_apply_affine). Here we only adjust strokes, patterns, etc.
 
     Geom::Matrix ret(Geom::Matrix(xform).without_translation());
     gdouble const sw = hypot(ret[0], ret[1]);
@@ -412,9 +395,9 @@ box3d_get_corner_screen (SPBox3D const *box, guint id, bool item_coords) {
     }
     Geom::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(box)));
     if (item_coords) {
-        return box3d_get_perspective(box)->tmat.image(proj_corner).affine() * i2d.inverse();
+        return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_corner).affine() * i2d.inverse();
     } else {
-        return box3d_get_perspective(box)->tmat.image(proj_corner).affine();
+        return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_corner).affine();
     }
 }
 
@@ -435,7 +418,7 @@ box3d_get_center_screen (SPBox3D *box) {
         return Geom::Point (NR_HUGE, NR_HUGE);
     }
     Geom::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(box)));
-    return box3d_get_perspective(box)->tmat.image(proj_center).affine() * i2d.inverse();
+    return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_center).affine() * i2d.inverse();
 }
 
 /*
@@ -461,13 +444,13 @@ box3d_snap (SPBox3D *box, int id, Proj::Pt3 const &pt_proj, Proj::Pt3 const &sta
     Proj::Pt3 D_proj (x_coord,          y_coord + diff_y, z_coord, 1.0);
     Proj::Pt3 E_proj (x_coord - diff_x, y_coord + diff_y, z_coord, 1.0);
 
-    Persp3D *persp = box3d_get_perspective(box);
-    Geom::Point A = persp->tmat.image(A_proj).affine();
-    Geom::Point B = persp->tmat.image(B_proj).affine();
-    Geom::Point C = persp->tmat.image(C_proj).affine();
-    Geom::Point D = persp->tmat.image(D_proj).affine();
-    Geom::Point E = persp->tmat.image(E_proj).affine();
-    Geom::Point pt = persp->tmat.image(pt_proj).affine();
+    Persp3DImpl *persp_impl = box3d_get_perspective(box)->perspective_impl;
+    Geom::Point A = persp_impl->tmat.image(A_proj).affine();
+    Geom::Point B = persp_impl->tmat.image(B_proj).affine();
+    Geom::Point C = persp_impl->tmat.image(C_proj).affine();
+    Geom::Point D = persp_impl->tmat.image(D_proj).affine();
+    Geom::Point E = persp_impl->tmat.image(E_proj).affine();
+    Geom::Point pt = persp_impl->tmat.image(pt_proj).affine();
 
     // TODO: Replace these lines between corners with lines from a corner to a vanishing point
     //       (this might help to prevent rounding errors if the box is small)
@@ -523,7 +506,7 @@ box3d_snap (SPBox3D *box, int id, Proj::Pt3 const &pt_proj, Proj::Pt3 const &sta
         remember_snap_index = snap_index;
         result = snap_pts[snap_index];
     }
-    return box3d_get_perspective(box)->tmat.preimage (result, z_coord, Proj::Z);
+    return box3d_get_perspective(box)->perspective_impl->tmat.preimage (result, z_coord, Proj::Z);
 }
 
 void
@@ -535,8 +518,9 @@ box3d_set_corner (SPBox3D *box, const guint id, Geom::Point const &new_pos, cons
 
     /* update corners 0 and 7 according to which handle was moved and to the axes of movement */
     if (!(movement & Box3D::Z)) {
-        Proj::Pt3 pt_proj (box3d_get_perspective(box)->tmat.preimage (new_pos, (id < 4) ? box->orig_corner0[Proj::Z] :
-                                                                      box->orig_corner7[Proj::Z], Proj::Z));
+        Persp3DImpl *persp_impl = box3d_get_perspective(box)->perspective_impl;
+        Proj::Pt3 pt_proj (persp_impl->tmat.preimage (new_pos, (id < 4) ? box->orig_corner0[Proj::Z] :
+                                                      box->orig_corner7[Proj::Z], Proj::Z));
         if (constrained) {
             pt_proj = box3d_snap (box, id, pt_proj, box3d_get_proj_corner (id, box->save_corner0, box->save_corner7));
         }
@@ -553,13 +537,14 @@ box3d_set_corner (SPBox3D *box, const guint id, Geom::Point const &new_pos, cons
                                        1.0);
     } else {
         Persp3D *persp = box3d_get_perspective(box);
-        Box3D::PerspectiveLine pl(persp->tmat.image(
+        Persp3DImpl *persp_impl = box3d_get_perspective(box)->perspective_impl;
+        Box3D::PerspectiveLine pl(persp_impl->tmat.image(
                                       box3d_get_proj_corner (id, box->save_corner0, box->save_corner7)).affine(),
                                   Proj::Z, persp);
         Geom::Point new_pos_snapped(pl.closest_to(new_pos));
-        Proj::Pt3 pt_proj (persp->tmat.preimage (new_pos_snapped,
-                                          box3d_get_proj_corner (box, id)[(movement & Box3D::Y) ? Proj::X : Proj::Y],
-                                          (movement & Box3D::Y) ? Proj::X : Proj::Y));
+        Proj::Pt3 pt_proj (persp_impl->tmat.preimage (new_pos_snapped,
+                                      box3d_get_proj_corner (box, id)[(movement & Box3D::Y) ? Proj::X : Proj::Y],
+                                                      (movement & Box3D::Y) ? Proj::X : Proj::Y));
         bool corner0_move_x = !(id & Box3D::X) && (movement & Box3D::X);
         bool corner0_move_y = !(id & Box3D::Y) && (movement & Box3D::Y);
         bool corner7_move_x =  (id & Box3D::X) && (movement & Box3D::X);
@@ -590,9 +575,9 @@ void box3d_set_center (SPBox3D *box, Geom::Point const &new_pos, Geom::Point con
         double radx = (box->orig_corner7[Proj::X] - box->orig_corner0[Proj::X]) / 2;
         double rady = (box->orig_corner7[Proj::Y] - box->orig_corner0[Proj::Y]) / 2;
 
-        Proj::Pt3 pt_proj (persp->tmat.preimage (new_pos, coord, Proj::Z));
+        Proj::Pt3 pt_proj (persp->perspective_impl->tmat.preimage (new_pos, coord, Proj::Z));
         if (constrained) {
-            Proj::Pt3 old_pos_proj (persp->tmat.preimage (old_pos, coord, Proj::Z));
+            Proj::Pt3 old_pos_proj (persp->perspective_impl->tmat.preimage (old_pos, coord, Proj::Z));
             old_pos_proj.normalize();
             pt_proj = box3d_snap (box, -1, pt_proj, old_pos_proj);
         }
@@ -612,7 +597,7 @@ void box3d_set_center (SPBox3D *box, Geom::Point const &new_pos, Geom::Point con
 
         Box3D::PerspectiveLine pl(old_pos, Proj::Z, persp);
         Geom::Point new_pos_snapped(pl.closest_to(new_pos));
-        Proj::Pt3 pt_proj (persp->tmat.preimage (new_pos_snapped, coord, Proj::X));
+        Proj::Pt3 pt_proj (persp->perspective_impl->tmat.preimage (new_pos_snapped, coord, Proj::X));
 
         /* normalizing pt_proj is essential because we want to mingle affine coordinates */
         pt_proj.normalize();
@@ -636,6 +621,7 @@ void box3d_corners_for_PLs (const SPBox3D * box, Proj::Axis axis,
 {
     Persp3D *persp = box3d_get_perspective(box);
     g_return_if_fail (persp);
+    Persp3DImpl *persp_impl = persp->perspective_impl;
     //box->orig_corner0.normalize();
     //box->orig_corner7.normalize();
     double coord = (box->orig_corner0[axis] > box->orig_corner7[axis]) ?
@@ -666,10 +652,10 @@ void box3d_corners_for_PLs (const SPBox3D * box, Proj::Axis axis,
         default:
             return;
     }
-    corner1 = persp->tmat.image(c1).affine();
-    corner2 = persp->tmat.image(c2).affine();
-    corner3 = persp->tmat.image(c3).affine();
-    corner4 = persp->tmat.image(c4).affine();
+    corner1 = persp_impl->tmat.image(c1).affine();
+    corner2 = persp_impl->tmat.image(c2).affine();
+    corner3 = persp_impl->tmat.image(c3).affine();
+    corner4 = persp_impl->tmat.image(c4).affine();
 }
 
 /* Auxiliary function: Checks whether the half-line from A to B crosses the line segment joining C and D */
@@ -1027,7 +1013,7 @@ box3d_recompute_z_orders (SPBox3D *box) {
     Geom::Point dirs[3];
     for (int i = 0; i < 3; ++i) {
         dirs[i] = persp3d_get_PL_dir_from_pt(persp, c3, Box3D::toProj(Box3D::axes[i]));
-        if (persp3d_VP_is_finite(persp, Proj::axes[i])) {
+        if (persp3d_VP_is_finite(persp->perspective_impl, Proj::axes[i])) {
             num_finite++;
             axis_finite = Box3D::axes[i];
         } else {
@@ -1212,7 +1198,7 @@ box3d_pt_lies_in_PL_sector (SPBox3D const *box, Geom::Point const &pt, int id1,
     Geom::Point c2(box3d_get_corner_screen(box, id2, false));
 
     int ret = 0;
-    if (persp3d_VP_is_finite(persp, Box3D::toProj(axis))) {
+    if (persp3d_VP_is_finite(persp->perspective_impl, Box3D::toProj(axis))) {
         Geom::Point vp(persp3d_get_VP(persp, Box3D::toProj(axis)).affine());
         Geom::Point v1(c1 - vp);
         Geom::Point v2(c2 - vp);
@@ -1239,7 +1225,7 @@ int
 box3d_VP_lies_in_PL_sector (SPBox3D const *box, Proj::Axis vpdir, int id1, int id2, Box3D::Axis axis) {
     Persp3D *persp = box3d_get_perspective(box);
 
-    if (!persp3d_VP_is_finite(persp, vpdir)) {
+    if (!persp3d_VP_is_finite(persp->perspective_impl, vpdir)) {
         return 0;
     } else {
         return box3d_pt_lies_in_PL_sector(box, persp3d_get_VP(persp, vpdir).affine(), id1, id2, axis);
@@ -1302,31 +1288,6 @@ box3d_check_for_swapped_coords(SPBox3D *box) {
     box3d_exchange_coords(box);
 }
 
-void
-box3d_add_to_selection(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    g_return_if_fail(persp);
-    persp3d_add_box_transform(persp, box);
-}
-
-void
-box3d_remove_from_selection(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    if (!persp) {
-        /* this can happen if a box is deleted through undo and the persp_ref is already detached;
-           should we rebuild the boxes of each perspective in this case or is it safe to leave it alone? */
-        return;
-    }
-    persp3d_remove_box_transform(persp, box);
-}
-
-void
-box3d_mark_transformed(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    g_return_if_fail(persp);
-    persp3d_set_box_transformed(persp, box, true);
-}
-
 static void
 box3d_extract_boxes_rec(SPObject *obj, std::list<SPBox3D *> &boxes) {
     if (SP_IS_BOX3D(obj)) {
@@ -1360,16 +1321,13 @@ box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp,
         Geom::Point corner0_screen = box3d_get_corner_screen(box, 0, false);
         Geom::Point corner7_screen = box3d_get_corner_screen(box, 7, false);
 
-        box->orig_corner0 = new_persp->tmat.preimage(corner0_screen, z0, Proj::Z);
-        box->orig_corner7 = new_persp->tmat.preimage(corner7_screen, z7, Proj::Z);
+        box->orig_corner0 = new_persp->perspective_impl->tmat.preimage(corner0_screen, z0, Proj::Z);
+        box->orig_corner7 = new_persp->perspective_impl->tmat.preimage(corner7_screen, z7, Proj::Z);
     }
 
     persp3d_remove_box (old_persp, box);
     persp3d_add_box (new_persp, box);
 
-    persp3d_remove_box_transform (old_persp, box);
-    persp3d_add_box_transform (new_persp, box);
-
     gchar *href = g_strdup_printf("#%s", SP_OBJECT_REPR(new_persp)->attribute("id"));
     SP_OBJECT_REPR(box)->setAttribute("inkscape:perspectiveID", href);
     g_free(href);
index b6d962a3c924375ca6c6b3daa34df8c0e4dc53a7..9f2e1d78e8ac33210b80d30c5abaa56969600911 100644 (file)
@@ -70,10 +70,6 @@ int box3d_VP_lies_in_PL_sector (SPBox3D const *box, Proj::Axis vpdir, int id1, i
 void box3d_relabel_corners(SPBox3D *box);
 void box3d_check_for_swapped_coords(SPBox3D *box);
 
-void box3d_add_to_selection(SPBox3D *box);
-void box3d_remove_from_selection(SPBox3D *box);
-void box3d_mark_transformed(SPBox3D *box);
-
 std::list<SPBox3D *> box3d_extract_boxes(SPObject *obj);
 
 Persp3D *box3d_get_perspective(SPBox3D const *box);
index b9dc218b4fcc84bfaa48e06df9b81ad0c11cf701..b2aa0ce6bc1e9877242de5f3697a7a90048c410f 100644 (file)
@@ -19,6 +19,7 @@
 #include "2geom/line.h"
 #include "2geom/crossing.h"
 #include "2geom/convex-cover.h"
+#include "helper/geom-curves.h"
 #include "svg/stringstream.h"
 #include "conn-avoid-ref.h"
 #include "connection-points.h"
@@ -32,6 +33,7 @@
 #include "desktop.h"
 #include "desktop-handles.h"
 #include "sp-namedview.h"
+#include "sp-item-group.h"
 #include "inkscape.h"
 #include <glibmm/i18n.h>
 
@@ -232,7 +234,7 @@ void SPAvoidRef::addConnectionPoint(ConnectionPoint &cp)
     else
         ostr<<'|'<<cp;
 
-    this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Added a new connection point") );
+    this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Add a new connection point") );
 }
 
 void SPAvoidRef::updateConnectionPoint(ConnectionPoint &cp)
@@ -257,7 +259,7 @@ void SPAvoidRef::updateConnectionPoint(ConnectionPoint &cp)
             else
                 ostr<<'|'<<*to_write;
         }
-        this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Moved a connection point") );
+        this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Move a connection point") );
     }
 }
 
@@ -277,7 +279,7 @@ void SPAvoidRef::deleteConnectionPoint(ConnectionPoint &cp)
                 }
             }
         }
-        this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Removed a connection point") );
+        this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Remove a connection point") );
     }
 }
 
@@ -424,134 +426,123 @@ bool SPAvoidRef::isValidConnPointId( const int type, const int id )
     return true;
 }
 
-static Avoid::Polygon avoid_item_poly(SPItem const *item)
+static std::vector<Geom::Point> approxCurveWithPoints(SPCurve *curve)
 {
-    SPDesktop *desktop = inkscape_active_desktop();
-    g_assert(desktop != NULL);
-
-    // TODO: The right way to do this is to return the convex hull of
-    //       the object, or an approximation in the case of a rounded
-    //       object.  Specific SPItems will need to have a new
-    //       function that returns points for the convex hull.
-    //       For some objects it is enough to feed the snappoints to
-    //       some convex hull code, though not NR::ConvexHull as this
-    //       only keeps the bounding box of the convex hull currently.
-
-    double spacing = desktop->namedview->connector_spacing;
-
-    // [sommer] If item is a shape, use an approximation of its convex hull
+    // The number of segments to use for not straight curves approximation
+    const unsigned NUM_SEGS = 4;
+    
+    const Geom::PathVector& curve_pv = curve->get_pathvector();
+   
+    // The structure to hold the output
+    std::vector<Geom::Point> poly_points;
+
+    // Iterate over all curves, adding the endpoints for linear curves and
+    // sampling the other curves
+    double seg_size = 1.0 / NUM_SEGS;
+    double at;
+    at = 0;
+    Geom::PathVector::const_iterator pit = curve_pv.begin();
+    while (pit != curve_pv.end())
     {
-        // MJW: Disable this for the moment.  It still has some issues.
-        const bool convex_hull_approximation_enabled = false;
-
-        if ( convex_hull_approximation_enabled && SP_IS_SHAPE (item) ) {
-            // The number of points to use for approximation
-            const unsigned NUM_POINTS = 64;
-
-//             printf("[sommer] is a shape\n");
-            SPCurve* curve = sp_shape_get_curve (SP_SHAPE (item));
-            if (curve) {
-//                 printf("[sommer] is a curve\n");
-
-                // apply all transformations
-                Geom::Matrix itd_mat = sp_item_i2doc_affine(item);
-                curve->transform(itd_mat);
-
-                // iterate over all paths
-                const Geom::PathVector& curve_pv = curve->get_pathvector();
-                std::vector<Geom::Point> hull_points;
-                for (Geom::PathVector::const_iterator i = curve_pv.begin(); i != curve_pv.end(); i++) {
-                    const Geom::Path& curve_pv_path = *i;
-//                     printf("[sommer] tracing sub-path\n");
-
-                    // FIXME: enlarge path by "desktop->namedview->connector_spacing" (using sp_selected_path_do_offset)?
-
-                    // use appropriate fraction of points for this path (first one gets any remainder)
-                    unsigned num_points = NUM_POINTS / curve_pv.size();
-                    if (i == curve_pv.begin()) num_points += NUM_POINTS - (num_points * curve_pv.size());
-                    printf("[sommer] using %d points for this path\n", num_points);
-
-                    // sample points along the path for approximation of convex hull
-                    for (unsigned n = 0; n < num_points; n++) {
-                        double at = curve_pv_path.size() / static_cast<double>(num_points) * n;
-                        Geom::Point pt = curve_pv_path.pointAt(at);
-                        hull_points.push_back(pt);
-                    }
-                }
-
-                curve->unref();
-
-                // create convex hull from all sampled points
-                Geom::ConvexHull hull(hull_points);
-
-                // store expanded convex hull in Avoid::Polygn
-                unsigned n = 0;
-                Avoid::Polygon poly;
-/*
-                const Geom::Point& old_pt = *hull.boundary.begin();
-*/
-
-                Geom::Line hull_edge(*hull.boundary.begin(), *(hull.boundary.begin()+1));
-                Geom::Line parallel_hull_edge;
-                parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
-                parallel_hull_edge.versor(hull_edge.versor());
-                Geom::Line bisector = Geom::make_angle_bisector_line( *(hull.boundary.end()), *hull.boundary.begin(),
-                                                                      *(hull.boundary.begin()+1));
-                Geom::OptCrossing int_pt = Geom::intersection(parallel_hull_edge, bisector);
-
-                if (int_pt)
+        Geom::Path::const_iterator cit = pit->begin();
+        while (cit != pit->end())
+            if (dynamic_cast<Geom::CubicBezier const*>(&*cit))
+            {
+                at += seg_size;
+                if (at <= 1.0 )
+                    poly_points.push_back(cit->pointAt(at));
+                else
                 {
-                    Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
-                                            (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
-//                     printf("[sommer] %f, %f\n", old_pt[Geom::X], old_pt[Geom::Y]);
-/*                    printf("[sommer] %f, %f\n", (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
-                                                (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);*/
-                    poly.ps.push_back(avoid_pt);
-                }
-                for (std::vector<Geom::Point>::const_iterator i = hull.boundary.begin() + 1; i != hull.boundary.end(); i++, n++) {
-/*
-                        const Geom::Point& old_pt = *i;
-*/
-                        Geom::Line hull_edge(*i, *(i+1));
-                        Geom::Line parallel_hull_edge;
-                        parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
-                        parallel_hull_edge.versor(hull_edge.versor());
-                        Geom::Line bisector = Geom::make_angle_bisector_line( *(i-1), *i, *(i+1));
-                        Geom::OptCrossing intersect_pt = Geom::intersection(parallel_hull_edge, bisector);
-
-                        if (int_pt)
-                        {
-                            Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
-                                                  (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
-/*                            printf("[sommer] %f, %f\n", old_pt[Geom::X], old_pt[Geom::Y]);
-                            printf("[sommer] %f, %f\n", (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
-                                                        (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);*/
-                            poly.ps.push_back(avoid_pt);
-                        }
+                    at = 0.0;
+                    ++cit;
                 }
+            }
+            else
+            {
+                poly_points.push_back(cit->finalPoint());
+                ++cit;
+            }
+        ++pit;
+    }
+    return poly_points;
+}
 
+static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const Geom::Matrix& item_transform)
+{
+    // The structure to hold the output
+    std::vector<Geom::Point> poly_points;
 
-                return poly;
-            }// else printf("[sommer] is no curve\n");
-        }// else printf("[sommer] is no shape\n");
+    if (SP_IS_GROUP(item))
+    {
+        SPGroup* group = SP_GROUP(item);
+        // consider all first-order children
+        for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) {
+            SPItem* child_item = SP_ITEM(i->data);
+            std::vector<Geom::Point> child_points = approxItemWithPoints(child_item, item_transform * child_item->transform);
+            poly_points.insert(poly_points.end(), child_points.begin(), child_points.end());
+        }
     }
-
-    Geom::OptRect rHull = item->getBounds(sp_item_i2doc_affine(item));
-    if (!rHull) {
-        return Avoid::Polygon();
+    else if (SP_IS_SHAPE(item))
+    {
+        SPCurve* item_curve = sp_shape_get_curve(SP_SHAPE(item));
+        // make sure it has an associated curve
+        if (item_curve)
+        {
+            // apply transformations (up to common ancestor)
+            item_curve->transform(item_transform);
+            std::vector<Geom::Point> curve_points = approxCurveWithPoints(item_curve);
+            poly_points.insert(poly_points.end(), curve_points.begin(), curve_points.end());
+            item_curve->unref();
+        }
     }
 
-    // Add a little buffer around the edge of each object.
-    Geom::Rect rExpandedHull = *rHull;
-    rExpandedHull.expandBy(spacing);
-    Avoid::Polygon poly(4);
+    return poly_points;
+}
+static Avoid::Polygon avoid_item_poly(SPItem const *item)
+{
+    SPDesktop *desktop = inkscape_active_desktop();
+    g_assert(desktop != NULL);
+    double spacing = desktop->namedview->connector_spacing;
+
+    Geom::Matrix itd_mat = sp_item_i2doc_affine(item);
+    std::vector<Geom::Point> hull_points;
+    hull_points = approxItemWithPoints(item, itd_mat);
 
-    for (size_t n = 0; n < 4; ++n) {
-        Geom::Point hullPoint = rExpandedHull.corner(n);
-        poly.ps[n].x = hullPoint[Geom::X];
-        poly.ps[n].y = hullPoint[Geom::Y];
-    }
+    // create convex hull from all sampled points
+    Geom::ConvexHull hull(hull_points);
+
+    // enlarge path by "desktop->namedview->connector_spacing"
+    // store expanded convex hull in Avoid::Polygn
+    Avoid::Polygon poly;
 
+    Geom::Line hull_edge(hull[-1], hull[0]);
+    Geom::Line prev_parallel_hull_edge;
+    prev_parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
+    prev_parallel_hull_edge.versor(hull_edge.versor());
+    int hull_size = hull.boundary.size();
+    for (int i = 0; i <= hull_size; ++i)
+    {
+        hull_edge.setBy2Points(hull[i], hull[i+1]);
+        Geom::Line parallel_hull_edge;
+        parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
+        parallel_hull_edge.versor(hull_edge.versor());
+        
+        // determine the intersection point
+        
+        Geom::OptCrossing int_pt = Geom::intersection(parallel_hull_edge, prev_parallel_hull_edge);
+        if (int_pt)
+        {
+            Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
+                                    (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
+            poly.ps.push_back(avoid_pt);
+        }
+        else
+        {
+            // something went wrong...
+            std::cout<<"conn-avoid-ref.cpp: avoid_item_poly: Geom:intersection failed."<<std::endl;
+        }
+        prev_parallel_hull_edge = parallel_hull_edge;
+    }
     return poly;
 }
 
index 307d59d1f5f2efad35e2068b78e710424d0b71f3..0fc9de9d0384ee0e99d98e0366012ed7851aa2ce 100644 (file)
 #include "connector-context.h"
 #include "pixmaps/cursor-connector.xpm"
 #include "pixmaps/cursor-node.xpm"
-#include "pixmaps/cursor-node-m.xpm"
-#include "pixmaps/cursor-node-d.xpm"
+//#include "pixmaps/cursor-node-m.xpm"
+//#include "pixmaps/cursor-node-d.xpm"
 #include "xml/node-event-vector.h"
 #include "xml/repr.h"
 #include "svg/svg.h"
@@ -625,7 +625,6 @@ sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, G
                 {
                     spcc_reset_colors(cc);
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(event_context);
                 }
                 if (cc->state != SP_CONNECTOR_CONTEXT_IDLE) {
                     // Doing something else like rerouting.
@@ -757,7 +756,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
 
             switch (cc->state) {
                 case SP_CONNECTOR_CONTEXT_STOP:
-                    /* This is allowed, if we just cancelled curve */
+                    /* This is allowed, if we just canceled curve */
                 case SP_CONNECTOR_CONTEXT_IDLE:
                 {
                     if ( cc->npoints == 0 ) {
@@ -772,8 +771,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
                         // Test whether we clicked on a connection point
                         cc->sid = conn_pt_handle_test(cc, p);
 
-//                        sp_event_context_snap_window_open(event_context);
-
                         if (!cc->sid) {
                             // This is the first point, so just snap it to the grid
                             // as there's no other points to go off.
@@ -800,7 +797,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
                     }
                     cc_set_active_conn(cc, cc->newconn);
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(event_context);
                     ret = TRUE;
                     break;
                 }
@@ -819,7 +815,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
                 cc_connector_rerouting_finish(cc, &p);
 
                 cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                sp_event_context_snap_window_closed(event_context);
 
                 // Don't set ret to TRUE, so we drop through to the
                 // parent handler which will open the context menu.
@@ -827,7 +822,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
             else if (cc->npoints != 0) {
                 spcc_connector_finish(cc);
                 cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                sp_event_context_snap_window_closed(event_context);
                 ret = TRUE;
             }
         }
@@ -879,7 +873,6 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const
 
                     if ( cc->selected_handle )
                     {
-//                         sp_event_context_snap_window_open(event_context);
                         cc->state = SP_CONNECTOR_CONTEXT_DRAGGING;
                         cc->selection->set( SP_OBJECT( cc->active_shape ) );
                     }
@@ -1047,7 +1040,6 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
                     }
                     cc_set_active_conn(cc, cc->newconn);
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(event_context);
                     break;
                 }
                 case SP_CONNECTOR_CONTEXT_REROUTING:
@@ -1057,7 +1049,6 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
 
                     sp_document_ensure_up_to_date(doc);
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(event_context);
                     return TRUE;
                     break;
                 }
@@ -1077,10 +1068,8 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
 
                     if (!cc->within_tolerance)
                     {
-//                        sp_event_context_snap_window_open(event_context);
                         m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE);
                         sp_knot_set_position(cc->selected_handle, p, 0);
-//                        sp_event_context_snap_window_closed(event_context);
                         ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
                         cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
                         cc->active_shape->avoidRef->updateConnectionPoint(cp);
@@ -1092,11 +1081,9 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con
 
 
                 case SP_CONNECTOR_CONTEXT_NEWCONNPOINT:
-//                    sp_event_context_snap_window_open( event_context );
                     m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE);
 
                     sp_knot_set_position(cc->selected_handle, p, 0);
-//                    sp_event_context_snap_window_closed(event_context);
 
                     ConnectionPoint cp;
                     cp.type = ConnPointUserDefined;
@@ -1137,7 +1124,6 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
                 if (cc->npoints != 0) {
                     spcc_connector_finish(cc);
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc));
                     ret = TRUE;
                 }
                 break;
@@ -1152,7 +1138,6 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
                     sp_document_undo(doc);
 
                     cc->state = SP_CONNECTOR_CONTEXT_IDLE;
-//                    sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc));
                     desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE,
                             _("Connector endpoint drag cancelled."));
                     ret = TRUE;
@@ -1160,7 +1145,6 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
                 else if (cc->npoints != 0) {
                     // if drawing, cancel, otherwise pass it up for deselecting
                     cc->state = SP_CONNECTOR_CONTEXT_STOP;
-//                    sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc));
                     spcc_reset_colors(cc);
                     ret = TRUE;
                 }
@@ -1200,10 +1184,8 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
 
                     if (!cc->within_tolerance)
                     {
-//                        sp_event_context_snap_window_open(event_context);
                         m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE);
                         sp_knot_set_position(cc->selected_handle, p, 0);
-//                        sp_event_context_snap_window_closed(event_context);
                         ConnectionPoint& cp = cc->connpthandles[cc->selected_handle];
                         cp.pos = p * sp_item_dt2i_affine(cc->active_shape);
                         cc->active_shape->avoidRef->updateConnectionPoint(cp);
@@ -1229,13 +1211,10 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval)
                     SnapManager &m = desktop->namedview->snap_manager;
                     m.setup(desktop);
                     Geom::Point p = cc->selected_handle->pos;
-//                     SPEventContext* event_context = SP_EVENT_CONTEXT( cc );
 
-//                    sp_event_context_snap_window_open( event_context );
                     m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE);
 
                     sp_knot_set_position(cc->selected_handle, p, 0);
-//                    sp_event_context_snap_window_closed(event_context);
 
                     ConnectionPoint cp;
                     cp.type = ConnPointUserDefined;
@@ -1571,7 +1550,6 @@ endpt_handler(SPKnot */*knot*/, GdkEvent *event, SPConnectorContext *cc)
                 cc->clickedhandle = cc->active_handle;
                 cc_clear_active_conn(cc);
                 cc->state = SP_CONNECTOR_CONTEXT_REROUTING;
-//                sp_event_context_snap_window_open(SP_EVENT_CONTEXT(cc));
 
                 // Disconnect from attached shape
                 unsigned ind = (cc->active_handle == cc->endpt_handle[0]) ? 0 : 1;
index a92e7cf5bb993f758afd88e609cb3b5b8b211c10..ee05cd01cd011c6591301a6eb445e693a7a39e3c 100644 (file)
@@ -359,9 +359,9 @@ CanvasAxonomGrid::readRepr()
     }
 
     if ( (value = repr->attribute("snapvisiblegridlinesonly")) ) {
-               g_assert(snapper != NULL);
-               snapper->setSnapVisibleOnly(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
-       }
+        g_assert(snapper != NULL);
+        snapper->setSnapVisibleOnly(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
+    }
 
     for (GSList *l = canvasitems; l != NULL; l = l->next) {
         sp_canvas_item_request_update ( SP_CANVAS_ITEM(l->data) );
@@ -671,9 +671,9 @@ CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapMan
  */
 Geom::Coord CanvasAxonomGridSnapper::getSnapperTolerance() const
 {
-       SPDesktop const *dt = _snapmanager->getDesktop();
-       double const zoom =  dt ? dt->current_zoom() : 1;
-       return _snapmanager->snapprefs.getGridTolerance() / zoom;
+    SPDesktop const *dt = _snapmanager->getDesktop();
+    double const zoom =  dt ? dt->current_zoom() : 1;
+    return _snapmanager->snapprefs.getGridTolerance() / zoom;
 }
 
 bool CanvasAxonomGridSnapper::getSnapperAlwaysSnap() const
@@ -694,22 +694,22 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
     double spacing_v;
 
     if (getSnapVisibleOnly()) {
-               // Only snapping to visible grid lines
-               spacing_h = grid->spacing_ylines; // this is the spacing of the visible grid lines measured in screen pixels
-               spacing_v = grid->lyw; // vertical
-               // convert screen pixels to px
-               // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
-               SPDesktop const *dt = _snapmanager->getDesktop();
-               if (dt) {
-                       spacing_h /= dt->current_zoom();
-                       spacing_v /= dt->current_zoom();
-               }
-       } else {
-               // Snapping to any grid line, whether it's visible or not
-               spacing_h = grid->lengthy  /(grid->tan_angle[X] + grid->tan_angle[Z]);
-               spacing_v = grid->lengthy;
-
-       }
+        // Only snapping to visible grid lines
+        spacing_h = grid->spacing_ylines; // this is the spacing of the visible grid lines measured in screen pixels
+        spacing_v = grid->lyw; // vertical
+        // convert screen pixels to px
+        // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
+        SPDesktop const *dt = _snapmanager->getDesktop();
+        if (dt) {
+            spacing_h /= dt->current_zoom();
+            spacing_v /= dt->current_zoom();
+        }
+    } else {
+        // Snapping to any grid line, whether it's visible or not
+        spacing_h = grid->lengthy  /(grid->tan_angle[X] + grid->tan_angle[Z]);
+        spacing_v = grid->lengthy;
+
+    }
 
     // In an axonometric grid, any point will be surrounded by 6 grid lines:
     // - 2 vertical grid lines, one left and one right from the point
@@ -746,18 +746,18 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
     Geom::Point p_x(0, y_proj_along_x_max);
     Geom::Line line_x(p_x, p_x + vers_x);
     Geom::Point p_z(0, y_proj_along_z_max);
-       Geom::Line line_z(p_z, p_z + vers_z);
+    Geom::Line line_z(p_z, p_z + vers_z);
 
     Geom::OptCrossing inters = Geom::OptCrossing(); // empty by default
-       try
-       {
-               inters = Geom::intersection(line_x, line_z);
-       }
-       catch (Geom::InfiniteSolutions e)
-       {
-               // We're probably dealing with parallel lines; this is useless!
-               return s;
-       }
+    try
+    {
+        inters = Geom::intersection(line_x, line_z);
+    }
+    catch (Geom::InfiniteSolutions e)
+    {
+        // We're probably dealing with parallel lines; this is useless!
+        return s;
+    }
 
     // Determine which half of the parallelogram to use
     bool use_left_half = true;
@@ -765,7 +765,7 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
 
     if (inters) {
         Geom::Point inters_pt = line_x.pointAt((*inters).ta);
-       use_left_half = (p[Geom::X] - grid->origin[Geom::X]) < inters_pt[Geom::X];
+        use_left_half = (p[Geom::X] - grid->origin[Geom::X]) < inters_pt[Geom::X];
         use_right_half = !use_left_half;
     }
 
@@ -786,16 +786,16 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
     return s;
 }
 
-void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, source_num, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
 }
 
-void CanvasAxonomGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+void CanvasAxonomGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
 {
-       SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
-       sc.points.push_back(dummy);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    sc.points.push_back(dummy);
 }
 
 bool CanvasAxonomGridSnapper::ThisSnapperMightSnap() const
index e36804d7c409d60b125fac8fc99fcc55e17c857b..4b1cd48340ccec5215131c0e88084b5281283364 100644 (file)
@@ -78,8 +78,8 @@ public:
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
 
     CanvasAxonomGrid *grid;
 };
index 5037c0375a695e2d093023505a4613cdbe1c27b2..3532c504a73954f30666174de8e3c0f033774f9c 100644 (file)
@@ -635,9 +635,9 @@ CanvasXYGrid::readRepr()
     }
 
     if ( (value = repr->attribute("snapvisiblegridlinesonly")) ) {
-               g_assert(snapper != NULL);
-               snapper->setSnapVisibleOnly(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
-       }
+        g_assert(snapper != NULL);
+        snapper->setSnapVisibleOnly(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
+    }
 
     for (GSList *l = canvasitems; l != NULL; l = l->next) {
         sp_canvas_item_request_update ( SP_CANVAS_ITEM(l->data) );
@@ -972,9 +972,9 @@ CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Ge
  */
 Geom::Coord CanvasXYGridSnapper::getSnapperTolerance() const
 {
-       SPDesktop const *dt = _snapmanager->getDesktop();
-       double const zoom =  dt ? dt->current_zoom() : 1;
-       return _snapmanager->snapprefs.getGridTolerance() / zoom;
+    SPDesktop const *dt = _snapmanager->getDesktop();
+    double const zoom =  dt ? dt->current_zoom() : 1;
+    return _snapmanager->snapprefs.getGridTolerance() / zoom;
 }
 
 bool CanvasXYGridSnapper::getSnapperAlwaysSnap() const
@@ -993,20 +993,20 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
 
     for (unsigned int i = 0; i < 2; ++i) {
 
-       double spacing;
-
-       if (getSnapVisibleOnly()) {
-               // Only snapping to visible grid lines
-               spacing = grid->sw[i]; // this is the spacing of the visible grid lines measured in screen pixels
-                       // convert screen pixels to px
-                       // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
-                       SPDesktop const *dt = _snapmanager->getDesktop();
-               if (dt) {
-                       spacing /= dt->current_zoom();
-               }
+        double spacing;
+
+        if (getSnapVisibleOnly()) {
+            // Only snapping to visible grid lines
+            spacing = grid->sw[i]; // this is the spacing of the visible grid lines measured in screen pixels
+            // convert screen pixels to px
+            // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
+            SPDesktop const *dt = _snapmanager->getDesktop();
+            if (dt) {
+                spacing /= dt->current_zoom();
+            }
         } else {
-               // Snapping to any grid line, whether it's visible or not
-               spacing = grid->spacing[i];
+            // Snapping to any grid line, whether it's visible or not
+            spacing = grid->spacing[i];
         }
 
         Geom::Coord rounded;
@@ -1024,16 +1024,16 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
     return s;
 }
 
-void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, source_num, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
 }
 
-void CanvasXYGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+void CanvasXYGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
 {
-       SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
-       sc.points.push_back(dummy);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    sc.points.push_back(dummy);
 }
 
 /**
index 58cfbf735d63b9a5cdb9a32c9ca987fe02b863fd..daf28c15c4fcf62e9b63a21bb1d7e984df309fb0 100644 (file)
@@ -166,8 +166,8 @@ public:
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
     CanvasXYGrid *grid;
 };
 
index 20ea7d58cc5d3f6d9a0e4a2155193faaada73577..fdea9cbbfae1ecf3433bcbefee0c61e9f3664706 100644 (file)
@@ -46,11 +46,10 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const p)
 
     g_assert(_desktop != NULL);
 
-    /* Commented out for now, because this might hide any snapping bug!
     if (!p.getSnapped()) {
-       return; // If we haven't snapped, then it is of no use to draw a snapindicator
+        g_warning("No snapping took place, so no snap target will be displayed");
+        return; // If we haven't snapped, then it is of no use to draw a snapindicator
     }
-    */
 
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     bool value = prefs->getBool("/options/snapindicator/value", true);
index a3ad6f7beb1486a4bc236e6d0ff44213b2d89ef5..3104ade288663e40d9b79b41266dceb9ca224419 100644 (file)
@@ -97,10 +97,9 @@ SPDocument::SPDocument() :
     rerouting_handler_id(0),
     profileManager(0), // deferred until after other initialization
     router(new Avoid::Router(Avoid::PolyLineRouting|Avoid::OrthogonalRouting)),
-    perspectives(0),
-    current_persp3d(0),
     _collection_queue(0),
-    oldSignalsConnected(false)
+    oldSignalsConnected(false),
+    current_persp3d(0)
 {
     // Penalise libavoid for choosing paths with needless extra segments.
     // This results in much better looking orthogonal connector paths.
@@ -216,26 +215,43 @@ SPDocument::~SPDocument() {
     //delete this->_whiteboard_session_manager;
 }
 
-void SPDocument::add_persp3d (Persp3D * const /*persp*/)
-{
-    SPDefs *defs = SP_ROOT(this->root)->defs;
-    for (SPObject *i = sp_object_first_child(SP_OBJECT(defs)); i != NULL; i = SP_OBJECT_NEXT(i) ) {
-        if (SP_IS_PERSP3D(i)) {
-            g_print ("Encountered a Persp3D in defs\n");
-        }
+Persp3D *
+SPDocument::getCurrentPersp3D() {
+    // Check if current_persp3d is still valid
+    std::vector<Persp3D*> plist;
+    getPerspectivesInDefs(plist);
+    for (unsigned int i = 0; i < plist.size(); ++i) {
+        if (current_persp3d == plist[i])
+            return current_persp3d;
     }
 
-    g_print ("Adding Persp3D to defs\n");
-    persp3d_create_xml_element (this);
+    // If not, return the first perspective in defs (which may be NULL of none exists)
+    current_persp3d = persp3d_document_first_persp (this);
+
+    return current_persp3d;
 }
 
-void SPDocument::remove_persp3d (Persp3D * const /*persp*/)
-{
-    // TODO: Delete the repr, maybe perform a check if any boxes are still linked to the perspective.
-    //       Anything else?
-    g_print ("Please implement deletion of perspectives here.\n");
+Persp3DImpl *
+SPDocument::getCurrentPersp3DImpl() {
+    return current_persp3d_impl;
 }
 
+void
+SPDocument::setCurrentPersp3D(Persp3D * const persp) {
+    current_persp3d = persp;
+    //current_persp3d_impl = persp->perspective_impl;
+}
+
+void
+SPDocument::getPerspectivesInDefs(std::vector<Persp3D*> &list) {
+    SPDefs *defs = SP_ROOT(this->root)->defs;
+    for (SPObject *i = sp_object_first_child(SP_OBJECT(defs)); i != NULL; i = SP_OBJECT_NEXT(i) ) {
+        if (SP_IS_PERSP3D(i))
+            list.push_back(SP_PERSP3D(i));
+    }
+}
+
+/**
 void SPDocument::initialize_current_persp3d()
 {
     this->current_persp3d = persp3d_document_first_persp(this);
@@ -243,6 +259,7 @@ void SPDocument::initialize_current_persp3d()
         this->current_persp3d = persp3d_create_xml_element(this);
     }
 }
+**/
 
 unsigned long SPDocument::serial() const {
     return priv->serial;
@@ -390,10 +407,14 @@ sp_document_create(Inkscape::XML::Document *rdoc,
         inkscape_ref();
     }
 
-    // Remark: Here, we used to create a "currentpersp3d" element in the document defs.
-    // But this is probably a bad idea since we need to adapt it for every change of selection, which will
-    // completely clutter the undo history. Maybe rather save it to prefs on exit and re-read it on startup?
-    document->initialize_current_persp3d();
+    // Check if the document already has a perspective (e.g., when opening an existing
+    // document). If not, create a new one and set it as the current perspective.
+    document->setCurrentPersp3D(persp3d_document_first_persp(document));
+    if (!document->getCurrentPersp3D()) {
+        //document->setCurrentPersp3D(persp3d_create_xml_element (document));
+        Persp3DImpl *persp_impl = new Persp3DImpl();
+        document->setCurrentPersp3DImpl(persp_impl);
+    }
 
     sp_document_set_undo_sensitive(document, true);
 
@@ -746,11 +767,13 @@ SPDocument::emitReconstructionFinish(void)
 {
     // printf("Finishing Reconstruction\n");
     priv->_reconstruction_finish_signal.emit();
-    
+
+/**    
     // Reference to the old persp3d object is invalid after reconstruction.
     initialize_current_persp3d();
     
     return;
+**/
 }
 
 sigc::connection SPDocument::connectCommit(SPDocument::CommitSignal::slot_type slot)
index 06174c265f593b402151200b2fcb2e6a221f6c26..e83c37a968a2d4584cd020ed5173d70752aa7207 100644 (file)
@@ -55,6 +55,7 @@ namespace Inkscape {
 
 class SP3DBox;
 class Persp3D;
+class Persp3DImpl;
 
 namespace Proj {
     class TransfMat3x4;
@@ -107,17 +108,26 @@ struct SPDocument : public Inkscape::GC::Managed<>,
     // Instance of the connector router
     Avoid::Router *router;
 
-    GSList *perspectives;
-
-    Persp3D *current_persp3d; // "currently active" perspective (e.g., newly created boxes are attached to this one)
-
     GSList *_collection_queue;
 
     bool oldSignalsConnected;
 
-    void add_persp3d(Persp3D * const persp);
-    void remove_persp3d(Persp3D * const persp);
-    void initialize_current_persp3d();
+    void setCurrentPersp3D(Persp3D * const persp);
+    inline void setCurrentPersp3DImpl(Persp3DImpl * const persp_impl) { current_persp3d_impl = persp_impl; }
+    /*
+     * getCurrentPersp3D returns current_persp3d (if non-NULL) or the first
+     * perspective in the defs. If no perspective exists, returns NULL.
+     */
+    Persp3D * getCurrentPersp3D();
+    Persp3DImpl * getCurrentPersp3DImpl();
+    void getPerspectivesInDefs(std::vector<Persp3D*> &list);
+    unsigned int numPerspectivesInDefs() {
+        std::vector<Persp3D*> list;
+        getPerspectivesInDefs(list);
+        return list.size();
+    }
+
+    //void initialize_current_persp3d();
 
     sigc::connection connectModified(ModifiedSignal::slot_type slot);
     sigc::connection connectURISet(URISetSignal::slot_type slot);
@@ -155,6 +165,9 @@ private:
     SPDocument(SPDocument const &); // no copy
     void operator=(SPDocument const &); // no assign
 
+    Persp3D *current_persp3d; /**< Currently 'active' perspective (to which, e.g., newly created boxes are attached) */
+    Persp3DImpl *current_persp3d_impl;
+
 public:
     sigc::connection connectReconstructionStart(ReconstructionStart::slot_type slot);
     sigc::connection connectReconstructionFinish(ReconstructionFinish::slot_type slot);
index 9b846f2b7e51a5f54e88c6e15363e33be52dcae8..918e3d4194cdb57baff49f51109aca5a7556e7fb 100644 (file)
@@ -174,7 +174,7 @@ sp_event_context_dispose(GObject *object)
     }
 
     if (ec->_delayed_snap_event) {
-       delete ec->_delayed_snap_event;
+        delete ec->_delayed_snap_event;
     }
 
     G_OBJECT_CLASS(parent_class)->dispose(object);
@@ -374,9 +374,9 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
             switch (event->button.button) {
                 case 1:
                     if (event_context->space_panning) {
-                       // When starting panning, make sure there are no snap events pending because these might disable the panning again
-                       sp_event_context_discard_delayed_snap_event(event_context);
-                       panning = 1;
+                        // When starting panning, make sure there are no snap events pending because these might disable the panning again
+                        sp_event_context_discard_delayed_snap_event(event_context);
+                        panning = 1;
                         sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
                             GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK,
                             NULL, event->button.time-1);
@@ -387,9 +387,9 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                     if (event->button.state & GDK_SHIFT_MASK) {
                         zoom_rb = 2;
                     } else {
-                       // When starting panning, make sure there are no snap events pending because these might disable the panning again
-                                               sp_event_context_discard_delayed_snap_event(event_context);
-                                               panning = 2;
+                        // When starting panning, make sure there are no snap events pending because these might disable the panning again
+                        sp_event_context_discard_delayed_snap_event(event_context);
+                        panning = 2;
                         sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
                             GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK,
                             NULL, event->button.time-1);
@@ -399,9 +399,9 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                 case 3:
                     if (event->button.state & GDK_SHIFT_MASK
                             || event->button.state & GDK_CONTROL_MASK) {
-                       // When starting panning, make sure there are no snap events pending because these might disable the panning again
-                                               sp_event_context_discard_delayed_snap_event(event_context);
-                       panning = 3;
+                        // When starting panning, make sure there are no snap events pending because these might disable the panning again
+                        sp_event_context_discard_delayed_snap_event(event_context);
+                        panning = 3;
                         sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
                                 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK,
                                 NULL, event->button.time);
@@ -421,7 +421,7 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                         || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))
                    ) {
                     /* Gdk seems to lose button release for us sometimes :-( */
-                       panning = 0;
+                    panning = 0;
                     sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
                             event->button.time);
                     ret = TRUE;
@@ -514,11 +514,11 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
             }
             break;
         case GDK_KEY_PRESS:
-               {
-               double const acceleration = prefs->getDoubleLimited("/options/scrollingacceleration/value", 0, 0, 6);
-               int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", 10, 0, 1000);
+            {
+            double const acceleration = prefs->getDoubleLimited("/options/scrollingacceleration/value", 0, 0, 6);
+            int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", 10, 0, 1000);
 
-               switch (get_group0_keyval(&event->key)) {
+            switch (get_group0_keyval(&event->key)) {
                 // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets
                 // in the editing window). So we resteal them back and run our regular shortcut
                 // invoker on them.
@@ -545,11 +545,11 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                     break;
                 case GDK_Q:
                 case GDK_q:
-                                       if (desktop->quick_zoomed()) {
-                                               ret = TRUE;
-                                       }
+                    if (desktop->quick_zoomed()) {
+                        ret = TRUE;
+                    }
                     if (!MOD__SHIFT && !MOD__CTRL && !MOD__ALT) {
-                                               desktop->zoom_quick(true);
+                        desktop->zoom_quick(true);
                         ret = TRUE;
                     }
                     break;
@@ -632,7 +632,7 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                 default:
                     break;
             }
-               }
+            }
             break;
         case GDK_KEY_RELEASE:
             switch (get_group0_keyval(&event->key)) {
@@ -651,8 +651,8 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context,
                     break;
                 case GDK_Q:
                 case GDK_q:
-                                       if (desktop->quick_zoomed()) {
-                                               desktop->zoom_quick(false);
+                    if (desktop->quick_zoomed()) {
+                        desktop->zoom_quick(false);
                         ret = TRUE;
                     }
                     break;
@@ -907,24 +907,24 @@ gint
 sp_event_context_root_handler(SPEventContext * event_context, GdkEvent * event)
 {
     switch (event->type) {
-               case GDK_MOTION_NOTIFY:
-                       sp_event_context_snap_delay_handler(event_context, NULL, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER);
-                       break;
-               case GDK_BUTTON_RELEASE:
-                       if (event_context->_delayed_snap_event) {
-                               // If we have any pending snapping action, then invoke it now
-                               sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event);
-                       }
-                       break;
-               case GDK_BUTTON_PRESS:
+        case GDK_MOTION_NOTIFY:
+            sp_event_context_snap_delay_handler(event_context, NULL, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER);
+            break;
+        case GDK_BUTTON_RELEASE:
+            if (event_context->_delayed_snap_event) {
+                // If we have any pending snapping action, then invoke it now
+                sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event);
+            }
+            break;
+        case GDK_BUTTON_PRESS:
         case GDK_2BUTTON_PRESS:
         case GDK_3BUTTON_PRESS:
-                       // Snapping will be on hold if we're moving the mouse at high speeds. When starting
-                       // drawing a new shape we really should snap though.
-                       event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
-                       break;
+            // Snapping will be on hold if we're moving the mouse at high speeds. When starting
+            // drawing a new shape we really should snap though.
+            event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
+            break;
         default:
-               break;
+            break;
     }
 
     return sp_event_context_virtual_root_handler(event_context, event);
@@ -933,9 +933,9 @@ sp_event_context_root_handler(SPEventContext * event_context, GdkEvent * event)
 gint
 sp_event_context_virtual_root_handler(SPEventContext * event_context, GdkEvent * event)
 {
-       gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler(event_context, event);
-       set_event_location(event_context->desktop, event);
-       return ret;
+    gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler(event_context, event);
+    set_event_location(event_context->desktop, event);
+    return ret;
 }
 
 /**
@@ -944,27 +944,27 @@ sp_event_context_virtual_root_handler(SPEventContext * event_context, GdkEvent *
 gint
 sp_event_context_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event)
 {
-       switch (event->type) {
-               case GDK_MOTION_NOTIFY:
-                       sp_event_context_snap_delay_handler(event_context, item, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER);
-                       break;
-               case GDK_BUTTON_RELEASE:
-                       if (event_context->_delayed_snap_event) {
-                               // If we have any pending snapping action, then invoke it now
-                               sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event);
-                       }
-                       break;
-               /*case GDK_BUTTON_PRESS:
-               case GDK_2BUTTON_PRESS:
-               case GDK_3BUTTON_PRESS:
-                       // Snapping will be on hold if we're moving the mouse at high speeds. When starting
-                       // drawing a new shape we really should snap though.
-                       event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
-                       break;
-               */
-               default:
-                       break;
-       }
+    switch (event->type) {
+        case GDK_MOTION_NOTIFY:
+            sp_event_context_snap_delay_handler(event_context, item, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER);
+            break;
+        case GDK_BUTTON_RELEASE:
+            if (event_context->_delayed_snap_event) {
+                // If we have any pending snapping action, then invoke it now
+                sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event);
+            }
+            break;
+        /*case GDK_BUTTON_PRESS:
+        case GDK_2BUTTON_PRESS:
+        case GDK_3BUTTON_PRESS:
+            // Snapping will be on hold if we're moving the mouse at high speeds. When starting
+            // drawing a new shape we really should snap though.
+            event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
+            break;
+        */
+        default:
+            break;
+    }
 
     return sp_event_context_virtual_item_handler(event_context, item, event);
 }
@@ -972,15 +972,15 @@ sp_event_context_item_handler(SPEventContext * event_context, SPItem * item, Gdk
 gint
 sp_event_context_virtual_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event)
 {
-       gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->item_handler(event_context, item, event);
+    gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->item_handler(event_context, item, event);
 
-       if (! ret) {
-               ret = sp_event_context_virtual_root_handler(event_context, event);
-       } else {
-               set_event_location(event_context->desktop, event);
-       }
+    if (! ret) {
+        ret = sp_event_context_virtual_root_handler(event_context, event);
+    } else {
+        set_event_location(event_context->desktop, event);
+    }
 
-       return ret;
+    return ret;
 }
 
 /**
@@ -1174,124 +1174,124 @@ event_context_print_event_info(GdkEvent *event, bool print_return) {
 
 void sp_event_context_snap_delay_handler(SPEventContext *ec, SPItem* const item, SPKnot* const knot, GdkEventMotion *event, DelayedSnapEvent::DelayedSnapEventOrigin origin)
 {
-       static guint32 prev_time;
-       static boost::optional<Geom::Point> prev_pos;
+    static guint32 prev_time;
+    static boost::optional<Geom::Point> prev_pos;
 
-       // Snapping occurs when dragging with the left mouse button down, or when hovering e.g. in the pen tool with left mouse button up
+    // Snapping occurs when dragging with the left mouse button down, or when hovering e.g. in the pen tool with left mouse button up
     bool const c1 = event->state & GDK_BUTTON2_MASK; // We shouldn't hold back any events when other mouse buttons have been
     bool const c2 = event->state & GDK_BUTTON3_MASK; // pressed, e.g. when scrolling with the middle mouse button; if we do then
-                                                                                                    // Inkscape will get stuck in an unresponsive state
+                                                     // Inkscape will get stuck in an unresponsive state
     bool const c3 = tools_isactive(ec->desktop, TOOLS_CALLIGRAPHIC);
                                                      // The snap delay will repeat the last motion event, which will lead to
                                                      // erroneous points in the calligraphy context. And because we don't snap
                                                      // in this context, we might just as well disable the snap delay all together
  
     if (c1 || c2 || c3) {
-       // Make sure that we don't send any pending snap events to a context if we know in advance
-       // that we're not going to snap any way (e.g. while scrolling with middle mouse button)
-       // Any motion event might affect the state of the context, leading to unexpected behavior
-       sp_event_context_discard_delayed_snap_event(ec);
+        // Make sure that we don't send any pending snap events to a context if we know in advance
+        // that we're not going to snap any way (e.g. while scrolling with middle mouse button)
+        // Any motion event might affect the state of the context, leading to unexpected behavior
+        sp_event_context_discard_delayed_snap_event(ec);
     } else if (ec->desktop && ec->desktop->namedview->snap_manager.snapprefs.getSnapEnabledGlobally()) {
-               // Snap when speed drops below e.g. 0.02 px/msec, or when no motion events have occurred for some period.
-               // i.e. snap when we're at stand still. A speed threshold enforces snapping for tablets, which might never
-               // be fully at stand still and might keep spitting out motion events.
-               ec->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold
-
-               Geom::Point event_pos(event->x, event->y);
-               guint32 event_t = gdk_event_get_time ( (GdkEvent *) event );
-
-               if (prev_pos) {
-                       Geom::Coord dist = Geom::L2(event_pos - *prev_pos);
-                       guint32 delta_t = event_t - prev_time;
-                       gdouble speed = delta_t > 0 ? dist/delta_t : 1000;
-                       //std::cout << "Mouse speed = " << speed << " px/msec " << std::endl;
-                       if (speed > 0.02) { // Jitter threshold, might be needed for tablets
-                               // We're moving fast, so postpone any snapping until the next GDK_MOTION_NOTIFY event. We
-                               // will keep on postponing the snapping as long as the speed is high.
-                               // We must snap at some point in time though, so set a watchdog timer at some time from
-                               // now, just in case there's no future motion event that drops under the speed limit (when
-                               // stopping abruptly)
-                               delete ec->_delayed_snap_event;
-                               ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin); // watchdog is reset, i.e. pushed forward in time
-                               // If the watchdog expires before a new motion event is received, we will snap (as explained
-                               // above). This means however that when the timer is too short, we will always snap and that the
-                               // speed threshold is ineffective. In the extreme case the delay is set to zero, and snapping will
-                               // be immediate, as it used to be in the old days ;-).
-                       } else { // Speed is very low, so we're virtually at stand still
-                               // But if we're really standing still, then we should snap now. We could use some low-pass filtering,
-                               // otherwise snapping occurs for each jitter movement. For this filtering we'll leave the watchdog to expire,
-                               // snap, and set a new watchdog again.
-                               if (ec->_delayed_snap_event == NULL) { // no watchdog has been set
-                                       // it might have already expired, so we'll set a new one; the snapping frequency will be limited by this
-                                       ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin);
-                               } // else: watchdog has been set before and we'll wait for it to expire
-                       }
-               } else {
-                       // This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog
-                       g_assert(ec->_delayed_snap_event == NULL);
-                       ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin);
-               }
-
-               prev_pos = event_pos;
-               prev_time = event_t;
+        // Snap when speed drops below e.g. 0.02 px/msec, or when no motion events have occurred for some period.
+        // i.e. snap when we're at stand still. A speed threshold enforces snapping for tablets, which might never
+        // be fully at stand still and might keep spitting out motion events.
+        ec->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold
+
+        Geom::Point event_pos(event->x, event->y);
+        guint32 event_t = gdk_event_get_time ( (GdkEvent *) event );
+
+        if (prev_pos) {
+            Geom::Coord dist = Geom::L2(event_pos - *prev_pos);
+            guint32 delta_t = event_t - prev_time;
+            gdouble speed = delta_t > 0 ? dist/delta_t : 1000;
+            //std::cout << "Mouse speed = " << speed << " px/msec " << std::endl;
+            if (speed > 0.02) { // Jitter threshold, might be needed for tablets
+                // We're moving fast, so postpone any snapping until the next GDK_MOTION_NOTIFY event. We
+                // will keep on postponing the snapping as long as the speed is high.
+                // We must snap at some point in time though, so set a watchdog timer at some time from
+                // now, just in case there's no future motion event that drops under the speed limit (when
+                // stopping abruptly)
+                delete ec->_delayed_snap_event;
+                ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin); // watchdog is reset, i.e. pushed forward in time
+                // If the watchdog expires before a new motion event is received, we will snap (as explained
+                // above). This means however that when the timer is too short, we will always snap and that the
+                // speed threshold is ineffective. In the extreme case the delay is set to zero, and snapping will
+                // be immediate, as it used to be in the old days ;-).
+            } else { // Speed is very low, so we're virtually at stand still
+                // But if we're really standing still, then we should snap now. We could use some low-pass filtering,
+                // otherwise snapping occurs for each jitter movement. For this filtering we'll leave the watchdog to expire,
+                // snap, and set a new watchdog again.
+                if (ec->_delayed_snap_event == NULL) { // no watchdog has been set
+                    // it might have already expired, so we'll set a new one; the snapping frequency will be limited this way
+                    ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin);
+                } // else: watchdog has been set before and we'll wait for it to expire
+            }
+        } else {
+            // This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog
+            g_assert(ec->_delayed_snap_event == NULL);
+            ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin);
+        }
+
+        prev_pos = event_pos;
+        prev_time = event_t;
     }
 }
 
 gboolean sp_event_context_snap_watchdog_callback(gpointer data)
 {
-       // Snap NOW! For this the "postponed" flag will be reset and the last motion event will be repeated
-       DelayedSnapEvent *dse = reinterpret_cast<DelayedSnapEvent*>(data);
-
-       if (dse == NULL) {
-               // This might occur when this method is called directly, i.e. not through the timer
-               // E.g. on GDK_BUTTON_RELEASE in sp_event_context_root_handler()
-               return FALSE;
-       }
-
-       SPEventContext *ec = dse->getEventContext();
-       if (ec == NULL || ec->desktop == NULL) {
-               return false;
-       }
-
-       SPDesktop *dt = ec->desktop;
-       dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
-
-       switch (dse->getOrigin()) {
-               case DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER:
-                       sp_event_context_virtual_root_handler(ec, dse->getEvent());
-                       break;
-               case DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER:
-                       {
-                               SPItem* item = NULL;
-                               item = dse->getItem();
-                               if (item && SP_IS_ITEM(item)) {
-                                       sp_event_context_virtual_item_handler(ec, item, dse->getEvent());
-                               }
-                       }
-                       break;
-               case DelayedSnapEvent::KNOT_HANDLER:
-                       {
-                               SPKnot* knot = dse->getKnot();
-                               if (knot && SP_IS_KNOT(knot)) {
-                                       sp_knot_handler_request_position(dse->getEvent(), knot);
-                               }
-                       }
-                       break;
-               default:
-                       g_warning("Origin of snap-delay event has not been defined!;");
-                       break;
-       }
-
-       ec->_delayed_snap_event = NULL;
-       delete dse;
-
-       return FALSE; //Kills the timer and stops it from executing this callback over and over again.
+    // Snap NOW! For this the "postponed" flag will be reset and the last motion event will be repeated
+    DelayedSnapEvent *dse = reinterpret_cast<DelayedSnapEvent*>(data);
+
+    if (dse == NULL) {
+        // This might occur when this method is called directly, i.e. not through the timer
+        // E.g. on GDK_BUTTON_RELEASE in sp_event_context_root_handler()
+        return FALSE;
+    }
+
+    SPEventContext *ec = dse->getEventContext();
+    if (ec == NULL || ec->desktop == NULL) {
+        return false;
+    }
+
+    SPDesktop *dt = ec->desktop;
+    dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false);
+
+    switch (dse->getOrigin()) {
+        case DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER:
+            sp_event_context_virtual_root_handler(ec, dse->getEvent());
+            break;
+        case DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER:
+            {
+                SPItem* item = NULL;
+                item = dse->getItem();
+                if (item && SP_IS_ITEM(item)) {
+                    sp_event_context_virtual_item_handler(ec, item, dse->getEvent());
+                }
+            }
+            break;
+        case DelayedSnapEvent::KNOT_HANDLER:
+            {
+                SPKnot* knot = dse->getKnot();
+                if (knot && SP_IS_KNOT(knot)) {
+                    sp_knot_handler_request_position(dse->getEvent(), knot);
+                }
+            }
+            break;
+        default:
+            g_warning("Origin of snap-delay event has not been defined!;");
+            break;
+    }
+
+    ec->_delayed_snap_event = NULL;
+    delete dse;
+
+    return FALSE; //Kills the timer and stops it from executing this callback over and over again.
 }
 
 void sp_event_context_discard_delayed_snap_event(SPEventContext *ec)
 {
-       delete ec->_delayed_snap_event;
-       ec->_delayed_snap_event = NULL;
+    delete ec->_delayed_snap_event;
+    ec->_delayed_snap_event = NULL;
 }
 
 
index c16ed2456548e33f7adcc5a72d874835ca79b1d1..e61bd95527212f795b3a0824156637b4b1f0b5ef 100644 (file)
@@ -609,7 +609,7 @@ gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gp
                 dist = fabs(p[Geom::Y] - dragger->parent->hor_levels[i]);
                 if (dist < snap_dist) {
                     p[Geom::Y] = dragger->parent->hor_levels[i];
-                    s = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_HANDLE, Inkscape::SNAPTARGET_GRADIENTS_PARENT_BBOX, dist, snap_dist, false, false);
+                    s = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_HANDLE, 0, Inkscape::SNAPTARGET_GRADIENTS_PARENT_BBOX, dist, snap_dist, false, false);
                     was_snapped = true;
                     sp_knot_moveto (knot, p);
                 }
@@ -618,7 +618,7 @@ gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gp
                 dist = fabs(p[Geom::X] - dragger->parent->vert_levels[i]);
                 if (dist < snap_dist) {
                     p[Geom::X] = dragger->parent->vert_levels[i];
-                    s = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_HANDLE, Inkscape::SNAPTARGET_GRADIENTS_PARENT_BBOX, dist, snap_dist, false, false);
+                    s = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_HANDLE, 0, Inkscape::SNAPTARGET_GRADIENTS_PARENT_BBOX, dist, snap_dist, false, false);
                     was_snapped = true;
                     sp_knot_moveto (knot, p);
                 }
index 5cf97958a299390600e3c2eb0bda64dfbb301a80..9121e3ee20df852d4bb0bd15242a7ddddb58064e 100644 (file)
@@ -68,22 +68,22 @@ bool Inkscape::GuideSnapper::ThisSnapperMightSnap() const
     return (_snap_enabled && _snapmanager->snapprefs.getSnapToGuides() && _snapmanager->getNamedView()->showguides);
 }
 
-void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GUIDE, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, source_num, Inkscape::SNAPTARGET_GUIDE, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.guide_lines.push_back(dummy);
 }
 
-void Inkscape::GuideSnapper::_addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+void Inkscape::GuideSnapper::_addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
 {
-    SnappedPoint dummy = SnappedPoint(origin, source, Inkscape::SNAPTARGET_GUIDE_ORIGIN, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(origin, source, source_num, Inkscape::SNAPTARGET_GUIDE_ORIGIN, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
     sc.points.push_back(dummy);
 }
 
 
-void Inkscape::GuideSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+void Inkscape::GuideSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const
 {
-    SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GUIDE, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+    SnappedPoint dummy = SnappedPoint(snapped_point, source, source_num, Inkscape::SNAPTARGET_GUIDE, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
     sc.points.push_back(dummy);
 }
 
index 1dc602f72075df6b00a904237c1e1efff5d05cb5..5adac6e2220951ef6d39d31ad27c3825002e18c7 100644 (file)
@@ -30,13 +30,13 @@ public:
     bool ThisSnapperMightSnap() const;
 
     Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
-       bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
+    bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
-    void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
-    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
+    void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
 };
 
 }
index 3b99678e26b40255080f69d65f685be95e78284f..74f9d036b49feee1466dd44ff36a8c946fa165a2 100644 (file)
@@ -773,6 +773,7 @@ nr_R8G8B8A8_P_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const un
                c[3] = a;
                /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
                nr_mmx_R8G8B8A8_P_EMPTY_A8_RGBAP (px, w, h, rs, mpx, mrs, c);
+               // This mmx optimized code is approx. 2x faster than the non-optimized code below (Measured by Diederik van Lierop, 2009-12-17)
                return;
        }
 #endif
index fec9316b98a7aa3e3493e0fd9ca77133aa5c02cd..1f85ee5ca7c39e2cac79ade09a814c66b2c541f6 100644 (file)
 /* Freetype2 */
 # include <pango/pangoft2.h>
 
+#include <ext/hash_map>
+
+
+typedef __gnu_cxx::hash_map<PangoFontDescription*, font_instance*, font_descr_hash, font_descr_equal> FaceMapType;
 
 // need to avoid using the size field
 size_t font_descr_hash::operator()( PangoFontDescription *const &x) const {
@@ -299,20 +303,25 @@ font_factory *font_factory::Default(void)
     return lUsine;
 }
 
-font_factory::font_factory(void)
-{
-    fontSize = 512;
-    nbEnt = 0;
-    maxEnt = 32;
-    ents = (font_entry*)g_malloc(maxEnt*sizeof(font_entry));
+font_factory::font_factory(void) :
+    nbEnt(0),
+    maxEnt(32),
+    ents(static_cast<font_entry*>(g_malloc(maxEnt*sizeof(font_entry)))),
 
 #ifdef USE_PANGO_WIN32
-    hScreenDC = pango_win32_get_dc();
-    fontServer = pango_win32_font_map_for_display();
-    fontContext = pango_win32_get_context();
-    pangoFontCache = pango_win32_font_map_get_font_cache(fontServer);
+    fontServer(pango_win32_font_map_for_display()),
+    fontContext(pango_win32_get_context()),
+    pangoFontCache(pango_win32_font_map_get_font_cache(fontServer)),
+    hScreenDC(pango_win32_get_dc()),
+#else
+    fontServer(pango_ft2_font_map_new()),
+    fontContext(0),
+#endif
+    fontSize(512),
+    loadedPtr(new FaceMapType())
+{
+#ifdef USE_PANGO_WIN32
 #else
-    fontServer = pango_ft2_font_map_new();
     pango_ft2_font_map_set_resolution((PangoFT2FontMap*)fontServer, 72, 72);
     fontContext = pango_ft2_font_map_create_context((PangoFT2FontMap*)fontServer);
     pango_ft2_font_map_set_default_substitute((PangoFT2FontMap*)fontServer,FactorySubstituteFunc,this,NULL);
@@ -321,6 +330,11 @@ font_factory::font_factory(void)
 
 font_factory::~font_factory(void)
 {
+    if (loadedPtr) {
+        FaceMapType* tmp = static_cast<FaceMapType*>(loadedPtr);
+        loadedPtr = 0;
+    }
+
     for (int i = 0;i < nbEnt;i++) ents[i].f->Unref();
     if ( ents ) g_free(ents);
 
@@ -793,6 +807,7 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
 
     font_instance *res = NULL;
 
+    FaceMapType& loadedFaces = *static_cast<FaceMapType*>(loadedPtr);
     if ( loadedFaces.find(descr) == loadedFaces.end() ) {
         // not yet loaded
         PangoFont *nFace = NULL;
@@ -849,8 +864,9 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
         res->Ref();
         AddInCache(res);
     }
-    if(res)
-       res->InitTheFace();
+    if (res) {
+        res->InitTheFace();
+    }
     return res;
 }
 
@@ -924,15 +940,18 @@ font_instance *font_factory::Face(char const *family, NRTypePosDef apos)
 
 void font_factory::UnrefFace(font_instance *who)
 {
-    if ( who == NULL ) return;
-    if ( loadedFaces.find(who->descr) == loadedFaces.end() ) {
-        // not found
-        char *tc = pango_font_description_to_string(who->descr);
-        g_warning("unrefFace %p=%s: failed\n",who,tc);
-        g_free(tc);
-    } else {
-        loadedFaces.erase(loadedFaces.find(who->descr));
-        //                     printf("unrefFace %p: success\n",who);
+    if ( who ) {
+        FaceMapType& loadedFaces = *static_cast<FaceMapType*>(loadedPtr);
+
+        if ( loadedFaces.find(who->descr) == loadedFaces.end() ) {
+            // not found
+            char *tc = pango_font_description_to_string(who->descr);
+            g_warning("unrefFace %p=%s: failed\n",who,tc);
+            g_free(tc);
+        } else {
+            loadedFaces.erase(loadedFaces.find(who->descr));
+            //                 printf("unrefFace %p: success\n",who);
+        }
     }
 }
 
index 9f4b31a2e5c776f967d85ef1e7ccec5412a24f4a..8d85bcf3e88e3127181c604ef0b9b6edb2717aba 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <functional>
 #include <algorithm>
-#include <ext/hash_map>
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -84,31 +83,29 @@ public:
     double fontSize; /**< The huge fontsize used as workaround for hinting.
                       *   Different between freetype and win32. */
 
-    __gnu_cxx::hash_map<PangoFontDescription*, font_instance*, font_descr_hash, font_descr_equal> loadedFaces;
-
     font_factory();
     virtual ~font_factory();
 
     /// Returns the default font_factory.
     static font_factory*  Default();
-    
+
     /// Constructs a pango string for use with the fontStringMap (see below)
     Glib::ustring         ConstructFontSpecification(PangoFontDescription *font);
     Glib::ustring         ConstructFontSpecification(font_instance *font);
-    
+
     /// Returns strings to be used in the UI for family and face (or "style" as the column is labeled)
     Glib::ustring         GetUIFamilyString(PangoFontDescription const *fontDescr);
     Glib::ustring         GetUIStyleString(PangoFontDescription const *fontDescr);
-    
+
     /// Modifiers for the font specification (returns new font specification)
     Glib::ustring         ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily);
     Glib::ustring         FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn);
     Glib::ustring         FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn);
-    
+
     // Gathers all strings needed for UI while storing pango information in
     // fontInstanceMap and fontStringMap
     void                  GetUIFamiliesAndStyles(FamilyToStylesMap *map);
-    
+
     /// Retrieve a font_instance from a style object, first trying to use the font-specification, the CSS information
     font_instance*        FaceFromStyle(SPStyle const *style);
 
@@ -129,17 +126,19 @@ public:
 
     // internal
     void                  AddInCache(font_instance *who);
-    
+
 private:
+    void*                 loadedPtr;
+
     // These two maps are used for translating between what's in the UI and a pango
     // font description.  This is necessary because Pango cannot always
     // reproduce these structures from the names it gave us in the first place.
-    
+
     // Key: A string produced by font_factory::ConstructFontSpecification
     // Value: The associated PangoFontDescription
     typedef std::map<Glib::ustring, PangoFontDescription *> PangoStringToDescrMap;
     PangoStringToDescrMap fontInstanceMap;
-    
+
     // Key: Family name in UI + Style name in UI
     // Value: The associated string that should be produced with font_factory::ConstructFontSpecification
     typedef std::map<Glib::ustring, Glib::ustring> UIStringToPangoStringMap;
index e1413b46e788a87f9f90832c551aeec169d4e614..f34a230c1f05ac09b2d984ed1cb0660431649b67 100644 (file)
 # include FT_TRUETYPE_TABLES_H
 # include <pango/pangoft2.h>
 
+#include <ext/hash_map>
+
+
+// the various raster_font in use at a given time are held in a hash_map whose indices are the
+// styles, hence the 2 following 'classes'
+struct font_style_hash : public std::unary_function<font_style, size_t> {
+    size_t operator()(font_style const &x) const;
+};
+
+struct font_style_equal : public std::binary_function<font_style, font_style, bool> {
+    bool operator()(font_style const &a, font_style const &b);
+};
+
+
+typedef __gnu_cxx::hash_map<font_style, raster_font*, font_style_hash, font_style_equal> StyleMap;
+
 
 
 size_t  font_style_hash::operator()(const font_style &x) const {
@@ -155,36 +171,61 @@ static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FR
  *
  */
 
-font_instance::font_instance(void)
+font_instance::font_instance(void) :
+    pFont(0),
+    descr(0),
+    refCount(0),
+    daddy(0),
+    nbGlyph(0),
+    maxGlyph(0),
+    glyphs(0),
+    loadedPtr(new StyleMap()),
+    theFace(0)
 {
-       //printf("font instance born\n");
-       descr=NULL;
-       pFont=NULL;
-       refCount=0;
-       daddy=NULL;
-       nbGlyph=maxGlyph=0;
-       glyphs=NULL;
-       theFace=NULL;
+    //printf("font instance born\n");
 }
 
 font_instance::~font_instance(void)
 {
-       if ( daddy ) daddy->UnrefFace(this);
-       //printf("font instance death\n");
-       if ( pFont ) g_object_unref(pFont);
-       pFont=NULL;
-       if ( descr ) pango_font_description_free(descr);
-       descr=NULL;
-       //      if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
-       theFace=NULL;
-
-       for (int i=0;i<nbGlyph;i++) {
-               if ( glyphs[i].outline ) delete glyphs[i].outline;
-        if ( glyphs[i].pathvector ) delete glyphs[i].pathvector;
-       }
-       if ( glyphs ) free(glyphs);
-       nbGlyph=maxGlyph=0;
-       glyphs=NULL;
+    if ( loadedPtr ) {
+        StyleMap* tmp = static_cast<StyleMap*>(loadedPtr);
+        delete tmp;
+        loadedPtr = 0;
+    }
+
+    if ( daddy ) {
+        daddy->UnrefFace(this);
+        daddy = 0;
+    }
+
+    //printf("font instance death\n");
+    if ( pFont ) {
+        g_object_unref(pFont);
+        pFont = 0;
+    }
+
+    if ( descr ) {
+        pango_font_description_free(descr);
+        descr = 0;
+    }
+
+    // if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
+    theFace = 0;
+
+    for (int i=0;i<nbGlyph;i++) {
+        if ( glyphs[i].outline ) {
+            delete glyphs[i].outline;
+        }
+        if ( glyphs[i].pathvector ) {
+            delete glyphs[i].pathvector;
+        }
+    }
+    if ( glyphs ) {
+        free(glyphs);
+        glyphs = 0;
+    }
+    nbGlyph = 0;
+    maxGlyph = 0;
 }
 
 void font_instance::Ref(void)
@@ -728,7 +769,8 @@ raster_font* font_instance::RasterFont(const font_style &inStyle)
                nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
                memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
        }
-       if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
+        StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
+        if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
                 raster_font *nR = new raster_font(nStyle);
                nR->Ref();
                nR->daddy=this;
@@ -746,15 +788,17 @@ raster_font* font_instance::RasterFont(const font_style &inStyle)
 
 void font_instance::RemoveRasterFont(raster_font* who)
 {
-       if ( who == NULL ) return;
-       if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
-               //g_print("RemoveRasterFont failed \n");
-               // not found
-       } else {
-               loadedStyles.erase(loadedStyles.find(who->style));
-               //g_print("RemoveRasterFont\n");
-               Unref();
-       }
+    if ( who ) {
+        StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
+        if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
+            //g_print("RemoveRasterFont failed \n");
+            // not found
+        } else {
+            loadedStyles.erase(loadedStyles.find(who->style));
+            //g_print("RemoveRasterFont\n");
+            Unref();
+        }
+    }
 }
 
 
index f4e8e4031f6cc84cc958e4324d474663dc136fd1..0682e3570d4fb3ae2f696eebe291419a7cd05ec8 100644 (file)
@@ -227,7 +227,11 @@ boost::optional<Geom::Point> Layout::baselineAnchorPoint() const
     Geom::Point left_pt = this->characterAnchorPoint(pos);
     pos.thisEndOfLine();
     Geom::Point right_pt = this->characterAnchorPoint(pos);
-    Geom::Point mid_pt = (left_pt + right_pt)/2;
+
+    if (this->_blockProgression() == LEFT_TO_RIGHT || this->_blockProgression() == RIGHT_TO_LEFT) {
+        left_pt = Geom::Point(left_pt[Geom::Y], left_pt[Geom::X]);
+        right_pt = Geom::Point(right_pt[Geom::Y], right_pt[Geom::X]);
+    }
 
     switch (this->paragraphAlignment(pos)) {
         case LEFT:
@@ -235,7 +239,7 @@ boost::optional<Geom::Point> Layout::baselineAnchorPoint() const
             return left_pt;
             break;
         case CENTER:
-            return mid_pt;
+            return (left_pt + right_pt)/2; // middle point
             break;
         case RIGHT:
             return right_pt;
index 4209a20af68c723c41daabd6867857cb0b62ee8b..521c9a42428db3f94884c7cee1352b4d095404de 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SEEN_LIBNRTYPE_FONT_INSTANCE_H
 #define SEEN_LIBNRTYPE_FONT_INSTANCE_H
 
-#include <ext/hash_map>
 #include <map>
 #include <pango/pango-types.h>
 #include <pango/pango-font.h>
 #include <2geom/d2.h>
 
 // the font_instance are the template of several raster_font; they provide metrics and outlines
-// that are drawn by the raster_font, so the raster_font needs info relative to the way the 
+// that are drawn by the raster_font, so the raster_font needs info relative to the way the
 // font need to be drawn. note that fontsize is a scale factor in the transform matrix
 // of the style
-// the various raster_font in use at a given time are held in a hash_map whose indices are the
-// styles, hence the 2 following 'classes'
-struct font_style_hash : public std::unary_function<font_style, size_t> {
-    size_t operator()(font_style const &x) const;
-};
-
-struct font_style_equal : public std::binary_function<font_style, font_style, bool> {
-    bool operator()(font_style const &a, font_style const &b);
-};
-
 class font_instance {
 public:
-       // hashmap to get the raster_font for a given style
-    __gnu_cxx::hash_map<font_style, raster_font*, font_style_hash, font_style_equal>     loadedStyles;
-       // the real source of the font
+    // the real source of the font
     PangoFont*            pFont;
-               // depending on the rendering backend, different temporary data
+    // depending on the rendering backend, different temporary data
 
-               // that's the font's fingerprint; this particular PangoFontDescription gives the entry at which this font_instance
-               // resides in the font_factory loadedFaces hash_map
+    // that's the font's fingerprint; this particular PangoFontDescription gives the entry at which this font_instance
+    // resides in the font_factory loadedFaces hash_map
     PangoFontDescription* descr;
-               // refcount
+    // refcount
     int                   refCount;
-               // font_factory owning this font_instance
+    // font_factory owning this font_instance
     font_factory*         daddy;
 
     // common glyph definitions for all the rasterfonts
@@ -58,38 +45,38 @@ public:
 
     bool                 IsOutlineFont(void); // utility
     void                 InstallFace(PangoFont* iFace); // utility; should reset the pFont field if loading failed
-                                       // in case the PangoFont is a bitmap font, for example. that way, the calling function 
-                                       // will be able to check the validity of the font before installing it in loadedFaces
+    // in case the PangoFont is a bitmap font, for example. that way, the calling function
+    // will be able to check the validity of the font before installing it in loadedFaces
     void                 InitTheFace();
 
     int                  MapUnicodeChar(gunichar c); // calls the relevant unicode->glyph index function
     void                 LoadGlyph(int glyph_id);    // the main backend-dependent function
-                                       // loads the given glyph's info
-               
-               // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply 
-               // by the fontsize to get the real sizes
+    // loads the given glyph's info
+
+    // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply
+    // by the fontsize to get the real sizes
     Path*                Outline(int glyph_id, Path *copyInto=NULL);
-                                       // queries the outline of the glyph (in livarot Path form), and copies it into copyInto instead
-                                       // of allocating a new Path if copyInto != NULL
+    // queries the outline of the glyph (in livarot Path form), and copies it into copyInto instead
+    // of allocating a new Path if copyInto != NULL
     Geom::PathVector*    PathVector(int glyph_id);
                          // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies
     double               Advance(int glyph_id, bool vertical);
-                                       // nominal advance of the font.
+    // nominal advance of the font.
     bool                 FontMetrics(double &ascent, double &descent, double &leading);
     bool                 FontSlope(double &run, double &rise);
                                 // for generating slanted cursors for oblique fonts
     Geom::OptRect             BBox(int glyph_id);
 
-               // creates a rasterfont for the given style
+    // creates a rasterfont for the given style
     raster_font*         RasterFont(Geom::Matrix const &trs, double stroke_width,
                                     bool vertical = false, JoinType stroke_join = join_straight,
                                     ButtType stroke_cap = butt_straight, float miter_limit = 4.0);
-               // the dashes array in iStyle is copied
+    // the dashes array in iStyle is copied
     raster_font*         RasterFont(font_style const &iStyle);
-               // private use: tells the font_instance that the raster_font 'who' has died
+    // private use: tells the font_instance that the raster_font 'who' has died
     void                 RemoveRasterFont(raster_font *who);
 
-               // attribute queries
+    // attribute queries
     unsigned             Name(gchar *str, unsigned size);
     unsigned             PSName(gchar *str, unsigned size);
     unsigned             Family(gchar *str, unsigned size);
@@ -98,10 +85,13 @@ public:
 private:
     void                 FreeTheFace();
 
+    // hashmap to get the raster_font for a given style
+    void*                loadedPtr; // Pointer to a hash_map. Moved into .cpp to not expose use of __gnu_cxx extension.
+
 #ifdef USE_PANGO_WIN32
     HFONT                 theFace;
 #else
-    FT_Face               theFace; 
+    FT_Face               theFace;
                 // it's a pointer in fact; no worries to ref/unref it, pango does its magic
                 // as long as pFont is valid, theFace is too
 #endif
index 5d5a772809d10163018394d3c8a7ea0b0028466f..31fa07515293bc77a2bdb2069eb2dc822e0d6292 100644 (file)
@@ -25,7 +25,7 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
                                                     Inkscape::SnapPreferences::PointType const &t,
                                                     Geom::Point const &p,
                                                     SnapSourceType const &source_type,
-                                                    bool const &/*f*/,
+                                                    long source_num,
                                                     Geom::OptRect const &/*bbox_to_snap*/,
                                                     std::vector<SPItem const *> const */*it*/,
                                                     std::vector<std::pair<Geom::Point, int> > */*unselected_nodes*/) const
@@ -49,13 +49,13 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
         Geom::Coord const dist = Geom::L2(p_proj - p);
         //Store any line that's within snapping range
         if (dist < getSnapperTolerance()) {
-            _addSnappedLine(sc, p_proj, dist, source_type, i->first, i->second);
+            _addSnappedLine(sc, p_proj, dist, source_type, source_num, i->first, i->second);
             // For any line that's within range, we will also look at it's "point on line" p1. For guides
             // this point coincides with its origin; for grids this is of no use, but we cannot
             // discern between grids and guides here
             Geom::Coord const dist_p1 = Geom::L2(p1 - p);
             if (dist_p1 < getSnapperTolerance()) {
-                _addSnappedLinesOrigin(sc, p1, dist_p1, source_type);
+                _addSnappedLinesOrigin(sc, p1, dist_p1, source_type, source_num);
                 // Only relevant for guides; grids don't have an origin per line
                 // Therefore _addSnappedLinesOrigin() will only be implemented for guides
             }
@@ -69,7 +69,7 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
                                                Inkscape::SnapPreferences::PointType const &t,
                                                Geom::Point const &p,
                                                SnapSourceType const &source_type,
-                                               bool const &/*f*/,
+                                               long source_num,
                                                Geom::OptRect const &/*bbox_to_snap*/,
                                                ConstraintLine const &c,
                                                std::vector<SPItem const *> const */*it*/) const
@@ -112,13 +112,13 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
                     // This snappoint is therefore fully constrained, so there's no need
                     // to look for additional intersections; just return the snapped point
                     // and forget about the line
-                    _addSnappedPoint(sc, t, dist, source_type);
+                    _addSnappedPoint(sc, t, dist, source_type, source_num);
                     // For any line that's within range, we will also look at it's "point on line" p1. For guides
                     // this point coincides with its origin; for grids this is of no use, but we cannot
                     // discern between grids and guides here
                     Geom::Coord const dist_p1 = Geom::L2(p1 - p);
                     if (dist_p1 < getSnapperTolerance()) {
-                        _addSnappedLinesOrigin(sc, p1, dist_p1, source_type);
+                        _addSnappedLinesOrigin(sc, p1, dist_p1, source_type, source_num);
                         // Only relevant for guides; grids don't have an origin per line
                         // Therefore _addSnappedLinesOrigin() will only be implemented for guides
                     }
@@ -130,7 +130,7 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
 
 // Will only be overridden in the guide-snapper class, because grid lines don't have an origin; the
 // grid-snapper classes will use this default empty method
-void Inkscape::LineSnapper::_addSnappedLinesOrigin(SnappedConstraints &/*sc*/, Geom::Point const /*origin*/, Geom::Coord const /*snapped_distance*/, SnapSourceType const &/*source_type*/) const
+void Inkscape::LineSnapper::_addSnappedLinesOrigin(SnappedConstraints &/*sc*/, Geom::Point const /*origin*/, Geom::Coord const /*snapped_distance*/, SnapSourceType const &/*source_type*/, long /*source_num*/) const
 {
 }
 
index 4ad08a99f95fe1f73ab8dbeb739569a32caadd23..af36b8330126cf5331e1b942122118b9f6008aa2 100644 (file)
@@ -28,7 +28,7 @@ public:
                    Inkscape::SnapPreferences::PointType const &t,
                    Geom::Point const &p,
                    SnapSourceType const &source_type,
-                   bool const &first_point,
+                   long source_num,
                    Geom::OptRect const &bbox_to_snap,
                    std::vector<SPItem const *> const *it,
                    std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const;
@@ -37,7 +37,7 @@ public:
                           Inkscape::SnapPreferences::PointType const &t,
                           Geom::Point const &p,
                           SnapSourceType const &source_type,
-                          bool const &first_point,
+                          long source_num,
                           Geom::OptRect const &bbox_to_snap,
                           ConstraintLine const &c,
                           std::vector<SPItem const *> const *it) const;
@@ -54,12 +54,12 @@ private:
    */
   virtual LineList _getSnapLines(Geom::Point const &p) const = 0;
 
-  virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
+  virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
 
   // Will only be implemented for guide lines, because grid lines don't have an origin
-  virtual void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
+  virtual void _addSnappedLinesOrigin(SnappedConstraints &sc, Geom::Point const origin, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const;
 
-  virtual void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const = 0;
+  virtual void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, long source_num) const = 0;
 };
 
 }
index 091a4d9ae2b90deee7799e0d840862ce45f42660..3d18318c5c53ff0bbe899e2a5cd3e40e0e312ec1 100644 (file)
@@ -58,7 +58,7 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) :
 
     Persp3D *persp = persp3d_document_first_persp(inkscape_active_document());
 
-    Proj::TransfMat3x4 pmat = persp->tmat;
+    Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat;
 
     pmat.copy_tmat(tmat);
 }
index 8f17ae0133122477bd60f9583553eed265fa15fb..1881dd72be73b6e2961041fd530782496f8470d7 100644 (file)
@@ -1367,7 +1367,7 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
          * must provide that information. */
 
         // Build a list of the unselected nodes to which the snapper should snap
-       std::vector<std::pair<Geom::Point, int> > unselected_nodes;
+        std::vector<std::pair<Geom::Point, int> > unselected_nodes;
         for (GList *spl = nodepath->subpaths; spl != NULL; spl = spl->next) {
             Inkscape::NodePath::SubPath *subpath = (Inkscape::NodePath::SubPath *) spl->data;
             for (GList *nl = subpath->nodes; nl != NULL; nl = nl->next) {
@@ -1388,39 +1388,39 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
         Inkscape::NodePath::Node *closest_node = NULL;
         Geom::Coord closest_dist = NR_HUGE;
 
-       if (closest_only) {
-               for (GList *l = nodepath->selected; l != NULL; l = l->next) {
-                       Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
-                       Geom::Coord dist = Geom::L2(nodepath->drag_origin_mouse - n->origin);
-                       if (dist < closest_dist) {
-                               closest_node = n;
-                               closest_dist = dist;
-                       }
-               }
+        if (closest_only) {
+            for (GList *l = nodepath->selected; l != NULL; l = l->next) {
+                Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
+                Geom::Coord dist = Geom::L2(nodepath->drag_origin_mouse - n->origin);
+                if (dist < closest_dist) {
+                    closest_node = n;
+                    closest_dist = dist;
+                }
+            }
         }
 
-       // Iterate through all selected nodes
-       m.setup(nodepath->desktop, false, nodepath->item, &unselected_nodes);
-       for (GList *l = nodepath->selected; l != NULL; l = l->next) {
+        // Iterate through all selected nodes
+        m.setup(nodepath->desktop, false, nodepath->item, &unselected_nodes);
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             if (!closest_only || n == closest_node) { //try to snap either all selected nodes or only the closest one
-                   Inkscape::SnappedPoint s;
-                   Inkscape::SnapSourceType source_type = (n->type == Inkscape::NodePath::NODE_SMOOTH ? Inkscape::SNAPSOURCE_NODE_SMOOTH : Inkscape::SNAPSOURCE_NODE_CUSP);
-                   if (constrained) {
-                       Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint;
-                       dedicated_constraint.setPoint(n->pos);
-                       s = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), source_type, dedicated_constraint, false);
-                   } else {
-                       s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), source_type);
-                   }
-
-                   if (s.getSnapped()) {
-                       s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin));
-                       if (!s.isOtherSnapBetter(best, true)) {
-                               best = s;
-                               best_pt = from_2geom(s.getPoint()) - n->pos;
-                       }
-                   }
+                Inkscape::SnappedPoint s;
+                Inkscape::SnapSourceType source_type = (n->type == Inkscape::NodePath::NODE_SMOOTH ? Inkscape::SNAPSOURCE_NODE_SMOOTH : Inkscape::SNAPSOURCE_NODE_CUSP);
+                if (constrained) {
+                    Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint;
+                    dedicated_constraint.setPoint(n->pos);
+                    s = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), source_type, dedicated_constraint, false);
+                } else {
+                    s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), source_type);
+                }
+
+                if (s.getSnapped()) {
+                    s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin));
+                    if (!s.isOtherSnapBetter(best, true)) {
+                        best = s;
+                        best_pt = from_2geom(s.getPoint()) - n->pos;
+                    }
+                }
             }
         }
 
@@ -3955,9 +3955,9 @@ static gboolean node_handle_request(SPKnot *knot, Geom::Point &p, guint state, g
     Inkscape::SnappedPoint s;
 
     if ((state & GDK_SHIFT_MASK) != 0) {
-       // We will not try to snap when the shift-key is pressed
-       // so remove the old snap indicator and don't wait for it to time-out
-       desktop->snapindicator->remove_snaptarget();
+        // We will not try to snap when the shift-key is pressed
+        // so remove the old snap indicator and don't wait for it to time-out
+        desktop->snapindicator->remove_snaptarget();
     }
 
     Inkscape::NodePath::Node *othernode = opposite->other;
index 22d438c1ebeca020be06482e057d9f85b387e248..88c2607822d16ddb0af335940992f9019902ab50 100644 (file)
@@ -67,9 +67,9 @@ Inkscape::ObjectSnapper::~ObjectSnapper()
  */
 Geom::Coord Inkscape::ObjectSnapper::getSnapperTolerance() const
 {
-       SPDesktop const *dt = _snapmanager->getDesktop();
-       double const zoom =  dt ? dt->current_zoom() : 1;
-       return _snapmanager->snapprefs.getObjectTolerance() / zoom;
+    SPDesktop const *dt = _snapmanager->getDesktop();
+    double const zoom =  dt ? dt->current_zoom() : 1;
+    return _snapmanager->snapprefs.getObjectTolerance() / zoom;
 }
 
 bool Inkscape::ObjectSnapper::getSnapperAlwaysSnap() const
@@ -81,7 +81,6 @@ bool Inkscape::ObjectSnapper::getSnapperAlwaysSnap() const
  *  Find all items within snapping range.
  *  \param parent Pointer to the document's root, or to a clipped path or mask object
  *  \param it List of items to ignore
- *  \param first_point If true then this point is the first one from a whole bunch of points
  *  \param bbox_to_snap Bounding box hulling the whole bunch of points, all from the same selection and having the same transformation
  *  \param DimensionToSnap Snap in X, Y, or both directions.
  */
@@ -173,7 +172,7 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
 
 
 void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType const &t,
-                                         bool const &first_point) const
+                                            bool const &first_point) const
 {
     // Now, let's first collect all points to snap to. If we have a whole bunch of points to snap,
     // e.g. when translating an item using the selector tool, then we will only do this for the
@@ -212,47 +211,47 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
             g_return_if_fail(root_item);
 
             //Collect all nodes so we can snap to them
-                       if (p_is_a_node || !(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_node) || p_is_a_guide) {
-                               // Note: there are two ways in which intersections are considered:
-                               // Method 1: Intersections are calculated for each shape individually, for both the
-                               //           snap source and snap target (see sp_shape_snappoints)
-                               // Method 2: Intersections are calculated for each curve or line that we've snapped to, i.e. only for
-                               //           the target (see the intersect() method in the SnappedCurve and SnappedLine classes)
-                               // Some differences:
-                               // - Method 1 doesn't find intersections within a set of multiple objects
-                               // - Method 2 only works for targets
-                               // When considering intersections as snap targets:
-                               // - Method 1 only works when snapping to nodes, whereas
-                               // - Method 2 only works when snapping to paths
-                               // - There will be performance differences too!
-                               // If both methods are being used simultaneously, then this might lead to duplicate targets!
-
-                               // Well, here we will be looking for snap TARGETS. Both methods can therefore be used.
-                               // When snapping to paths, we will get a collection of snapped lines and snapped curves. findBestSnap() will
-                               // go hunting for intersections (but only when asked to in the prefs of course). In that case we can just
-                               // temporarily block the intersections in sp_item_snappoints, we don't need duplicates. If we're not snapping to
-                               // paths though but only to item nodes then we should still look for the intersections in sp_item_snappoints()
-                               bool old_pref = _snapmanager->snapprefs.getSnapIntersectionCS();
-                               if (_snapmanager->snapprefs.getSnapToItemPath()) {
-                                       _snapmanager->snapprefs.setSnapIntersectionCS(false);
-                               }
-
-                               sp_item_snappoints(root_item, true, *_points_to_snap_to, &_snapmanager->snapprefs);
-
-                               if (_snapmanager->snapprefs.getSnapToItemPath()) {
-                                       _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
-                               }
-                       }
+            if (p_is_a_node || !(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_node) || p_is_a_guide) {
+                // Note: there are two ways in which intersections are considered:
+                // Method 1: Intersections are calculated for each shape individually, for both the
+                //           snap source and snap target (see sp_shape_snappoints)
+                // Method 2: Intersections are calculated for each curve or line that we've snapped to, i.e. only for
+                //           the target (see the intersect() method in the SnappedCurve and SnappedLine classes)
+                // Some differences:
+                // - Method 1 doesn't find intersections within a set of multiple objects
+                // - Method 2 only works for targets
+                // When considering intersections as snap targets:
+                // - Method 1 only works when snapping to nodes, whereas
+                // - Method 2 only works when snapping to paths
+                // - There will be performance differences too!
+                // If both methods are being used simultaneously, then this might lead to duplicate targets!
+
+                // Well, here we will be looking for snap TARGETS. Both methods can therefore be used.
+                // When snapping to paths, we will get a collection of snapped lines and snapped curves. findBestSnap() will
+                // go hunting for intersections (but only when asked to in the prefs of course). In that case we can just
+                // temporarily block the intersections in sp_item_snappoints, we don't need duplicates. If we're not snapping to
+                // paths though but only to item nodes then we should still look for the intersections in sp_item_snappoints()
+                bool old_pref = _snapmanager->snapprefs.getSnapIntersectionCS();
+                if (_snapmanager->snapprefs.getSnapToItemPath()) {
+                    _snapmanager->snapprefs.setSnapIntersectionCS(false);
+                }
+
+                sp_item_snappoints(root_item, true, *_points_to_snap_to, &_snapmanager->snapprefs);
+
+                if (_snapmanager->snapprefs.getSnapToItemPath()) {
+                    _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
+                }
+            }
 
             //Collect the bounding box's corners so we can snap to them
-                       if (p_is_a_bbox || !(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_bbox) || p_is_a_guide) {
-                               // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
-                               // of the item AND the bbox of the clipping path at the same time
-                               if (!(*i).clip_or_mask) {
-                                       Geom::OptRect b = sp_item_bbox_desktop(root_item, bbox_type);
-                                       getBBoxPoints(b, _points_to_snap_to, true, _snapmanager->snapprefs.getSnapToBBoxNode(), _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints(), _snapmanager->snapprefs.getSnapBBoxMidpoints());
-                               }
-                       }
+            if (p_is_a_bbox || !(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_bbox) || p_is_a_guide) {
+                // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
+                // of the item AND the bbox of the clipping path at the same time
+                if (!(*i).clip_or_mask) {
+                    Geom::OptRect b = sp_item_bbox_desktop(root_item, bbox_type);
+                    getBBoxPoints(b, _points_to_snap_to, true, _snapmanager->snapprefs.getSnapToBBoxNode(), _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints(), _snapmanager->snapprefs.getSnapBBoxMidpoints());
+                }
+            }
         }
     }
 }
@@ -261,12 +260,12 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
                                          Inkscape::SnapPreferences::PointType const &t,
                                          Geom::Point const &p,
                                          SnapSourceType const &source_type,
-                                         bool const &first_point,
+                                         long source_num,
                                          std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const
 {
     // Iterate through all nodes, find out which one is the closest to p, and snap to it!
 
-    _collectNodes(t, first_point);
+    _collectNodes(t, source_num == 0);
 
     if (unselected_nodes != NULL) {
         _points_to_snap_to->insert(_points_to_snap_to->end(), unselected_nodes->begin(), unselected_nodes->end());
@@ -278,7 +277,7 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
     for (std::vector<std::pair<Geom::Point, int> >::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
         Geom::Coord dist = Geom::L2((*k).first - p);
         if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
-            s = SnappedPoint((*k).first, source_type, static_cast<Inkscape::SnapTargetType>((*k).second), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+            s = SnappedPoint((*k).first, source_type, source_num, static_cast<Inkscape::SnapTargetType>((*k).second), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
             success = true;
         }
     }
@@ -298,10 +297,10 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
 
     // Although we won't snap to paths here (which would give us under constrained snaps) we can still snap to intersections of paths.
     if (_snapmanager->snapprefs.getSnapToItemPath() || _snapmanager->snapprefs.getSnapToBBoxPath() || _snapmanager->snapprefs.getSnapToPageBorder()) {
-       _collectPaths(t, true);
-       _snapPaths(sc, t, p, SNAPSOURCE_GUIDE, true, NULL, NULL);
-       // The paths themselves should be discarded in findBestSnap(), as we should only snap to their intersections
-       }
+        _collectPaths(t, true);
+        _snapPaths(sc, t, p, SNAPSOURCE_GUIDE, 0, NULL, NULL);
+        // The paths themselves should be discarded in findBestSnap(), as we should only snap to their intersections
+    }
 
     SnappedPoint s;
 
@@ -313,7 +312,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
         Geom::Coord dist = Geom::L2((*k).first - p_proj); // distance from node to the guide
         Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location
         if ((dist < tol && dist2 < tol) || getSnapperAlwaysSnap()) {
-            s = SnappedPoint((*k).first, SNAPSOURCE_GUIDE, static_cast<Inkscape::SnapTargetType>((*k).second), dist, tol, getSnapperAlwaysSnap(), true);
+            s = SnappedPoint((*k).first, SNAPSOURCE_GUIDE, 0, static_cast<Inkscape::SnapTargetType>((*k).second), dist, tol, getSnapperAlwaysSnap(), true);
             sc.points.push_back(s);
         }
     }
@@ -428,11 +427,11 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
                                      Inkscape::SnapPreferences::PointType const &t,
                                      Geom::Point const &p,
                                      SnapSourceType const &source_type,
-                                     bool const &first_point,
+                                     long source_num,
                                      std::vector<std::pair<Geom::Point, int> > *unselected_nodes,
                                      SPPath const *selected_path) const
 {
-    _collectPaths(t, first_point);
+    _collectPaths(t, source_num == 0);
     // Now we can finally do the real snapping, using the paths collected above
 
     g_assert(_snapmanager->getDesktop() != NULL);
@@ -440,7 +439,7 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
 
     bool const node_tool_active = _snapmanager->snapprefs.getSnapToItemPath() && selected_path != NULL;
 
-    if (first_point) {
+    if (source_num == 0) {
         /* findCandidates() is used for snapping to both paths and nodes. It ignores the path that is
          * currently being edited, because that path requires special care: when snapping to nodes
          * only the unselected nodes of that path should be considered, and these will be passed on separately.
@@ -503,7 +502,7 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
                 if (!being_edited || (c1 && c2)) {
                     Geom::Coord const dist = Geom::distance(sp_doc, p_doc);
                     if (dist < getSnapperTolerance()) {
-                        sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, source_type, it_p->second));
+                        sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, source_type, source_num, it_p->second));
                     }
                 }
             }
@@ -535,11 +534,11 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc,
                                      Inkscape::SnapPreferences::PointType const &t,
                                      Geom::Point const &p,
                                      SnapSourceType const source_type,
-                                     bool const &first_point,
+                                     long source_num,
                                      ConstraintLine const &c) const
 {
 
-    _collectPaths(t, first_point);
+    _collectPaths(t, source_num == 0);
 
     // Now we can finally do the real snapping, using the paths collected above
 
@@ -577,7 +576,7 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc,
                         // When it's within snapping range, then return it
                         // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1)
                         Geom::Coord dist = Geom::L2(_snapmanager->getDesktop()->dt2doc(p_proj_on_cl) - p_inters);
-                        SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), source_type, k->second, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+                        SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), source_type, source_num, k->second, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
                         sc.points.push_back(s);
                     }
                 }
@@ -591,7 +590,7 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
                                             Inkscape::SnapPreferences::PointType const &t,
                                             Geom::Point const &p,
                                             SnapSourceType const &source_type,
-                                            bool const &first_point,
+                                            long source_num,
                                             Geom::OptRect const &bbox_to_snap,
                                             std::vector<SPItem const *> const *it,
                                             std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const
@@ -601,17 +600,17 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
     }
 
     /* Get a list of all the SPItems that we will try to snap to */
-    if (first_point) {
+    if (source_num == 0) {
         Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
-        _findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
+        _findCandidates(sp_document_root(_snapmanager->getDocument()), it, source_num == 0, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
     }
 
     if (_snapmanager->snapprefs.getSnapToItemNode() || _snapmanager->snapprefs.getSnapSmoothNodes()
-       || _snapmanager->snapprefs.getSnapToBBoxNode() || _snapmanager->snapprefs.getSnapToPageBorder()
-               || _snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()
-               || _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()
-               || _snapmanager->snapprefs.getIncludeItemCenter()) {
-        _snapNodes(sc, t, p, source_type, first_point, unselected_nodes);
+        || _snapmanager->snapprefs.getSnapToBBoxNode() || _snapmanager->snapprefs.getSnapToPageBorder()
+        || _snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()
+        || _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()
+        || _snapmanager->snapprefs.getIncludeItemCenter()) {
+        _snapNodes(sc, t, p, source_type, source_num, unselected_nodes);
     }
 
     if (_snapmanager->snapprefs.getSnapToItemPath() || _snapmanager->snapprefs.getSnapToBBoxPath() || _snapmanager->snapprefs.getSnapToPageBorder()) {
@@ -625,13 +624,13 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
             SPPath *path = NULL;
             if (it != NULL) {
                 if (it->size() == 1 && SP_IS_PATH(*it->begin())) {
-                                       path = SP_PATH(*it->begin());
+                    path = SP_PATH(*it->begin());
                 } // else: *it->begin() might be a SPGroup, e.g. when editing a LPE of text that has been converted to a group of paths
                 // as reported in bug #356743. In that case we can just ignore it, i.e. not snap to this item
             }
-            _snapPaths(sc, t, p, source_type, first_point, unselected_nodes, path);
+            _snapPaths(sc, t, p, source_type, source_num, unselected_nodes, path);
         } else {
-            _snapPaths(sc, t, p, source_type, first_point, NULL, NULL);
+            _snapPaths(sc, t, p, source_type, source_num, NULL, NULL);
         }
     }
 }
@@ -640,7 +639,7 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
                                                   Inkscape::SnapPreferences::PointType const &t,
                                                   Geom::Point const &p,
                                                   SnapSourceType const &source_type,
-                                                  bool const &first_point,
+                                                  long source_num,
                                                   Geom::OptRect const &bbox_to_snap,
                                                   ConstraintLine const &c,
                                                   std::vector<SPItem const *> const *it) const
@@ -650,9 +649,9 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
     }
 
     /* Get a list of all the SPItems that we will try to snap to */
-    if (first_point) {
+    if (source_num == 0) {
         Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
-        _findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
+        _findCandidates(sp_document_root(_snapmanager->getDocument()), it, source_num == 0, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
     }
 
     // A constrained snap, is a snap in only one degree of freedom (specified by the constraint line).
@@ -665,7 +664,7 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
     // so we will more or less snap to them anyhow.
 
     if (_snapmanager->snapprefs.getSnapToItemPath() || _snapmanager->snapprefs.getSnapToBBoxPath() || _snapmanager->snapprefs.getSnapToPageBorder()) {
-        _snapPathsConstrained(sc, t, p, source_type, first_point, c);
+        _snapPathsConstrained(sc, t, p, source_type, 0, c);
     }
 }
 
@@ -723,13 +722,13 @@ void Inkscape::ObjectSnapper::guideConstrainedSnap(SnappedConstraints &sc,
 bool Inkscape::ObjectSnapper::ThisSnapperMightSnap() const
 {
     bool snap_to_something = _snapmanager->snapprefs.getSnapToItemPath()
-                                               || _snapmanager->snapprefs.getSnapToItemNode()
-                                               || _snapmanager->snapprefs.getSnapToBBoxPath()
-                                               || _snapmanager->snapprefs.getSnapToBBoxNode()
-                                               || _snapmanager->snapprefs.getSnapToPageBorder()
-                                               || _snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()
-                                               || _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()
-                                               || _snapmanager->snapprefs.getIncludeItemCenter();
+                        || _snapmanager->snapprefs.getSnapToItemNode()
+                        || _snapmanager->snapprefs.getSnapToBBoxPath()
+                        || _snapmanager->snapprefs.getSnapToBBoxNode()
+                        || _snapmanager->snapprefs.getSnapToPageBorder()
+                        || _snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()
+                        || _snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()
+                        || _snapmanager->snapprefs.getIncludeItemCenter();
 
     return (_snap_enabled && _snapmanager->snapprefs.getSnapModeBBoxOrNodes() && snap_to_something);
 }
@@ -737,12 +736,12 @@ bool Inkscape::ObjectSnapper::ThisSnapperMightSnap() const
 bool Inkscape::ObjectSnapper::GuidesMightSnap() const // almost the same as ThisSnapperMightSnap above, but only looking at points (and not paths)
 {
     bool snap_to_something = _snapmanager->snapprefs.getSnapToItemNode()
-                                               || _snapmanager->snapprefs.getSnapToPageBorder()
-                                               || (_snapmanager->snapprefs.getSnapModeBBox() && _snapmanager->snapprefs.getSnapToBBoxNode())
-                                               || (_snapmanager->snapprefs.getSnapModeBBox() && (_snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()))
-                                               || (_snapmanager->snapprefs.getSnapModeNode() && (_snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()))
-                                               || (_snapmanager->snapprefs.getSnapModeNode() && _snapmanager->snapprefs.getIncludeItemCenter())
-                                               || (_snapmanager->snapprefs.getSnapModeNode() && (_snapmanager->snapprefs.getSnapToItemPath() && _snapmanager->snapprefs.getSnapIntersectionCS()));
+                        || _snapmanager->snapprefs.getSnapToPageBorder()
+                        || (_snapmanager->snapprefs.getSnapModeBBox() && _snapmanager->snapprefs.getSnapToBBoxNode())
+                        || (_snapmanager->snapprefs.getSnapModeBBox() && (_snapmanager->snapprefs.getSnapBBoxEdgeMidpoints() || _snapmanager->snapprefs.getSnapBBoxMidpoints()))
+                        || (_snapmanager->snapprefs.getSnapModeNode() && (_snapmanager->snapprefs.getSnapLineMidpoints() || _snapmanager->snapprefs.getSnapObjectMidpoints()))
+                        || (_snapmanager->snapprefs.getSnapModeNode() && _snapmanager->snapprefs.getIncludeItemCenter())
+                        || (_snapmanager->snapprefs.getSnapModeNode() && (_snapmanager->snapprefs.getSnapToItemPath() && _snapmanager->snapprefs.getSnapIntersectionCS()));
 
     return (_snap_enabled && _snapmanager->snapprefs.getSnapModeGuide() && snap_to_something);
 }
@@ -784,21 +783,21 @@ void Inkscape::ObjectSnapper::_getBorderNodes(std::vector<std::pair<Geom::Point,
 
 void Inkscape::getBBoxPoints(Geom::OptRect const bbox, std::vector<std::pair<Geom::Point, int> > *points, bool const isTarget, bool const includeCorners, bool const includeLineMidpoints, bool const includeObjectMidpoints)
 {
-       if (bbox) {
-               // collect the corners of the bounding box
-               for ( unsigned k = 0 ; k < 4 ; k++ ) {
-                       if (includeCorners) {
-                               points->push_back(std::make_pair((bbox->corner(k)), isTarget ? int(Inkscape::SNAPTARGET_BBOX_CORNER) : int(Inkscape::SNAPSOURCE_BBOX_CORNER)));
-                       }
-                       // optionally, collect the midpoints of the bounding box's edges too
-                       if (includeLineMidpoints) {
-                               points->push_back(std::make_pair((bbox->corner(k) + bbox->corner((k+1) % 4))/2, isTarget ? int(Inkscape::SNAPTARGET_BBOX_EDGE_MIDPOINT) : int(Inkscape::SNAPSOURCE_BBOX_EDGE_MIDPOINT)));
-                       }
-               }
-               if (includeObjectMidpoints) {
-                       points->push_back(std::make_pair(bbox->midpoint(), isTarget ? int(Inkscape::SNAPTARGET_BBOX_MIDPOINT) : int(Inkscape::SNAPSOURCE_BBOX_MIDPOINT)));
-               }
-       }
+    if (bbox) {
+        // collect the corners of the bounding box
+        for ( unsigned k = 0 ; k < 4 ; k++ ) {
+            if (includeCorners) {
+                points->push_back(std::make_pair((bbox->corner(k)), isTarget ? int(Inkscape::SNAPTARGET_BBOX_CORNER) : int(Inkscape::SNAPSOURCE_BBOX_CORNER)));
+            }
+            // optionally, collect the midpoints of the bounding box's edges too
+            if (includeLineMidpoints) {
+                points->push_back(std::make_pair((bbox->corner(k) + bbox->corner((k+1) % 4))/2, isTarget ? int(Inkscape::SNAPTARGET_BBOX_EDGE_MIDPOINT) : int(Inkscape::SNAPSOURCE_BBOX_EDGE_MIDPOINT)));
+            }
+        }
+        if (includeObjectMidpoints) {
+            points->push_back(std::make_pair(bbox->midpoint(), isTarget ? int(Inkscape::SNAPTARGET_BBOX_MIDPOINT) : int(Inkscape::SNAPSOURCE_BBOX_MIDPOINT)));
+        }
+    }
 }
 
 /*
index baa60a096fdc392049dfb48664aad4bb3563c8cb..2fcafb79a106b03112ff6864b8ea72a9fd1f3e06 100644 (file)
@@ -46,47 +46,47 @@ class ObjectSnapper : public Snapper
 {
 
 public:
-       ObjectSnapper(SnapManager *sm, Geom::Coord const d);
+    ObjectSnapper(SnapManager *sm, Geom::Coord const d);
     ~ObjectSnapper();
 
-       enum DimensionToSnap {
-               GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects,
-               GUIDE_TRANSL_SNAP_Y, // For snapping a horizontal guide (normal in the Y-direction) to objects
-               ANGLED_GUIDE_TRANSL_SNAP, // For snapping an angled guide, while translating it accross the desktop
-               TRANSL_SNAP_XY}; // All other cases; for snapping to objects, other than guides
-
-       void guideFreeSnap(SnappedConstraints &sc,
-                                  Geom::Point const &p,
-                                  Geom::Point const &guide_normal) const;
-
-       void guideConstrainedSnap(SnappedConstraints &sc,
-                                          Geom::Point const &p,
-                                          Geom::Point const &guide_normal,
-                                          ConstraintLine const &c) const;
-
-       bool ThisSnapperMightSnap() const;
-       bool GuidesMightSnap() const;
-
-       Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
-       bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
-
-       void freeSnap(SnappedConstraints &sc,
-                                 Inkscape::SnapPreferences::PointType const &t,
-                                 Geom::Point const &p,
-                                 SnapSourceType const &source_type,
-                                 bool const &first_point,
-                                 Geom::OptRect const &bbox_to_snap,
-                                 std::vector<SPItem const *> const *it,
-                                 std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const;
-
-       void constrainedSnap(SnappedConstraints &sc,
-                                 Inkscape::SnapPreferences::PointType const &t,
-                                 Geom::Point const &p,
-                                 SnapSourceType const &source_type,
-                                 bool const &first_point,
-                                 Geom::OptRect const &bbox_to_snap,
-                                 ConstraintLine const &c,
-                                 std::vector<SPItem const *> const *it) const;
+    enum DimensionToSnap {
+        GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects,
+        GUIDE_TRANSL_SNAP_Y, // For snapping a horizontal guide (normal in the Y-direction) to objects
+        ANGLED_GUIDE_TRANSL_SNAP, // For snapping an angled guide, while translating it accross the desktop
+        TRANSL_SNAP_XY}; // All other cases; for snapping to objects, other than guides
+
+    void guideFreeSnap(SnappedConstraints &sc,
+                   Geom::Point const &p,
+                   Geom::Point const &guide_normal) const;
+
+    void guideConstrainedSnap(SnappedConstraints &sc,
+                       Geom::Point const &p,
+                       Geom::Point const &guide_normal,
+                       ConstraintLine const &c) const;
+
+    bool ThisSnapperMightSnap() const;
+    bool GuidesMightSnap() const;
+
+    Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
+    bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
+
+    void freeSnap(SnappedConstraints &sc,
+                  Inkscape::SnapPreferences::PointType const &t,
+                  Geom::Point const &p,
+                  SnapSourceType const &source_type,
+                  long source_num,
+                  Geom::OptRect const &bbox_to_snap,
+                  std::vector<SPItem const *> const *it,
+                  std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const;
+
+    void constrainedSnap(SnappedConstraints &sc,
+                  Inkscape::SnapPreferences::PointType const &t,
+                  Geom::Point const &p,
+                  SnapSourceType const &source_type,
+                  long source_num,
+                  Geom::OptRect const &bbox_to_snap,
+                  ConstraintLine const &c,
+                  std::vector<SPItem const *> const *it) const;
 
 private:
     //store some lists of candidates, points and paths, so we don't have to rebuild them for each point we want to snap
@@ -106,7 +106,7 @@ private:
                       Inkscape::SnapPreferences::PointType const &t,
                       Geom::Point const &p, // in desktop coordinates
                       SnapSourceType const &source_type,
-                      bool const &first_point,
+                      long source_num,
                       std::vector<std::pair<Geom::Point, int> > *unselected_nodes) const; // in desktop coordinates
 
     void _snapTranslatingGuideToNodes(SnappedConstraints &sc,
@@ -119,9 +119,9 @@ private:
 
     void _snapPaths(SnappedConstraints &sc,
                       Inkscape::SnapPreferences::PointType const &t,
-                      Geom::Point const &p,    // in desktop coordinates
+                      Geom::Point const &p,    // in desktop coordinates
                       SnapSourceType const &source_type,
-                      bool const &first_point,
+                      long source_num,
                       std::vector<std::pair<Geom::Point, int> > *unselected_nodes, // in desktop coordinates
                       SPPath const *selected_path) const;
 
@@ -129,7 +129,7 @@ private:
                  Inkscape::SnapPreferences::PointType const &t,
                  Geom::Point const &p, // in desktop coordinates
                  SnapSourceType const source_type,
-                                bool const &first_point,
+                 long source_num,
                  ConstraintLine const &c) const;
 
     bool isUnselectedNode(Geom::Point const &point, std::vector<std::pair<Geom::Point, int> > const *unselected_nodes) const;
index 99ee78ade932963fbb01cabfca7e7f0411965935..204c82aedff4e74dab93fc955043e72296eb0dcc 100644 (file)
@@ -86,12 +86,20 @@ sp_selected_path_combine(SPDesktop *desktop)
     SPItem *first = NULL;
     Inkscape::XML::Node *parent = NULL; 
 
+    if (did) {
+        selection->clear();
+    }
+
     for (GSList *i = items; i != NULL; i = i->next) {  // going from top to bottom
 
         SPItem *item = (SPItem *) i->data;
         if (!SP_IS_PATH(item))
             continue;
-        did = true;
+
+        if (!did) {
+            selection->clear();
+            did = true;
+        }
 
         SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(item));
         if (first == NULL) {  // this is the topmost path
@@ -124,11 +132,7 @@ sp_selected_path_combine(SPDesktop *desktop)
     g_slist_free(items);
 
     if (did) {
-        selection->clear();
-
-        // delete the topmost one so that its clones don't get alerted; this object will be
-        // restored shortly, with the same id
-        SP_OBJECT(first)->deleteObject(false);
+        // delete the topmost.
 
         Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
         Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
index 43b0e82b1f5431899b2c55b6f8b6f5190f6e2c62..7c2ce31bf6136bf5996d2603239e41eaa3d31e2e 100644 (file)
@@ -12,9 +12,9 @@
 
 #include "uri-references.h"
 #include <sigc++/sigc++.h>
+#include "persp3d.h"
 
 class SPObject;
-class Persp3D;
 
 namespace Inkscape {
 namespace XML {
@@ -28,7 +28,7 @@ public:
     ~Persp3DReference();
 
     Persp3D *getObject() const {
-        return (Persp3D *)URIReference::getObject();
+        return SP_PERSP3D(URIReference::getObject());
     }
 
     SPObject *owner;
index 916e9f25f421fe071452b070e4088abfb2cf9bdf..6a697ec9b5e1d9893ed76b787144abc608c8bb50 100644 (file)
@@ -24,7 +24,7 @@
 #include <glibmm/i18n.h>
 
 static void persp3d_class_init(Persp3DClass *klass);
-static void persp3d_init(Persp3D *stop);
+static void persp3d_init(Persp3D *persp);
 
 static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 static void persp3d_release(SPObject *object);
@@ -34,10 +34,22 @@ static Inkscape::XML::Node *persp3d_write(SPObject *object, Inkscape::XML::Docum
 
 static void persp3d_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
 
+static void persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image);
+static gchar * persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis);
+
 static SPObjectClass *persp3d_parent_class;
 
 static int global_counter = 0;
 
+/* Constructor/destructor for the internal class */
+
+Persp3DImpl::Persp3DImpl() {
+    tmat = Proj::TransfMat3x4 ();
+    document = NULL;
+
+    my_counter = global_counter++;
+}
+
 /**
  * Registers Persp3d class and returns its type.
  */
@@ -91,13 +103,7 @@ static void persp3d_class_init(Persp3DClass *klass)
 static void
 persp3d_init(Persp3D *persp)
 {
-    persp->tmat = Proj::TransfMat3x4 ();
-
-    persp->boxes_transformed = new std::map<SPBox3D *, bool>;
-    persp->boxes_transformed->clear();
-    persp->document = NULL;
-
-    persp->my_counter = global_counter++;
+    persp->perspective_impl = new Persp3DImpl();
 }
 
 /**
@@ -124,8 +130,8 @@ static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML:
  * Virtual release of Persp3D members before destruction.
  */
 static void persp3d_release(SPObject *object) {
-    Persp3D *persp = SP_PERSP3D (object);
-    delete persp->boxes_transformed;
+    Persp3D *persp = SP_PERSP3D(object);
+    delete persp->perspective_impl;
     SP_OBJECT_REPR(object)->removeListenerByData(object);
 }
 
@@ -138,34 +144,34 @@ static void persp3d_release(SPObject *object) {
 static void
 persp3d_set(SPObject *object, unsigned key, gchar const *value)
 {
-    Persp3D *persp = SP_PERSP3D (object);
+    Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl;
 
     switch (key) {
         case SP_ATTR_INKSCAPE_PERSP3D_VP_X: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::X, new_image);
+                persp3d_update_with_point (persp_impl, Proj::X, new_image);
             }
             break;
         }
         case SP_ATTR_INKSCAPE_PERSP3D_VP_Y: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::Y, new_image);
+                persp3d_update_with_point (persp_impl, Proj::Y, new_image);
                 break;
             }
         }
         case SP_ATTR_INKSCAPE_PERSP3D_VP_Z: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::Z, new_image);
+                persp3d_update_with_point (persp_impl, Proj::Z, new_image);
                 break;
             }
         }
         case SP_ATTR_INKSCAPE_PERSP3D_ORIGIN: {
             if (value) {
                 Proj::Pt2 new_image (value);
-                persp3d_update_with_point (persp, Proj::W, new_image);
+                persp3d_update_with_point (persp_impl, Proj::W, new_image);
                 break;
             }
         }
@@ -201,36 +207,40 @@ persp3d_update(SPObject *object, SPCtx *ctx, guint flags)
 }
 
 Persp3D *
-persp3d_create_xml_element (SPDocument *document, Persp3D *dup) {// if dup is given, copy the attributes over
+persp3d_create_xml_element (SPDocument *document, Persp3DImpl *dup) {// if dup is given, copy the attributes over
     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
     Inkscape::XML::Node *repr;
-    if (dup) {
-        repr = SP_OBJECT_REPR(dup)->duplicate (xml_doc);
-    } else {
-        /* if no perspective is given, create a default one */
-        repr = xml_doc->createElement("inkscape:perspective");
-        repr->setAttribute("sodipodi:type", "inkscape:persp3d");
 
-        Proj::Pt2 proj_vp_x = Proj::Pt2 (0.0, sp_document_height(document)/2, 1.0);
-        Proj::Pt2 proj_vp_y = Proj::Pt2 (  0.0,1000.0, 0.0);
-        Proj::Pt2 proj_vp_z = Proj::Pt2 (sp_document_width(document), sp_document_height(document)/2, 1.0);
-        Proj::Pt2 proj_origin = Proj::Pt2 (sp_document_width(document)/2, sp_document_height(document)/3, 1.0);
+    /* if no perspective is given, create a default one */
+    repr = xml_doc->createElement("inkscape:perspective");
+    repr->setAttribute("sodipodi:type", "inkscape:persp3d");
 
-        gchar *str = NULL;
-        str = proj_vp_x.coord_string();
-        repr->setAttribute("inkscape:vp_x", str);
-        g_free (str);
-        str = proj_vp_y.coord_string();
-        repr->setAttribute("inkscape:vp_y", str);
-        g_free (str);
-        str = proj_vp_z.coord_string();
-        repr->setAttribute("inkscape:vp_z", str);
-        g_free (str);
-        str = proj_origin.coord_string();
-        repr->setAttribute("inkscape:persp3d-origin", str);
-        g_free (str);
-    }
+    Proj::Pt2 proj_vp_x = Proj::Pt2 (0.0, sp_document_height(document)/2, 1.0);
+    Proj::Pt2 proj_vp_y = Proj::Pt2 (0.0, 1000.0, 0.0);
+    Proj::Pt2 proj_vp_z = Proj::Pt2 (sp_document_width(document), sp_document_height(document)/2, 1.0);
+    Proj::Pt2 proj_origin = Proj::Pt2 (sp_document_width(document)/2, sp_document_height(document)/3, 1.0);
+
+    if (dup) {
+        proj_vp_x = dup->tmat.column (Proj::X);
+        proj_vp_y = dup->tmat.column (Proj::Y);
+        proj_vp_z = dup->tmat.column (Proj::Z);
+        proj_origin = dup->tmat.column (Proj::W);
+    }
+
+    gchar *str = NULL;
+    str = proj_vp_x.coord_string();
+    repr->setAttribute("inkscape:vp_x", str);
+    g_free (str);
+    str = proj_vp_y.coord_string();
+    repr->setAttribute("inkscape:vp_y", str);
+    g_free (str);
+    str = proj_vp_z.coord_string();
+    repr->setAttribute("inkscape:vp_z", str);
+    g_free (str);
+    str = proj_origin.coord_string();
+    repr->setAttribute("inkscape:persp3d-origin", str);
+    g_free (str);
 
     /* Append the new persp3d to defs */
     SP_OBJECT_REPR(defs)->addChild(repr, NULL);
@@ -258,7 +268,7 @@ persp3d_document_first_persp (SPDocument *document) {
 static Inkscape::XML::Node *
 persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
-    Persp3D *persp = SP_PERSP3D(object);
+    Persp3DImpl *persp_impl = SP_PERSP3D(object)->perspective_impl;
 
     if ((flags & SP_OBJECT_WRITE_BUILD & SP_OBJECT_WRITE_EXT) && !repr) {
         // this is where we end up when saving as plain SVG (also in other circumstances?);
@@ -268,16 +278,16 @@ persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML:
 
     if (flags & SP_OBJECT_WRITE_EXT) {
         gchar *str = NULL; // FIXME: Should this be freed each time we set an attribute or only in the end or at all?
-        str = persp3d_pt_to_str (persp, Proj::X);
+        str = persp3d_pt_to_str (persp_impl, Proj::X);
         repr->setAttribute("inkscape:vp_x", str);
 
-        str = persp3d_pt_to_str (persp, Proj::Y);
+        str = persp3d_pt_to_str (persp_impl, Proj::Y);
         repr->setAttribute("inkscape:vp_y", str);
 
-        str = persp3d_pt_to_str (persp, Proj::Z);
+        str = persp3d_pt_to_str (persp_impl, Proj::Z);
         repr->setAttribute("inkscape:vp_z", str);
 
-        str = persp3d_pt_to_str (persp, Proj::W);
+        str = persp3d_pt_to_str (persp_impl, Proj::W);
         repr->setAttribute("inkscape:persp3d-origin", str);
     }
 
@@ -289,7 +299,7 @@ persp3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML:
 
 /* convenience wrapper around persp3d_get_finite_dir() and persp3d_get_infinite_dir() */
 Geom::Point persp3d_get_PL_dir_from_pt (Persp3D *persp, Geom::Point const &pt, Proj::Axis axis) {
-    if (persp3d_VP_is_finite(persp, axis)) {
+    if (persp3d_VP_is_finite(persp->perspective_impl, axis)) {
         return persp3d_get_finite_dir(persp, pt, axis);
     } else {
         return persp3d_get_infinite_dir(persp, axis);
@@ -314,17 +324,17 @@ persp3d_get_infinite_dir (Persp3D *persp, Proj::Axis axis) {
 
 double
 persp3d_get_infinite_angle (Persp3D *persp, Proj::Axis axis) {
-    return persp->tmat.get_infinite_angle(axis);
+    return persp->perspective_impl->tmat.get_infinite_angle(axis);
 }
 
 bool
-persp3d_VP_is_finite (Persp3D *persp, Proj::Axis axis) {
-    return persp->tmat.has_finite_image(axis);
+persp3d_VP_is_finite (Persp3DImpl *persp_impl, Proj::Axis axis) {
+    return persp_impl->tmat.has_finite_image(axis);
 }
 
 void
 persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo) {
-    persp->tmat.toggle_finite(axis);
+    persp->perspective_impl->tmat.toggle_finite(axis);
     // FIXME: Remove this repr update and rely on vp_drag_sel_modified() to do this for us
     //        On the other hand, vp_drag_sel_modified() would update all boxes;
     //        here we can confine ourselves to the boxes of this particular perspective.
@@ -348,7 +358,7 @@ persp3d_toggle_VPs (std::list<Persp3D *> p, Proj::Axis axis) {
 
 void
 persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state) {
-    if (persp3d_VP_is_finite(persp, axis) != (state == Proj::VP_FINITE)) {
+    if (persp3d_VP_is_finite(persp->perspective_impl, axis) != (state == Proj::VP_FINITE)) {
         persp3d_toggle_VP(persp, axis);
     }
 }
@@ -356,62 +366,67 @@ persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state) {
 void
 persp3d_rotate_VP (Persp3D *persp, Proj::Axis axis, double angle, bool alt_pressed) { // angle is in degrees
     // FIXME: Most of this functionality should be moved to trans_mat_3x4.(h|cpp)
-    if (persp->tmat.has_finite_image(axis)) {
+    if (persp->perspective_impl->tmat.has_finite_image(axis)) {
         // don't rotate anything for finite VPs
         return;
     }
-    Proj::Pt2 v_dir_proj (persp->tmat.column(axis));
+    Proj::Pt2 v_dir_proj (persp->perspective_impl->tmat.column(axis));
     Geom::Point v_dir (v_dir_proj[0], v_dir_proj[1]);
     double a = Geom::atan2 (v_dir) * 180/M_PI;
     a += alt_pressed ? 0.5 * ((angle > 0 ) - (angle < 0)) : angle; // the r.h.s. yields +/-0.5 or angle
-    persp->tmat.set_infinite_direction (axis, a);
+    persp->perspective_impl->tmat.set_infinite_direction (axis, a);
 
     persp3d_update_box_reprs (persp);
     SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT);
 }
 
 void
-persp3d_update_with_point (Persp3D *persp, Proj::Axis const axis, Proj::Pt2 const &new_image) {
-    persp->tmat.set_image_pt (axis, new_image);
+persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image) {
+    persp_impl->tmat.set_image_pt (axis, new_image);
 }
 
 void
 persp3d_apply_affine_transformation (Persp3D *persp, Geom::Matrix const &xform) {
-    persp->tmat *= xform;
+    persp->perspective_impl->tmat *= xform;
     persp3d_update_box_reprs(persp);
     SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT);
 }
 
 gchar *
-persp3d_pt_to_str (Persp3D *persp, Proj::Axis const axis)
+persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis)
 {
-    return persp->tmat.pt_to_str(axis);
+    return persp_impl->tmat.pt_to_str(axis);
 }
 
 void
 persp3d_add_box (Persp3D *persp, SPBox3D *box) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     if (!box) {
         return;
     }
-    if (std::find (persp->boxes.begin(), persp->boxes.end(), box) != persp->boxes.end()) {
+    if (std::find (persp_impl->boxes.begin(), persp_impl->boxes.end(), box) != persp_impl->boxes.end()) {
         return;
     }
-    persp->boxes.push_back(box);
+    persp_impl->boxes.push_back(box);
 }
 
 void
 persp3d_remove_box (Persp3D *persp, SPBox3D *box) {
-    std::vector<SPBox3D *>::iterator i = std::find (persp->boxes.begin(), persp->boxes.end(), box);
-    if (i != persp->boxes.end()) {
-        persp->boxes.erase(i);
-    }
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    std::vector<SPBox3D *>::iterator i = std::find (persp_impl->boxes.begin(), persp_impl->boxes.end(), box);
+    if (i != persp_impl->boxes.end())
+        persp_impl->boxes.erase(i);
 }
 
 bool
 persp3d_has_box (Persp3D *persp, SPBox3D *box) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     // FIXME: For some reason, std::find() does not seem to compare pointers "correctly" (or do we need to
     //        provide a proper comparison function?), so we manually traverse the list.
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         if ((*i) == box) {
             return true;
         }
@@ -420,86 +435,27 @@ persp3d_has_box (Persp3D *persp, SPBox3D *box) {
 }
 
 void
-persp3d_add_box_transform (Persp3D *persp, SPBox3D *box) {
-    std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed->find(box);
-    if (i != persp->boxes_transformed->end() && (*i).second == true) {
-        g_print ("Warning! In %s (%d): trying to add transform status for box %d twice when it's already listed as true.\n", SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter, box->my_counter);
-        return;
-    }
-    (*persp->boxes_transformed)[box] = false;
-}
-
-void
-persp3d_remove_box_transform (Persp3D *persp, SPBox3D *box) {
-    persp->boxes_transformed->erase(box);
-}
+persp3d_update_box_displays (Persp3D *persp) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
 
-void
-persp3d_set_box_transformed (Persp3D *persp, SPBox3D *box, bool transformed) {
-    if (persp->boxes_transformed->find(box) == persp->boxes_transformed->end()) {
-        g_print ("Warning! In %s (%d): trying to set transform status for box %d, but it is not listed in the perspective!! Aborting.\n",
-                 SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter,
-                 box->my_counter);
+    if (persp_impl->boxes.empty())
         return;
-    }
-
-    (*persp->boxes_transformed)[box] = transformed;
-}
-
-bool
-persp3d_was_transformed (Persp3D *persp) {
-    if (persp->boxes_transformed->size() == 1) {
-        /* either the transform has not been applied to the single box associated to this perspective yet
-           or the transform was already reset; in both cases we need to return false because upcoming
-           transforms need to be applied */
-        (*persp->boxes_transformed->begin()).second = false; // make sure the box is marked as untransformed (in case more boxes are added later)
-        return false;
-    }
-
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed->begin();
-         i != persp->boxes_transformed->end(); ++i) {
-        if ((*i).second == true) {
-            // at least one of the boxes in the perspective has already been transformed;
-            return true;
-        }
-    }
-    return false; // all boxes in the perspective are still untransformed; a pending transformation should be applied
-}
-
-bool
-persp3d_all_transformed(Persp3D *persp) {
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed->begin();
-         i != persp->boxes_transformed->end(); ++i) {
-        if ((*i).second == false) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void
-persp3d_unset_transforms(Persp3D *persp) {
-    for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed->begin();
-         i != persp->boxes_transformed->end(); ++i) {
-        (*i).second = false;
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
+        box3d_position_set(*i);
     }
 }
 
 void
-persp3d_update_box_displays (Persp3D *persp) {
-    if (persp->boxes.empty())
+persp3d_update_box_reprs (Persp3D *persp) {
+    if (!persp) {
+        // Hmm, is it an error if this happens?
         return;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
-        box3d_position_set(*i);
     }
-}
+    Persp3DImpl *persp_impl = persp->perspective_impl;
 
-void
-persp3d_update_box_reprs (Persp3D *persp) {
-    if (persp->boxes.empty())
+    if (persp_impl->boxes.empty())
         return;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         SP_OBJECT(*i)->updateRepr(SP_OBJECT_WRITE_EXT);
         box3d_set_z_orders(*i);
     }
@@ -507,9 +463,11 @@ persp3d_update_box_reprs (Persp3D *persp) {
 
 void
 persp3d_update_z_orders (Persp3D *persp) {
-    if (persp->boxes.empty())
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    if (persp_impl->boxes.empty())
         return;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         box3d_set_z_orders(*i);
     }
 }
@@ -519,8 +477,10 @@ persp3d_update_z_orders (Persp3D *persp) {
 //        obsolete. We should do this.
 std::list<SPBox3D *>
 persp3d_list_of_boxes(Persp3D *persp) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
     std::list<SPBox3D *> bx_lst;
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         bx_lst.push_back(*i);
     }
     return bx_lst;
@@ -529,7 +489,7 @@ persp3d_list_of_boxes(Persp3D *persp) {
 bool
 persp3d_perspectives_coincide(const Persp3D *lhs, const Persp3D *rhs)
 {
-    return lhs->tmat == rhs->tmat;
+    return lhs->perspective_impl->tmat == rhs->perspective_impl->tmat;
 }
 
 void
@@ -566,10 +526,12 @@ persp3d_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/,
 
 /* checks whether all boxes linked to this perspective are currently selected */
 bool
-persp3d_has_all_boxes_in_selection (Persp3D *persp) {
-    std::list<SPBox3D *> selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList();
+persp3d_has_all_boxes_in_selection (Persp3D *persp, Inkscape::Selection *selection) {
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+
+    std::list<SPBox3D *> selboxes = selection->box3DList();
 
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
         if (std::find(selboxes.begin(), selboxes.end(), *i) == selboxes.end()) {
             // we have an unselected box in the perspective
             return false;
@@ -578,62 +540,12 @@ persp3d_has_all_boxes_in_selection (Persp3D *persp) {
     return true;
 }
 
-/**
- * For each perspective having a box in \a selection, determine all its unselected boxes.
- */
-// TODO: Check where we can use pass-by-reference (or so) instead of recreating all the lists afresh.
-std::map<Persp3D *, std::list<SPBox3D *> >
-persp3d_unselected_boxes(Inkscape::Selection *selection) {
-    std::list<Persp3D *> plist = selection->perspList();
-    std::map<Persp3D *, std::list<SPBox3D *> > punsel;
-
-    std::list<Persp3D *>::iterator i;
-    std::vector<SPBox3D *>::iterator j;
-    // for all perspectives in the list ...
-    for (i = plist.begin(); i != plist.end(); ++i) {
-        Persp3D *persp = *i;
-        // ... and each box associated to it ...
-        for (j = persp->boxes.begin(); j != persp->boxes.end(); ++j) {
-            SPBox3D *box = *j;
-            // ... check whether it is unselected, and if so add it to the list
-            if (persp->boxes_transformed->find(box) == persp->boxes_transformed->end()) {
-                punsel[persp].push_back(box);
-            }
-        }
-    }
-    return punsel;
-}
-
-/**
- * Split all perspectives with a box in \a selection by moving their unselected boxes to newly
- * created perspectives.
- */
-void
-persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection) {
-    std::map<Persp3D *, std::list<SPBox3D *> > punsel = persp3d_unselected_boxes(selection);
-
-    std::map<Persp3D *, std::list<SPBox3D *> >::iterator i;
-    std::list<SPBox3D *>::iterator j;
-    // for all perspectives in the list ...
-    for (i = punsel.begin(); i != punsel.end(); ++i) {
-        Persp3D *persp = (*i).first;
-        // ... if the perspective has unselected boxes ...
-        if (!(*i).second.empty()) {
-            // create a new perspective and move these boxes over
-            Persp3D * new_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp);
-            for (j = (*i).second.begin(); j != (*i).second.end(); ++j) {
-                SPBox3D *box = *j;
-                box3d_switch_perspectives(box, persp, new_persp);
-            }
-        }
-    }
-}
-
 /* some debugging stuff follows */
 
 void
 persp3d_print_debugging_info (Persp3D *persp) {
-    g_print ("=== Info for Persp3D %d ===\n", persp->my_counter);
+    Persp3DImpl *persp_impl = persp->perspective_impl;
+    g_print ("=== Info for Persp3D %d ===\n", persp_impl->my_counter);
     gchar * cstr;
     for (int i = 0; i < 4; ++i) {
         cstr = persp3d_get_VP(persp, Proj::axes[i]).coord_string();
@@ -645,8 +557,8 @@ persp3d_print_debugging_info (Persp3D *persp) {
     g_free(cstr);
 
     g_print ("  Boxes: ");
-    for (std::vector<SPBox3D *>::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) {
-        g_print ("%d (%d)  ", (*i)->my_counter, box3d_get_perspective(*i)->my_counter);
+    for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) {
+        g_print ("%d (%d)  ", (*i)->my_counter, box3d_get_perspective(*i)->perspective_impl->my_counter);
     }
     g_print ("\n");
     g_print ("========================\n");
@@ -674,16 +586,23 @@ persp3d_print_all_selected() {
 
     for (std::list<Persp3D *>::iterator j = sel_persps.begin(); j != sel_persps.end(); ++j) {
         Persp3D *persp = SP_PERSP3D(*j);
-        g_print ("  %s (%d):  ", SP_OBJECT_REPR(persp)->attribute("id"), persp->my_counter);
-        for (std::map<SPBox3D *, bool>::iterator i = persp->boxes_transformed->begin();
-             i != persp->boxes_transformed->end(); ++i) {
-            g_print ("<%d,%d> ", (*i).first->my_counter, (*i).second);
+        Persp3DImpl *persp_impl = persp->perspective_impl;
+        g_print ("  %s (%d):  ", SP_OBJECT_REPR(persp)->attribute("id"), persp->perspective_impl->my_counter);
+        for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin();
+             i != persp_impl->boxes.end(); ++i) {
+            g_print ("%d ", (*i)->my_counter);
         }
         g_print ("\n");
     }
     g_print ("======================================\n\n");
  }
 
+void print_current_persp3d(gchar *func_name, Persp3D *persp) {
+    g_print ("%s: current_persp3d is now %s\n",
+             func_name,
+             persp ? SP_OBJECT_REPR(persp)->attribute("id") : "NULL");
+}
+
 /*
   Local Variables:
   mode:c++
index 79bec0232c5372465266a04e90924ade2e8e1481..62cc586ef15496c3fff523fc707e16e77ecedae8 100644 (file)
 class SPBox3D;
 class Box3DContext;
 
-struct Persp3D : public SPObject {
+class Persp3DImpl {
+public:
+    Persp3DImpl();
+
+//private:
     Proj::TransfMat3x4 tmat;
 
     // Also write the list of boxes into the xml repr and vice versa link boxes to their persp3d?
     std::vector<SPBox3D *> boxes;
-    std::map<SPBox3D *, bool>* boxes_transformed; // TODO: eventually we should merge this with 'boxes'
-    SPDocument *document; // should this rather be the SPDesktop?
+    SPDocument *document;
 
     // for debugging only
     int my_counter;
+
+//    friend class Persp3D;
+};
+
+struct Persp3D : public SPObject {
+    Persp3DImpl *perspective_impl;
 };
 
 struct Persp3DClass {
@@ -54,52 +63,43 @@ inline Persp3D * persp3d_get_from_repr (Inkscape::XML::Node *repr) {
     return SP_PERSP3D(SP_ACTIVE_DOCUMENT->getObjectByRepr(repr));
 }
 inline Proj::Pt2 persp3d_get_VP (Persp3D *persp, Proj::Axis axis) {
-    return persp->tmat.column(axis);
+    return persp->perspective_impl->tmat.column(axis);
 }
 Geom::Point persp3d_get_PL_dir_from_pt (Persp3D *persp, Geom::Point const &pt, Proj::Axis axis); // convenience wrapper around the following two
 Geom::Point persp3d_get_finite_dir (Persp3D *persp, Geom::Point const &pt, Proj::Axis axis);
 Geom::Point persp3d_get_infinite_dir (Persp3D *persp, Proj::Axis axis);
 double persp3d_get_infinite_angle (Persp3D *persp, Proj::Axis axis);
-bool persp3d_VP_is_finite (Persp3D *persp, Proj::Axis axis);
+bool persp3d_VP_is_finite (Persp3DImpl *persp_impl, Proj::Axis axis);
 void persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo = true);
 void persp3d_toggle_VPs (std::list<Persp3D *>, Proj::Axis axis);
 void persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state);
 void persp3d_rotate_VP (Persp3D *persp, Proj::Axis axis, double angle, bool alt_pressed); // angle is in degrees
-void persp3d_update_with_point (Persp3D *persp, Proj::Axis const axis, Proj::Pt2 const &new_image);
 void persp3d_apply_affine_transformation (Persp3D *persp, Geom::Matrix const &xform);
-gchar * persp3d_pt_to_str (Persp3D *persp, Proj::Axis const axis);
 
 void persp3d_add_box (Persp3D *persp, SPBox3D *box);
 void persp3d_remove_box (Persp3D *persp, SPBox3D *box);
 bool persp3d_has_box (Persp3D *persp, SPBox3D *box);
 
-void persp3d_add_box_transform (Persp3D *persp, SPBox3D *box);
-void persp3d_remove_box_transform (Persp3D *persp, SPBox3D *box);
-void persp3d_set_box_transformed (Persp3D *persp, SPBox3D *box, bool transformed = true);
-bool persp3d_was_transformed (Persp3D *persp);
-bool persp3d_all_transformed(Persp3D *persp);
-void persp3d_unset_transforms(Persp3D *persp);
-
 void persp3d_update_box_displays (Persp3D *persp);
 void persp3d_update_box_reprs (Persp3D *persp);
 void persp3d_update_z_orders (Persp3D *persp);
-inline unsigned int persp3d_num_boxes (Persp3D *persp) { return persp->boxes.size(); }
+inline unsigned int persp3d_num_boxes (Persp3D *persp) { return persp->perspective_impl->boxes.size(); }
 std::list<SPBox3D *> persp3d_list_of_boxes(Persp3D *persp);
 
 bool persp3d_perspectives_coincide(const Persp3D *lhs, const Persp3D *rhs);
 void persp3d_absorb(Persp3D *persp1, Persp3D *persp2);
 
-Persp3D * persp3d_create_xml_element (SPDocument *document, Persp3D *dup = NULL);
+Persp3D * persp3d_create_xml_element (SPDocument *document, Persp3DImpl *dup = NULL);
 Persp3D * persp3d_document_first_persp (SPDocument *document);
 
-bool persp3d_has_all_boxes_in_selection (Persp3D *persp);
-std::map<Persp3D *, std::list<SPBox3D *> > persp3d_unselected_boxes(Inkscape::Selection *selection);
-void persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection);
+bool persp3d_has_all_boxes_in_selection (Persp3D *persp, Inkscape::Selection *selection);
 
 void persp3d_print_debugging_info (Persp3D *persp);
 void persp3d_print_debugging_info_all(SPDocument *doc);
 void persp3d_print_all_selected();
 
+void print_current_persp3d(gchar *func_name, Persp3D *persp);
+
 #endif /* __PERSP3D_H__ */
 
 /*
index e55bba2a5926079ef2e3a2fd99f300d7b8e791c2..31e899d8a34c703866ae9dbc40c6b51244fdb8dc 100644 (file)
@@ -76,6 +76,7 @@
 #include "helper/units.h"
 #include "sp-item.h"
 #include "box3d.h"
+#include "persp3d.h"
 #include "unit-constants.h"
 #include "xml/simple-document.h"
 #include "sp-filter-reference.h"
@@ -1171,7 +1172,6 @@ selection_contains_both_clone_and_original(Inkscape::Selection *selection)
     return clone_with_original;
 }
 
-
 /** Apply matrix to the selection.  \a set_i2d is normally true, which means objects are in the
 original transform, synced with their reprs, and need to jump to the new transform in one go. A
 value of set_i2d==false is only used by seltrans when it's dragging objects live (not outlines); in
@@ -1183,6 +1183,29 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons
     if (selection->isEmpty())
         return;
 
+    // For each perspective with a box in selection, check whether all boxes are selected and
+    // unlink all non-selected boxes.
+    Persp3D *persp;
+    Persp3D *transf_persp;
+    std::list<Persp3D *> plist = selection->perspList();
+    for (std::list<Persp3D *>::iterator i = plist.begin(); i != plist.end(); ++i) {
+        persp = (Persp3D *) (*i);
+
+        if (!persp3d_has_all_boxes_in_selection (persp, selection)) {
+            std::list<SPBox3D *> selboxes = selection->box3DList(persp);
+
+            // create a new perspective as a copy of the current one and link the selected boxes to it
+            transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp->perspective_impl);
+
+            for (std::list<SPBox3D *>::iterator b = selboxes.begin(); b != selboxes.end(); ++b)
+                box3d_switch_perspectives(*b, persp, transf_persp);
+        } else {
+            transf_persp = persp;
+        }
+
+        persp3d_apply_affine_transformation(transf_persp, affine);
+    }
+
     for (GSList const *l = selection->itemList(); l != NULL; l = l->next) {
         SPItem *item = SP_ITEM(l->data);
 
index 4d92a18df77948f7de0620a8609566eb9e33075e..7b936587c343513760684927f30be54e7179f00b 100644 (file)
@@ -162,24 +162,12 @@ void Selection::add(SPObject *obj, bool persist_selection_context/* = false */)
     _emitChanged(persist_selection_context);
 }
 
-void Selection::add_box_perspective(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    std::map<Persp3D *, unsigned int>::iterator p = _persps.find(persp);
-    if (p != _persps.end()) {
-        (*p).second++;
-    } else {
-        _persps[persp] = 1;
-    }
-}
-
 void Selection::add_3D_boxes_recursively(SPObject *obj) {
     std::list<SPBox3D *> boxes = box3d_extract_boxes(obj);
 
     for (std::list<SPBox3D *>::iterator i = boxes.begin(); i != boxes.end(); ++i) {
         SPBox3D *box = *i;
-        box3d_add_to_selection(box);
         _3dboxes.push_back(box);
-        add_box_perspective(box);
     }
 }
 
@@ -220,33 +208,17 @@ void Selection::remove(SPObject *obj) {
     _emitChanged();
 }
 
-void Selection::remove_box_perspective(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    std::map<Persp3D *, unsigned int>::iterator p = _persps.find(persp);
-    if (p == _persps.end()) {
-        g_print ("Warning! Trying to remove unselected perspective from selection!\n");
-        return;
-    }
-    if ((*p).second > 1) {
-        _persps[persp]--;
-    } else {
-        _persps.erase(p);
-    }
-}
-
 void Selection::remove_3D_boxes_recursively(SPObject *obj) {
     std::list<SPBox3D *> boxes = box3d_extract_boxes(obj);
 
     for (std::list<SPBox3D *>::iterator i = boxes.begin(); i != boxes.end(); ++i) {
         SPBox3D *box = *i;
-        box3d_remove_from_selection(box);
         std::list<SPBox3D *>::iterator b = std::find(_3dboxes.begin(), _3dboxes.end(), box);
         if (b == _3dboxes.end()) {
             g_print ("Warning! Trying to remove unselected box from selection.\n");
             return;
         }
         _3dboxes.erase(b);
-        remove_box_perspective(box);
     }
 }
 
@@ -344,14 +316,27 @@ GSList const *Selection::reprList() {
 
 std::list<Persp3D *> const Selection::perspList() {
     std::list<Persp3D *> pl;
-    for (std::map<Persp3D *, unsigned int>::iterator p = _persps.begin(); p != _persps.end(); ++p) {
-        pl.push_back((*p).first);
+    for (std::list<SPBox3D *>::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) {
+        Persp3D *persp = box3d_get_perspective(*i);
+        if (std::find(pl.begin(), pl.end(), persp) == pl.end())
+            pl.push_back(persp);
     }
     return pl;
 }
 
-std::list<SPBox3D *> const Selection::box3DList() {
-    return _3dboxes;
+std::list<SPBox3D *> const Selection::box3DList(Persp3D *persp) {
+    std::list<SPBox3D *> boxes;
+    if (persp) {
+        SPBox3D *box;
+        for (std::list<SPBox3D *>::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) {
+            box = *i;
+            if (persp == box3d_get_perspective(box))
+                boxes.push_back(box);
+        }
+    } else {
+        boxes = _3dboxes;
+    }
+    return boxes;
 }
 
 SPObject *Selection::single() {
@@ -455,7 +440,7 @@ std::vector<std::pair<Geom::Point, int> > Selection::getSnapPoints(SnapPreferenc
         //Include the transformation origin for snapping
         //For a selection or group only the overall origin is considered
         if (snapprefs != NULL && snapprefs->getIncludeItemCenter()) {
-               p.push_back(std::make_pair(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER));
+            p.push_back(std::make_pair(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER));
         }
     }
 
@@ -467,12 +452,12 @@ std::vector<std::pair<Geom::Point, int> > Selection::getSnapPointsConvexHull(Sna
 
     std::vector<std::pair<Geom::Point, int> > p;
     for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-               sp_item_snappoints(SP_ITEM(iter->data), false, p, snapprefs);
+        sp_item_snappoints(SP_ITEM(iter->data), false, p, snapprefs);
     }
 
     std::vector<std::pair<Geom::Point, int> > pHull;
     if (!p.empty()) {
-       std::vector<std::pair<Geom::Point, int> >::iterator i;
+        std::vector<std::pair<Geom::Point, int> >::iterator i;
         Geom::RectHull cvh((p.front()).first);
         for (i = p.begin(); i != p.end(); i++) {
             // these are the points we get back
index 8eacf0d46c61969a11f211e5c4422abe3edc8aec..a0734c299f1ebbf954196e23483cc944d18c0530 100644 (file)
@@ -229,11 +229,14 @@ public:
     ///      method for that
     GSList const *reprList();
 
-    /* list of all perspectives which have a 3D box in the current selection
+    /** @brief Returns a list of all perspectives which have a 3D box in the current selection
        (these may also be nested in groups) */
     std::list<Persp3D *> const perspList();
 
-    std::list<SPBox3D *> const box3DList();
+    /** @brief Returns a list of all 3D boxes in the current selection which are associated to @c
+       persp. If @c pers is @c NULL, return all selected boxes.
+    */
+    std::list<SPBox3D *> const box3DList(Persp3D *persp = NULL);
 
     /** @brief Returns the number of layers in which there are selected objects */
     guint numberOfLayers();
@@ -353,7 +356,6 @@ private:
     void remove_box_perspective(SPBox3D *box);
     void remove_3D_boxes_recursively(SPObject *obj);
 
-    std::map<Persp3D *, unsigned int> _persps;
     std::list<SPBox3D *> _3dboxes;
 
     GC::soft_ptr<SPDesktop> _desktop;
index 545607889c48e13f21da41c2e05150b2028be135..2e38e4f146d9db8bc610ff049e10cb93e82ce35b 100644 (file)
@@ -164,18 +164,18 @@ bool SnapManager::gridSnapperMightSnap() const
  *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
  *  \param p Current position of the snap source; will be overwritten by the position of the snap target if snapping has occurred
  *  \param source_type Detailed description of the source type, will be used by the snap indicator
- *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
+ *  \param source_num Sequence number of the source point within the set of points that is to be snapped. Starting at zero
  *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
  */
 
 void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
                                       Geom::Point &p,
                                       Inkscape::SnapSourceType const source_type,
-                                      bool first_point,
+                                      long source_num,
                                       Geom::OptRect const &bbox_to_snap) const
 {
     //TODO: PointType and source_type are somewhat redundant; can't we get rid of the point_type parameter?
-    Inkscape::SnappedPoint const s = freeSnap(point_type, p, source_type, first_point, bbox_to_snap);
+    Inkscape::SnappedPoint const s = freeSnap(point_type, p, source_type, source_num, bbox_to_snap);
     s.getPoint(p);
 }
 
@@ -194,7 +194,7 @@ void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point
  *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
  *  \param p Current position of the snap source
  *  \param source_type Detailed description of the source type, will be used by the snap indicator
- *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
+ *  \param source_num Sequence number of the source point within the set of points that is to be snapped. Starting at zero
  *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
  *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics
  */
@@ -203,11 +203,11 @@ void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point
 Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointType point_type,
                                              Geom::Point const &p,
                                              Inkscape::SnapSourceType const &source_type,
-                                             bool first_point,
+                                             long source_num,
                                              Geom::OptRect const &bbox_to_snap) const
 {
-       if (!someSnapperMightSnap()) {
-        return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
+    if (!someSnapperMightSnap()) {
+        return Inkscape::SnappedPoint(p, source_type, 0, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
     }
 
     std::vector<SPItem const *> *items_to_ignore;
@@ -224,7 +224,7 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp
     SnapperList const snappers = getSnappers();
 
     for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
-        (*i)->freeSnap(sc, point_type, p, source_type, first_point, bbox_to_snap, items_to_ignore, _unselected_nodes);
+        (*i)->freeSnap(sc, point_type, p, source_type, source_num, bbox_to_snap, items_to_ignore, _unselected_nodes);
     }
 
     if (_item_to_ignore) {
@@ -280,7 +280,7 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const
                 Geom::Point const t_offset = t + grid->origin;
                 SnappedConstraints sc;
                 // Only the first three parameters are being used for grid snappers
-                snapper->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_NODE, t_offset, Inkscape::SNAPSOURCE_UNDEFINED, TRUE, Geom::OptRect(), NULL, NULL);
+                snapper->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_NODE, t_offset, Inkscape::SNAPSOURCE_UNDEFINED, 0, Geom::OptRect(), NULL, NULL);
                 // Find the best snap for this grid, including intersections of the grid-lines
                 Inkscape::SnappedPoint s = findBestSnap(t_offset, Inkscape::SNAPSOURCE_UNDEFINED, sc, false);
                 if (s.getSnapped() && (s.getSnapDistance() < nearest_distance)) {
@@ -323,7 +323,7 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const
  *  \param p Current position of the snap source; will be overwritten by the position of the snap target if snapping has occurred
  *  \param source_type Detailed description of the source type, will be used by the snap indicator
  *  \param constraint The direction or line along which snapping must occur
- *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
+ *  \param source_num Sequence number of the source point within the set of points that is to be snapped. Starting at zero
  *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
  */
 
@@ -331,10 +331,10 @@ void SnapManager::constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointTyp
                                              Geom::Point &p,
                                              Inkscape::SnapSourceType const source_type,
                                              Inkscape::Snapper::ConstraintLine const &constraint,
-                                             bool first_point,
+                                             long source_num,
                                              Geom::OptRect const &bbox_to_snap) const
 {
-    Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, source_type, constraint, first_point, bbox_to_snap);
+    Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, source_type, constraint, source_num, bbox_to_snap);
     s.getPoint(p);
 }
 
@@ -353,7 +353,7 @@ void SnapManager::constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointTyp
  *  \param p Current position of the snap source
  *  \param source_type Detailed description of the source type, will be used by the snap indicator
  *  \param constraint The direction or line along which snapping must occur
- *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
+ *  \param source_num Sequence number of the source point within the set of points that is to be snapped. Starting at zero
  *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
  */
 
@@ -361,11 +361,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P
                                                     Geom::Point const &p,
                                                     Inkscape::SnapSourceType const &source_type,
                                                     Inkscape::Snapper::ConstraintLine const &constraint,
-                                                    bool first_point,
+                                                    long source_num,
                                                     Geom::OptRect const &bbox_to_snap) const
 {
     if (!someSnapperMightSnap()) {
-        return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
+        return Inkscape::SnappedPoint(p, source_type, 0, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
     }
 
     std::vector<SPItem const *> *items_to_ignore;
@@ -386,7 +386,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P
     SnappedConstraints sc;
     SnapperList const snappers = getSnappers();
     for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
-        (*i)->constrainedSnap(sc, point_type, pp, source_type, first_point, bbox_to_snap, constraint, items_to_ignore);
+        (*i)->constrainedSnap(sc, point_type, pp, source_type, source_num, bbox_to_snap, constraint, items_to_ignore);
     }
 
     if (_item_to_ignore) {
@@ -420,7 +420,7 @@ void SnapManager::guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal,
 
     Inkscape::SnapSourceType source_type = Inkscape::SNAPSOURCE_GUIDE_ORIGIN;
     if (drag_type == SP_DRAG_ROTATE) {
-       source_type = Inkscape::SNAPSOURCE_GUIDE;
+        source_type = Inkscape::SNAPSOURCE_GUIDE;
     }
 
     // Snap to nodes
@@ -432,9 +432,9 @@ void SnapManager::guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal,
     // Snap to guides & grid lines
     SnapperList snappers = getGridSnappers();
     snappers.push_back(&guide);
-       for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
-               (*i)->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, true, Geom::OptRect(), NULL, NULL);
-       }
+    for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
+        (*i)->freeSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, 0, Geom::OptRect(), NULL, NULL);
+    }
 
     // Snap to intersections of curves, but not to the curves themselves! (see _snapTranslatingGuideToNodes in object-snapper.cpp)
     Inkscape::SnappedPoint const s = findBestSnap(p, source_type, sc, false, true);
@@ -458,7 +458,7 @@ void SnapManager::guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal,
 
 void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const
 {
-       if (!snapprefs.getSnapEnabledGlobally() || snapprefs.getSnapPostponedGlobally()) {
+    if (!snapprefs.getSnapEnabledGlobally() || snapprefs.getSnapPostponedGlobally()) {
         return;
     }
 
@@ -472,15 +472,15 @@ void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline)
     SnappedConstraints sc;
     Inkscape::Snapper::ConstraintLine cl(guideline.point_on_line, Geom::rot90(guideline.normal_to_line));
     if (object.ThisSnapperMightSnap()) {
-        object.constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, true, Geom::OptRect(), cl, NULL);
+        object.constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, 0, Geom::OptRect(), cl, NULL);
     }
 
     // Snap to guides & grid lines
-       SnapperList snappers = getGridSnappers();
-       snappers.push_back(&guide);
-       for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
-               (*i)->constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, true, Geom::OptRect(), cl, NULL);
-       }
+    SnapperList snappers = getGridSnappers();
+    snappers.push_back(&guide);
+    for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
+        (*i)->constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, source_type, 0, Geom::OptRect(), cl, NULL);
+    }
 
     Inkscape::SnappedPoint const s = findBestSnap(p, source_type, sc, false);
     s.getPoint(p);
@@ -566,6 +566,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
     g_assert(best_snapped_point.getAtIntersection() == false);
 
     std::vector<std::pair<Geom::Point, int> >::const_iterator j = transformed_points.begin();
+    long source_num = 0;
 
     // std::cout << std::endl;
     for (std::vector<std::pair<Geom::Point, int> >::const_iterator i = points.begin(); i != points.end(); i++) {
@@ -593,7 +594,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
             if (transformation_type == SCALE && !uniform) {
                 g_warning("Non-uniform constrained scaling is not supported!");
             }
-            snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, i == points.begin(), bbox);
+            snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, source_num, bbox);
         } else {
             bool const c1 = fabs(b[Geom::X]) < 1e-6;
             bool const c2 = fabs(b[Geom::Y]) < 1e-6;
@@ -602,9 +603,9 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
                 // move in that specific direction; therefore it should only snap in that direction, otherwise
                 // we will get snapped points with an invalid transformation
                 dedicated_constraint = Inkscape::Snapper::ConstraintLine(origin, component_vectors[c1]);
-                snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, i == points.begin(), bbox);
+                snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, source_num, bbox);
             } else {
-                snapped_point = freeSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), i == points.begin(), bbox);
+                snapped_point = freeSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), source_num, bbox);
             }
         }
         // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl;
@@ -715,6 +716,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
         }
 
         j++;
+        source_num++;
     }
 
     Geom::Coord best_metric;
@@ -917,10 +919,10 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(Inkscape::SnapPreference
  */
 
 Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p,
-                                                                                            Inkscape::SnapSourceType const source_type,
-                                                                                            SnappedConstraints &sc,
-                                                                                            bool constrained,
-                                                                                            bool noCurves) const
+                                                 Inkscape::SnapSourceType const source_type,
+                                                 SnappedConstraints &sc,
+                                                 bool constrained,
+                                                 bool noCurves) const
 {
 
     /*
@@ -943,10 +945,10 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p,
 
     // search for the closest snapped curve
     if (!noCurves) {
-               Inkscape::SnappedCurve closestCurve;
-               if (getClosestCurve(sc.curves, closestCurve)) {
-                       sp_list.push_back(Inkscape::SnappedPoint(closestCurve));
-               }
+        Inkscape::SnappedCurve closestCurve;
+        if (getClosestCurve(sc.curves, closestCurve)) {
+            sp_list.push_back(Inkscape::SnappedPoint(closestCurve));
+        }
     }
 
     if (snapprefs.getSnapIntersectionCS()) {
@@ -1005,7 +1007,7 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p,
     }
 
     // now let's see which snapped point gets a thumbs up
-    Inkscape::SnappedPoint bestSnappedPoint = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_UNDEFINED, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
+    Inkscape::SnappedPoint bestSnappedPoint = Inkscape::SnappedPoint(p, Inkscape::SNAPSOURCE_UNDEFINED, 0, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
     // std::cout << "Finding the best snap..." << std::endl;
     for (std::list<Inkscape::SnappedPoint>::const_iterator i = sp_list.begin(); i != sp_list.end(); i++) {
         // first find out if this snapped point is within snapping range
index e621bdb605334cb1b1e0fa4619368d2c09ca69f4..a3e463092cc4f8b1ddd570257db0c6073a9dd0df 100644 (file)
@@ -52,14 +52,14 @@ class SPNamedView;
 class SnapManager
 {
 public:
-       enum Transformation {
+    enum Transformation {
         TRANSLATION,
         SCALE,
         STRETCH,
         SKEW
     };
 
-       SnapManager(SPNamedView const *v);
+    SnapManager(SPNamedView const *v);
 
     typedef std::list<const Inkscape::Snapper*> SnapperList;
 
@@ -67,30 +67,30 @@ public:
     bool gridSnapperMightSnap() const;
 
     void setup(SPDesktop const *desktop,
-                       bool snapindicator = true,
-                       SPItem const *item_to_ignore = NULL,
-                       std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
-                       SPGuide *guide_to_ignore = NULL);
+            bool snapindicator = true,
+            SPItem const *item_to_ignore = NULL,
+            std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
+            SPGuide *guide_to_ignore = NULL);
 
     void setup(SPDesktop const *desktop,
-               bool snapindicator,
-               std::vector<SPItem const *> &items_to_ignore,
-               std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
-               SPGuide *guide_to_ignore = NULL);
+            bool snapindicator,
+            std::vector<SPItem const *> &items_to_ignore,
+            std::vector<std::pair<Geom::Point, int> > *unselected_nodes = NULL,
+            SPGuide *guide_to_ignore = NULL);
 
     // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
     // point if snapping has occurred (by overwriting p); otherwise p is untouched
     void freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
-                                                       Geom::Point &p,
-                                                       Inkscape::SnapSourceType const source_type,
-                                                       bool first_point = true,
-                                                       Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
+                                Geom::Point &p,
+                                Inkscape::SnapSourceType const source_type,
+                                long source_num = 0,
+                                Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
 
 
     Inkscape::SnappedPoint freeSnap(Inkscape::SnapPreferences::PointType point_type,
-                                                                       Geom::Point const &p,
-                                                           Inkscape::SnapSourceType const &source_type,
-                                       bool first_point = true,
+                                    Geom::Point const &p,
+                                    Inkscape::SnapSourceType const &source_type,
+                                    long source_num = 0,
                                     Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
 
     Geom::Point multipleOfGridPitch(Geom::Point const &t) const;
@@ -98,17 +98,17 @@ public:
     // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
     // point, by overwriting p, if snapping has occurred; otherwise p is untouched
     void constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
-                                                                       Geom::Point &p,
-                                                                       Inkscape::SnapSourceType const source_type,
-                                                                       Inkscape::Snapper::ConstraintLine const &constraint,
-                                                                       bool first_point = true,
-                                                                       Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
+                                    Geom::Point &p,
+                                    Inkscape::SnapSourceType const source_type,
+                                    Inkscape::Snapper::ConstraintLine const &constraint,
+                                    long source_num = 0,
+                                    Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
 
     Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapPreferences::PointType point_type,
-                                                                                  Geom::Point const &p,
-                                                                                  Inkscape::SnapSourceType const &source_type,
-                                                                                  Inkscape::Snapper::ConstraintLine const &constraint,
-                                                                                  bool first_point = true,
+                                           Geom::Point const &p,
+                                           Inkscape::SnapSourceType const &source_type,
+                                           Inkscape::Snapper::ConstraintLine const &constraint,
+                                           long source_num = 0,
                                            Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
 
     void guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal, SPGuideDragType drag_type) const;
index 4da2d4c7d5601aaf8699bcb23249f8b5a58501ca..33403863869525231c775f17e9580ed2a378190e 100644 (file)
@@ -12,7 +12,7 @@
 #include <2geom/crossing.h>
 #include <2geom/path-intersection.h>
 
-Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, SnapTargetType target)
+Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target)
 {
     _distance = snapped_distance;
     _tolerance = std::max(snapped_tolerance, 1.0);
@@ -25,6 +25,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coo
     _at_intersection = false;
     _fully_constrained = fully_constrained;
     _source = source;
+    _source_num = source_num;
     _target = target;
 }
 
@@ -41,6 +42,7 @@ Inkscape::SnappedCurve::SnappedCurve()
     _at_intersection = false;
     _fully_constrained = false;
     _source = SNAPSOURCE_UNDEFINED;
+    _source_num = 0;
     _target = SNAPTARGET_UNDEFINED;
 }
 
@@ -83,12 +85,12 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
         // TODO: Investigate whether it is possible to use document coordinates everywhere
         // in the snapper code. Only the mouse position should be in desktop coordinates, I guess.
         // All paths are already in document coords and we are certainly not going to change THAT.
-        return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryDist, primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true,
+        return SnappedPoint(best_p, Inkscape::SNAPSOURCE_UNDEFINED, primaryC->getSourceNum(), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryDist, primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, true,
                 secondaryDist, secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
 }
 
 // search for the closest snapped line
index 0a1fe243134760a08997b7ea21416a8b91a94ce1..4eea6e7342e64f5a864a354855c4123b148d7562 100644 (file)
@@ -24,7 +24,7 @@ class SnappedCurve : public SnappedPoint
 {
 public:
     SnappedCurve();
-    SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, SnapTargetType target);
+    SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target);
     ~SnappedCurve();
     Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Matrix dt2doc) const; //intersect with another SnappedCurve
 
index 3ebbeaf70d3962e5b38baa4bdbe06249707d1ba5..9dde22a4e1f675e25ea5a9336f01dcacc4dfdf7c 100644 (file)
 #include "snapped-line.h"
 #include <2geom/line.h>
 
-Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line)
+Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line)
     : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line)
 {
     _point = snapped_point;
     _source = source;
-       _target = target;
+    _source_num = source_num;
+    _target = target;
     _distance = snapped_distance;
     _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
@@ -32,7 +33,8 @@ Inkscape::SnappedLineSegment::SnappedLineSegment()
     _end_point_of_line = Geom::Point(0,0);
     _point = Geom::Point(0,0);
     _source = SNAPSOURCE_UNDEFINED;
-       _target = SNAPTARGET_UNDEFINED;
+    _source_num = 0;
+    _target = SNAPTARGET_UNDEFINED;
     _distance = NR_HUGE;
     _tolerance = 1;
     _always_snap = false;
@@ -50,19 +52,19 @@ Inkscape::SnappedLineSegment::~SnappedLineSegment()
 Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegment const &line) const
 {
     Geom::OptCrossing inters = Geom::OptCrossing(); // empty by default
-       try
-       {
-               inters = Geom::intersection(getLineSegment(), line.getLineSegment());
-       }
-       catch (Geom::InfiniteSolutions e)
-       {
-               // We're probably dealing with parallel lines, so they don't really cross
-               inters = Geom::OptCrossing();
-       }
+    try
+    {
+        inters = Geom::intersection(getLineSegment(), line.getLineSegment());
+    }
+    catch (Geom::InfiniteSolutions e)
+    {
+        // We're probably dealing with parallel lines, so they don't really cross
+        inters = Geom::OptCrossing();
+    }
 
     if (inters) {
         Geom::Point inters_pt = getLineSegment().pointAt((*inters).ta);
-       /* If a snapper has been told to "always snap", then this one should be preferred
+        /* If a snapper has been told to "always snap", then this one should be preferred
          * over the other, if that other one has not been told so. (The preferred snapper
          * will be labeled "primary" below)
         */
@@ -78,22 +80,23 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen
         Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this;
         Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
         Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
-        return SnappedPoint(inters_pt, SNAPSOURCE_UNDEFINED, SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
+        return SnappedPoint(inters_pt, SNAPSOURCE_UNDEFINED, primarySLS->getSourceNum(), SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
                                           secondaryDist, secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
 };
 
 
 
-Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line)
+Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line)
     : _normal_to_line(normal_to_line), _point_on_line(point_on_line)
 {
-       _source = source;
-       _target = target;
-       _distance = snapped_distance;
+    _source = source;
+    _source_num = source_num;
+    _target = target;
+    _distance = snapped_distance;
     _tolerance = std::max(snapped_tolerance, 1.0);
     _always_snap = always_snap;
     _second_distance = NR_HUGE;
@@ -108,7 +111,8 @@ Inkscape::SnappedLine::SnappedLine()
     _normal_to_line = Geom::Point(0,0);
     _point_on_line = Geom::Point(0,0);
     _source = SNAPSOURCE_UNDEFINED;
-       _target = SNAPTARGET_UNDEFINED;
+    _source_num = 0;
+    _target = SNAPTARGET_UNDEFINED;
     _distance = NR_HUGE;
     _tolerance = 1;
     _always_snap = false;
@@ -130,19 +134,19 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line)
     // The point of intersection should be considered for snapping, but might be outside the snapping range
 
     Geom::OptCrossing inters = Geom::OptCrossing(); // empty by default
-       try
-       {
-               inters = Geom::intersection(getLine(), line.getLine());
-       }
-       catch (Geom::InfiniteSolutions e)
-       {
-               // We're probably dealing with parallel lines, so they don't really cross
-               inters = Geom::OptCrossing();
-       }
+    try
+    {
+        inters = Geom::intersection(getLine(), line.getLine());
+    }
+    catch (Geom::InfiniteSolutions e)
+    {
+        // We're probably dealing with parallel lines, so they don't really cross
+        inters = Geom::OptCrossing();
+    }
 
     if (inters) {
-       Geom::Point inters_pt = getLine().pointAt((*inters).ta);
-       /* If a snapper has been told to "always snap", then this one should be preferred
+        Geom::Point inters_pt = getLine().pointAt((*inters).ta);
+        /* If a snapper has been told to "always snap", then this one should be preferred
          * over the other, if that other one has not been told so. (The preferred snapper
          * will be labelled "primary" below)
         */
@@ -157,14 +161,14 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line)
         Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this;
         Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
         Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
-        return SnappedPoint(inters_pt, Inkscape::SNAPSOURCE_UNDEFINED, Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
+        return SnappedPoint(inters_pt, Inkscape::SNAPSOURCE_UNDEFINED, primarySL->getSourceNum(), Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
                                           secondaryDist, secondarySL->getTolerance(), secondarySL->getAlwaysSnap());
         // The type of the snap target is yet undefined, as we cannot tell whether
         // we're snapping to grid or the guide lines; must be set by on a higher level
     }
 
     // No intersection
-    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
+    return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED, 0, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
 }
 
 // search for the closest snapped line segment
index 3dec432e7eff4e119a01f1695f6be1d41bdf152b..b95e7a7dff3d9f5884718b31fbe5e92ec8f11ce8 100644 (file)
@@ -23,7 +23,7 @@ class SnappedLineSegment : public SnappedPoint
 {
 public:
     SnappedLineSegment();
-    SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &snapped_tolerance,bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line);
+    SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance,bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line);
     ~SnappedLineSegment();
     Inkscape::SnappedPoint intersect(SnappedLineSegment const &line) const; //intersect with another SnappedLineSegment
     Geom::LineSegment getLineSegment() const {return Geom::LineSegment(_start_point_of_line, _end_point_of_line);}
@@ -39,7 +39,7 @@ class SnappedLine : public SnappedPoint
 {
 public:
     SnappedLine();
-    SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line);
+    SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line);
     ~SnappedLine();
     Inkscape::SnappedPoint intersect(SnappedLine const &line) const; //intersect with another SnappedLine
     // This line is described by this equation:
index 2d028c6d78eb441b264e18b8a30f342577d630cb..102e761b9ef2cadcb319ab0dcd7d64fe205d89da 100644 (file)
@@ -14,8 +14,8 @@
 #include "preferences.h"
 
 // overloaded constructor
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained)
-    : _point(p), _source(source), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a)
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained)
+    : _point(p), _source(source), _source_num(source_num), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a)
 {
     // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero.
     _at_intersection = false;
@@ -27,8 +27,8 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const
     _pointer_distance = NR_HUGE;
 }
 
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
-    : _point(p), _source(source), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a),
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
+    : _point(p), _source(source), _source_num(source_num), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a),
     _second_distance(d2), _second_tolerance(std::max(t2,1.0)), _second_always_snap(a2)
 {
     // tolerance should never be smaller than 1 px, as it is used for normalization in
@@ -41,6 +41,7 @@ Inkscape::SnappedPoint::SnappedPoint()
 {
     _point = Geom::Point(0,0);
     _source = SNAPSOURCE_UNDEFINED,
+    _source_num = 0,
     _target = SNAPTARGET_UNDEFINED,
     _at_intersection = false;
     _fully_constrained = false;
@@ -73,7 +74,7 @@ bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoin
     bool success = false;
 
     for (std::list<Inkscape::SnappedPoint>::const_iterator i = list.begin(); i != list.end(); i++) {
-       if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
+        if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
             result = *i;
             success = true;
         }
@@ -93,9 +94,9 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth
     // (both the snap distance and the pointer distance are measured in document pixels, not in screen pixels)
     if (weighted) {
 
-       Geom::Coord const dist_pointer_other = other_one.getPointerDistance();
-       Geom::Coord const dist_pointer_this = getPointerDistance();
-       // Weight factor: controls which node should be preferred for snapping, which is either
+        Geom::Coord const dist_pointer_other = other_one.getPointerDistance();
+        Geom::Coord const dist_pointer_this = getPointerDistance();
+        // Weight factor: controls which node should be preferred for snapping, which is either
         // the node with the closest snap (w = 0), or the node closest to the mousepointer (w = 1)
         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
         double w = prefs->getDoubleLimited("/options/snapweight/value", 0.5, 0, 1);
@@ -103,21 +104,21 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth
             w = 1;
         }
         if (w > 0) {
-               if (!(w == 1 && dist_pointer_this == dist_pointer_other)) {
-                       // When accounting for the distance to the mouse pointer, then at least one of the snapped points should
-                               // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the
-                               // mouse pointer distance must be set.
-                               g_assert(dist_pointer_this != NR_HUGE || dist_pointer_other != NR_HUGE);
-                               // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can
-                               // however be very large. To compare these in a fair way, we will have to normalize these metrics first
-                               // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0
-                               // The snap distance will be normalized to 1.0 if it's equal to the snapper tolerance
-                               double const norm_p = std::min(dist_pointer_this, dist_pointer_other);
-                               double const norm_t_other = std::min(50.0, other_one.getTolerance());
-                               double const norm_t_this = std::min(50.0, getTolerance());
-                               dist_other = w * dist_pointer_other / norm_p + (1-w) * dist_other / norm_t_other;
-                               dist_this = w * dist_pointer_this / norm_p + (1-w) * dist_this / norm_t_this;
-               }
+            if (!(w == 1 && dist_pointer_this == dist_pointer_other)) {
+                // When accounting for the distance to the mouse pointer, then at least one of the snapped points should
+                // have that distance set. If not, then this is a bug. Either "weighted" must be set to false, or the
+                // mouse pointer distance must be set.
+                g_assert(dist_pointer_this != NR_HUGE || dist_pointer_other != NR_HUGE);
+                // The snap distance will always be smaller than the tolerance set for the snapper. The pointer distance can
+                // however be very large. To compare these in a fair way, we will have to normalize these metrics first
+                // The closest pointer distance will be normalized to 1.0; the other one will be > 1.0
+                // The snap distance will be normalized to 1.0 if it's equal to the snapper tolerance
+                double const norm_p = std::min(dist_pointer_this, dist_pointer_other);
+                double const norm_t_other = std::min(50.0, other_one.getTolerance());
+                double const norm_t_this = std::min(50.0, getTolerance());
+                dist_other = w * dist_pointer_other / norm_p + (1-w) * dist_other / norm_t_other;
+                dist_this = w * dist_pointer_this / norm_p + (1-w) * dist_this / norm_t_this;
+            }
         }
     }
 
index 70d16b0be10be3c586aac58469e8f5065df6751a..70d353a7366ca2a28f94f8f8352f05a4c1d50e91 100644 (file)
@@ -78,8 +78,8 @@ class SnappedPoint
 
 public:
     SnappedPoint();
-    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
-    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained);
+    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
+    SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained);
     ~SnappedPoint();
 
     Geom::Coord getSnapDistance() const {return _distance;}
@@ -115,13 +115,15 @@ public:
     void setTarget(SnapTargetType const target) {_target = target;}
     SnapTargetType getTarget() const {return _target;}
     void setSource(SnapSourceType const source) {_source = source;}
-       SnapSourceType getSource() const {return _source;}
+    SnapSourceType getSource() const {return _source;}
+    long getSourceNum() const {return _source_num;}
 
     bool isOtherSnapBetter(SnappedPoint const &other_one, bool weighted) const;
 
     /*void dump() const {
         std::cout << "_point              = " << _point << std::endl;
         std::cout << "_source             = " << _source << std::endl;
+        std::cout << "_source_num         = " << _source_num << std::endl;
         std::cout << "_target             = " << _target << std::endl;
         std::cout << "_at_intersection    = " << _at_intersection << std::endl;
         std::cout << "_fully_constrained  = " << _fully_constrained << std::endl;
@@ -138,6 +140,7 @@ public:
 protected:
     Geom::Point _point; // Location of the snapped point
     SnapSourceType _source; // Describes what snapped
+    long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero)
     SnapTargetType _target; // Describes to what we've snapped to
     bool _at_intersection; // If true, the snapped point is at an intersection
     bool _fully_constrained; // When snapping for example to a node, then the snap will be "fully constrained".
@@ -153,7 +156,7 @@ protected:
     bool _always_snap;
 
     /* If the snapped point is at an intersection of e.g. two lines, then this is
-       the distance to the fartest line */
+       the distance to the farthest line */
     Geom::Coord _second_distance;
     /* The snapping tolerance in screen pixels (depends on zoom)*/
     Geom::Coord _second_tolerance;
index 110b3d36ad5292fa721e1db7e55b76af01c5ce19..dcc0fbb8146499662c2a49794a7298b9ce80057d 100644 (file)
@@ -39,9 +39,9 @@ namespace Inkscape
 class Snapper
 {
 public:
-       Snapper() {}
-       Snapper(SnapManager *sm, ::Geom::Coord const t);
-       virtual ~Snapper() {}
+    Snapper() {}
+    Snapper(SnapManager *sm, ::Geom::Coord const t);
+    virtual ~Snapper() {}
 
     virtual Geom::Coord getSnapperTolerance() const = 0; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
     virtual bool getSnapperAlwaysSnap() const = 0; //if true, then the snapper will always snap, regardless of its tolerance
@@ -53,7 +53,7 @@ public:
 
     // These four methods are only used for grids, for which snapping can be enabled individually
     void setEnabled(bool s);
-       void setSnapVisibleOnly(bool s);
+    void setSnapVisibleOnly(bool s);
     bool getEnabled() const {return _snap_enabled;}
     bool getSnapVisibleOnly() const {return _snap_visible_only;}
 
@@ -61,7 +61,7 @@ public:
                           SnapPreferences::PointType const &/*t*/,
                           Geom::Point const &/*p*/,
                           SnapSourceType const &/*source_type*/,
-                          bool const &/*first_point*/,
+                          long /*source_num*/,
                           Geom::OptRect const &/*bbox_to_snap*/,
                           std::vector<SPItem const *> const */*it*/,
                           std::vector<std::pair<Geom::Point, int> > */*unselected_nodes*/) const {};
@@ -90,9 +90,9 @@ public:
         }
 
         Geom::Point projection(Geom::Point const &p) const { // returns the projection of p on this constraintline
-               Geom::Point const p1_on_cl = _has_point ? _point : p;
-                       Geom::Point const p2_on_cl = p1_on_cl + _direction;
-               return Geom::projection(p, Geom::Line(p1_on_cl, p2_on_cl));
+            Geom::Point const p1_on_cl = _has_point ? _point : p;
+            Geom::Point const p2_on_cl = p1_on_cl + _direction;
+            return Geom::projection(p, Geom::Line(p1_on_cl, p2_on_cl));
         }
 
     private:
@@ -103,20 +103,20 @@ public:
     };
 
     virtual void constrainedSnap(SnappedConstraints &/*sc*/,
-                                                        SnapPreferences::PointType const &/*t*/,
+                                 SnapPreferences::PointType const &/*t*/,
                                  Geom::Point const &/*p*/,
                                  SnapSourceType const &/*source_type*/,
-                                 bool const &/*first_point*/,
+                                 long /*source_num*/,
                                  Geom::OptRect const &/*bbox_to_snap*/,
                                  ConstraintLine const &/*c*/,
                                  std::vector<SPItem const *> const */*it*/) const {};
 
 protected:
-       SnapManager *_snapmanager;
+    SnapManager *_snapmanager;
 
-       // This is only used for grids, for which snapping can be enabled individually
-       bool _snap_enabled; ///< true if this snapper is enabled, otherwise false
-       bool _snap_visible_only;
+    // This is only used for grids, for which snapping can be enabled individually
+    bool _snap_enabled; ///< true if this snapper is enabled, otherwise false
+    bool _snap_visible_only;
 };
 
 }
index 2287a182d16a0bbebc02125a7ef339a5037b4578..224442eb852370a877a160070d957f0ad09e6b13 100644 (file)
@@ -48,12 +48,12 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p
         SPGroup* group = SP_GROUP(item);
 
         // consider all first-order children
-        double child_pos = std::numeric_limits<double>::max();
+        double child_pos = 0.0;
         for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) {
             SPItem* child_item = SP_ITEM(i->data);
             try_get_intersect_point_with_item_recursive(conn_pv, child_item,
                     item_transform * child_item->transform, child_pos);
-            if (intersect_pos > child_pos)
+            if (intersect_pos < child_pos)
                 intersect_pos = child_pos;
         }
         return intersect_pos != initial_pos;
@@ -77,7 +77,7 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p
 
         for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); i++) {
             const Geom::Crossing& cr_pt = *i;
-            if ( intersect_pos > cr_pt.ta)
+            if ( intersect_pos < cr_pt.ta)
                 intersect_pos = cr_pt.ta;
         }
     }
@@ -109,8 +109,8 @@ static bool try_get_intersect_point_with_item(SPPath* conn, SPItem* item,
         conn_pv[0] = conn_pv[0].reverse();
     }
 
-    // We start with the intersection point at the end of the path
-    intersect_pos = conn_pv[0].size();
+    // We start with the intersection point at the beginning of the path
+    intersect_pos = 0.0;
 
     // Find the intersection.
     bool result = try_get_intersect_point_with_item_recursive(conn_pv, item, item_transform, intersect_pos);
index e4259e52ca9bb0f3adf9a8cc63f5d26f49975147..53bcd425db5916718ba4d13679614310615cde5d 100644 (file)
@@ -27,7 +27,7 @@
 #include "sp-rect.h"
 #include "text-tag-attributes.h"
 #include "text-chemistry.h"
-
+#include "text-editing.h"
 
 #include "livarot/Shape.h"
 
@@ -49,6 +49,7 @@ static void sp_flowtext_set(SPObject *object, unsigned key, gchar const *value);
 static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags);
 static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx);
 static gchar *sp_flowtext_description(SPItem *item);
+static void sp_flowtext_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs);
 static NRArenaItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags);
 static void sp_flowtext_hide(SPItem *item, unsigned key);
 
@@ -98,6 +99,7 @@ sp_flowtext_class_init(SPFlowtextClass *klass)
     item_class->bbox = sp_flowtext_bbox;
     item_class->print = sp_flowtext_print;
     item_class->description = sp_flowtext_description;
+    item_class->snappoints = sp_flowtext_snappoints;
     item_class->show = sp_flowtext_show;
     item_class->hide = sp_flowtext_hide;
 }
@@ -373,15 +375,27 @@ static gchar *sp_flowtext_description(SPItem *item)
     Inkscape::Text::Layout const &layout = SP_FLOWTEXT(item)->layout;
     int const nChars = layout.iteratorToCharIndex(layout.end());
 
-    char *trunc = "";
-    if (layout.inputTruncated()) {
-        trunc = _(" [truncated]");
-    }
+    char const *trunc = (layout.inputTruncated()) ? _(" [truncated]") : "";
 
-    if (SP_FLOWTEXT(item)->has_internal_frame())
+    if (SP_FLOWTEXT(item)->has_internal_frame()) {
         return g_strdup_printf(ngettext("<b>Flowed text</b> (%d character%s)", "<b>Flowed text</b> (%d characters%s)", nChars), nChars, trunc);
-    else
+    } else {
         return g_strdup_printf(ngettext("<b>Linked flowed text</b> (%d character%s)", "<b>Linked flowed text</b> (%d characters%s)", nChars), nChars, trunc);
+    }
+}
+
+static void sp_flowtext_snappoints(SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const */*snapprefs*/)
+{
+    // Choose a point on the baseline for snapping from or to, with the horizontal position
+    // of this point depending on the text alignment (left vs. right)
+    Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) item);
+    if (layout != NULL && layout->outputExists()) {
+        boost::optional<Geom::Point> pt = layout->baselineAnchorPoint();
+        if (pt) {
+            int type = target ? int(Inkscape::SNAPTARGET_TEXT_BASELINE) : int(Inkscape::SNAPSOURCE_TEXT_BASELINE);
+            p.push_back(std::make_pair((*pt) * sp_item_i2d_affine(item), type));
+        }
+    }
 }
 
 static NRArenaItem *
index 7ac7880a79d0e17a9653a6212d09aba2e84fa479..3845be23219b8ceb8e51a69cafa1f403e42dd6ff 100644 (file)
@@ -67,7 +67,6 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value);
 static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags);
 static void sp_group_print (SPItem * item, SPPrintContext *ctx);
 static gchar * sp_group_description (SPItem * item);
-static Geom::Matrix sp_group_set_transform(SPItem *item, Geom::Matrix const &xform);
 static NRArenaItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
 static void sp_group_hide (SPItem * item, unsigned int key);
 static void sp_group_snappoints (SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs);
@@ -129,7 +128,6 @@ sp_group_class_init (SPGroupClass *klass)
     item_class->bbox = sp_group_bbox;
     item_class->print = sp_group_print;
     item_class->description = sp_group_description;
-        item_class->set_transform = sp_group_set_transform;
     item_class->show = sp_group_show;
     item_class->hide = sp_group_hide;
     item_class->snappoints = sp_group_snappoints;
@@ -291,24 +289,6 @@ static gchar * sp_group_description (SPItem * item)
     return SP_GROUP(item)->group->getDescription();
 }
 
-static Geom::Matrix
-sp_group_set_transform(SPItem *item, Geom::Matrix const &xform)
-{
-    Inkscape::Selection *selection = sp_desktop_selection(inkscape_active_desktop());
-    persp3d_split_perspectives_according_to_selection(selection);
-
-    Geom::Matrix last_trans;
-    sp_svg_transform_read(SP_OBJECT_REPR(item)->attribute("transform"), &last_trans);
-    Geom::Matrix inc_trans = last_trans.inverse()*xform;
-
-    std::list<Persp3D *> plist = selection->perspList();
-    for (std::list<Persp3D *>::iterator i = plist.begin(); i != plist.end(); ++i) {
-        persp3d_apply_affine_transformation(*i, inc_trans);
-    }
-
-    return xform;
-}
-
 static void sp_group_set(SPObject *object, unsigned key, char const *value) {
     SPGroup *group = SP_GROUP(object);
 
index 9f7157b995561f8e8b6aeef0765ce67841f1b391..1a5ca6f772a72f7ba94fd99c153062bdabf9502b 100644 (file)
@@ -962,11 +962,11 @@ static void sp_item_private_snappoints(SPItem const *item, bool const target, Sn
         Geom::Point p1, p2;
         p1 = bbox->min();
         p2 = bbox->max();
-        int type = target ? int(Inkscape::SNAPSOURCE_CONVEX_HULL_CORNER) : int(Inkscape::SNAPSOURCE_CONVEX_HULL_CORNER);
+        int type = target ? int(Inkscape::SNAPTARGET_BBOX_CORNER) : int(Inkscape::SNAPSOURCE_BBOX_CORNER);
         p.push_back(std::make_pair(p1, type));
         p.push_back(std::make_pair(Geom::Point(p1[Geom::X], p2[Geom::Y]), type));
         p.push_back(std::make_pair(p2, type));
-        p.push_back(std::make_pair(Geom::Point(p1[Geom::Y], p2[Geom::X]), type));
+        p.push_back(std::make_pair(Geom::Point(p2[Geom::X], p1[Geom::Y]), type));
     }
 
 }
index b70e164675202ac1a89d9e94f0c08434cc311b98..b68fe0818cf00aef002b4d78dc32635e1a0b786a 100644 (file)
 #include "desktop-style.h"
 #include "message-context.h"
 #include "pixmaps/cursor-spray.xpm"
-#include "pixmaps/cursor-spray-move.xpm"
-#include "pixmaps/cursor-thin.xpm"
-#include "pixmaps/cursor-thicken.xpm"
-#include "pixmaps/cursor-attract.xpm"
-#include "pixmaps/cursor-repel.xpm"
-#include "pixmaps/cursor-push.xpm"
-#include "pixmaps/cursor-roughen.xpm"
-#include "pixmaps/cursor-color.xpm"
+//#include "pixmaps/cursor-spray-move.xpm"
+//#include "pixmaps/cursor-thin.xpm"
+//#include "pixmaps/cursor-thicken.xpm"
+//#include "pixmaps/cursor-attract.xpm"
+//#include "pixmaps/cursor-repel.xpm"
+//#include "pixmaps/cursor-push.xpm"
+//#include "pixmaps/cursor-roughen.xpm"
+//#include "pixmaps/cursor-color.xpm"
 #include <boost/optional.hpp>
 #include "libnr/nr-matrix-ops.h"
 #include "libnr/nr-scale-translate-ops.h"
@@ -107,10 +107,6 @@ static gint sp_spray_context_root_handler(SPEventContext *ec, GdkEvent *event);
 static SPEventContextClass *parent_class = 0;
 
 
-
-// The following code implements NormalDistribution wich is used for the density of the spray
-
-
 /*
    RAND is a macro which returns a pseudo-random numbers from a uniform
    distribution on the interval [0 1]
@@ -118,7 +114,7 @@ static SPEventContextClass *parent_class = 0;
 #define RAND ((double) rand())/((double) RAND_MAX)
 
 /*
-   TWOPI = 2.0*pi
+    TWOPI = 2.0*pi
 */
 #define TWOPI 2.0*3.141592653589793238462643383279502884197169399375
 
@@ -141,7 +137,6 @@ double NormalDistribution(double mu,double sigma)
 
 }
 
-//Fin de la création de NormalDistribution
 
 GtkType sp_spray_context_get_type(void)
 {
@@ -176,19 +171,16 @@ static void sp_spray_context_class_init(SPSprayContextClass *klass)
     event_context_class->root_handler = sp_spray_context_root_handler;
 }
 
-/*Method to rotate items*/
+/* Method to rotate items */
 void sp_spray_rotate_rel(Geom::Point c,SPDesktop */*desktop*/,SPItem *item, Geom::Rotate const &rotation)
 {
-
     Geom::Point center = c;
     Geom::Translate const s(c);
     Geom::Matrix affine = Geom::Matrix(s).inverse() * Geom::Matrix(rotation) * Geom::Matrix(s);
-
     // Rotate item.
     sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * (Geom::Matrix)affine);
     // Use each item's own transform writer, consistent with sp_selection_apply_affine()
     sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform);
-
     // Restore the center position (it's changed because the bbox center changed)
     if (item->isCenterSet()) {
         item->setCenter(c);
@@ -196,23 +188,17 @@ void sp_spray_rotate_rel(Geom::Point c,SPDesktop */*desktop*/,SPItem *item, Geom
     }
 }
 
-/*Method to scale items*/
+/* Method to scale items */
 void sp_spray_scale_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Scale  const &scale)
 {
-        Geom::Translate const s(c);
-
-
-        sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * s.inverse() * scale * s  );
-        sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform);
-
-
+    Geom::Translate const s(c);
+    sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * s.inverse() * scale * s  );
+    sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform);
 }
 
 static void sp_spray_context_init(SPSprayContext *tc)
 {
-   SPEventContext *event_context = SP_EVENT_CONTEXT(tc);
-
-
+    SPEventContext *event_context = SP_EVENT_CONTEXT(tc);
 
     event_context->cursor_shape = cursor_spray_xpm;
     event_context->hot_x = 4;
@@ -226,12 +212,10 @@ static void sp_spray_context_init(SPSprayContext *tc)
     tc->ratio = 0;
     tc->tilt=0;
     tc->mean = 0.2;
-    tc->rot_min=0;
-    tc->rot_max=0;
+    tc->rotation_variation=0;
     tc->standard_deviation=0.2;
     tc->scale=1;
-    tc->scale_min = 1;
-    tc->scale_max=1;
+    tc->scale_variation = 1;
     tc->pressure = TC_DEFAULT_PRESSURE;
 
     tc->is_dilating = false;
@@ -297,8 +281,7 @@ void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/)
        case SPRAY_MODE_SINGLE_PATH:
            tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray in a <b>single path</b> of the initial selection"), sel_message);
            break;
-       case SPRAY_OPTION:
-           tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Modify <b>spray</b> options"), sel_message);
+       default:
            break;
    }
    sp_event_context_update_cursor(event_context);
@@ -337,18 +320,14 @@ static void sp_spray_context_setup(SPEventContext *ec)
     sp_event_context_read(ec, "width");
     sp_event_context_read(ec, "ratio");
     sp_event_context_read(ec, "tilt");
-    sp_event_context_read(ec, "rot_min");
-    sp_event_context_read(ec, "rot_max");
-    sp_event_context_read(ec, "scale_min");
-    sp_event_context_read(ec, "scale_max");
+    sp_event_context_read(ec, "rotation_variation");
+    sp_event_context_read(ec, "scale_variation");
     sp_event_context_read(ec, "mode");
     sp_event_context_read(ec, "population");
     sp_event_context_read(ec, "force");
     sp_event_context_read(ec, "mean");
     sp_event_context_read(ec, "standard_deviation");
     sp_event_context_read(ec, "usepressure");
-    sp_event_context_read(ec, "Rotation min");
-    sp_event_context_read(ec, "Rotation max");
     sp_event_context_read(ec, "Scale");
     sp_event_context_read(ec, "doh");
     sp_event_context_read(ec, "dol");
@@ -387,14 +366,10 @@ static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entr
         tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9);
     } else if (path == "force") {
         tc->force = CLAMP(val->getDouble(1.0), 0, 1.0);
-    } else if (path == "rot_min") {
-        tc->rot_min = CLAMP(val->getDouble(0), 0, 10.0);
-    } else if (path == "rot_max") {
-        tc->rot_max = CLAMP(val->getDouble(0), 0, 10.0);
-    } else if (path == "scale_min") {
-        tc->scale_min = CLAMP(val->getDouble(1.0), 0, 10.0);
-    } else if (path == "scale_max") {
-        tc->scale_max = CLAMP(val->getDouble(1.0), 0, 10.0);
+    } else if (path == "rotation_variation") {
+        tc->rotation_variation = CLAMP(val->getDouble(0.0), 0, 100.0);
+    } else if (path == "scale_variation") {
+        tc->scale_variation = CLAMP(val->getDouble(1.0), 0, 100.0);
     } else if (path == "mean") {
         tc->mean = 0.01 * CLAMP(val->getInt(10), 1, 100);
     } else if (path == "standard_deviation") {
@@ -464,32 +439,24 @@ double get_move_standard_deviation(SPSprayContext *tc)
     return tc->standard_deviation;
 }
 
-/* Method to handle the distribution of the items */
-
-
-void random_position( double &r, double &p, double &a, double &s, int choix)
+/** Method to handle the distribution of the items */
+void random_position( double &r, double &p, double &a, double &s, int choice)
 {
-       if (choix == 0) // Mode 1 : uniform repartition
+    if (choice == 0) // 1 : uniform repartition
     {
         r = (1-pow(g_random_double_range(0, 1),2));
         p = g_random_double_range(0, M_PI*2);
     }
-    if (choix == 1) //Mode 0 : gaussian repartition
+    if (choice == 1) // 0 : gaussian repartition
     {
         double r_temp =-1;
-while(!((r_temp>=0)&&(r_temp<=1)))
-{
-         r_temp = NormalDistribution(a,s/4);
-}
-// generates a number following a normal distribution
+        while(!((r_temp>=0)&&(r_temp<=1)))
+        {
+            r_temp = NormalDistribution(a,s/4);
+        }
+        // generates a number following a normal distribution
         p = g_random_double_range(0, M_PI*2);
         r=r_temp;
-       /* if (r_temp<=0) r=0;
-        else
-        {
-            if (r_temp>1) r=1;
-            else r = r_temp;
-        }*/
     }
 }
 
@@ -497,7 +464,7 @@ while(!((r_temp>=0)&&(r_temp<=1)))
 
 
 
-bool sp_spray_dilate_recursive(SPDesktop *desktop,
+bool sp_spray_recursive(SPDesktop *desktop,
                                Inkscape::Selection *selection,
                                SPItem *item,
                                Geom::Point p,
@@ -507,202 +474,155 @@ bool sp_spray_dilate_recursive(SPDesktop *desktop,
                                double /*force*/,
                                double population,
                                double &scale,
-                               double scale_min,
-                               double scale_max,
+                               double scale_variation,
                                bool /*reverse*/,
                                double mean,
                                double standard_deviation,
                                double ratio,
                                double tilt,
-                               double rot_min,
-                               double rot_max,
+                               double rotation_variation,
                                gint _distrib )
 {
-
-
-
     bool did = false;
-
-    if (SP_IS_BOX3D(item) /*&& !is_transform_modes(mode)*/) {
+    
+    if (SP_IS_BOX3D(item) ) {
         // convert 3D boxes to ordinary groups before spraying their shapes
         item = SP_ITEM(box3d_convert_to_group(SP_BOX3D(item)));
         selection->add(item);
     }
 
-/*if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
-        GSList *items = g_slist_prepend (NULL, item);
-        GSList *selected = NULL;
-        GSList *to_select = NULL;
-        SPDocument *doc = SP_OBJECT_DOCUMENT(item);
-        sp_item_list_to_curves (items, &selected, &to_select);
-        g_slist_free (items);
-        SPObject* newObj = doc->getObjectByRepr((Inkscape::XML::Node *) to_select->data);
-        g_slist_free (to_select);
-        item = (SPItem *) newObj;
-      //  selection->add(item);
-    }
-*/
-   /*if (SP_IS_GROUP(item) && !SP_IS_BOX3D(item)) {
-        for (SPObject *child = sp_object_first_child(SP_OBJECT(item)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
-            if (SP_IS_ITEM(child)) {
-                if (sp_spray_dilate_recursive (desktop,selection, SP_ITEM(child), p, vector, mode, radius, force, population, scale, scale_min, scale_max, reverse, mean, standard_deviation,ratio,tilt, rot_min, rot_max,_distrib))
-                    did = true;
+    double _fid = g_random_double_range(0,1);
+    double angle = g_random_double_range( - rotation_variation / 100.0 * M_PI , rotation_variation / 100.0 * M_PI );
+    double _scale = g_random_double_range( 1.0 - scale_variation / 100.0, 1.0 + scale_variation / 100.0 );
+    double dr; double dp;
+    random_position(dr,dp,mean,standard_deviation,_distrib);
+    dr=dr*radius;
+
+    if (mode == SPRAY_MODE_COPY) {
+        Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item));
+        if (a) {
+            SPItem *item_copied;
+            if(_fid<=population)
+            {
+                // duplicate
+                SPDocument *doc = SP_OBJECT_DOCUMENT(item);
+                Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+                Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
+                Inkscape::XML::Node *parent = old_repr->parent();
+                Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+                parent->appendChild(copy);
+
+                SPObject *new_obj = doc->getObjectByRepr(copy);
+                item_copied = (SPItem *) new_obj;   //convertion object->item
+                Geom::Point center=item->getCenter();
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+
+                sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+                //Move the cursor p
+                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
+                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+                did = true;
             }
         }
+    } else if (mode == SPRAY_MODE_SINGLE_PATH) {
 
-    } else {*/
-        if (mode == SPRAY_MODE_COPY) {
-
-            Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item));
-            if (a) {
-                double dr; double dp;
-                random_position(dr,dp,mean,standard_deviation,_distrib);
-                dr=dr*radius;
-                double _fid = g_random_double_range(0,1);
-                SPItem *item_copied;
-                double angle = g_random_double_range(rot_min, rot_max);
-                double _scale = g_random_double_range(scale_min, scale_max);
-                if(_fid<=population)
-                {
-                          // duplicate
-                            SPDocument *doc = SP_OBJECT_DOCUMENT(item);
-                            Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
-                            Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
-                            Inkscape::XML::Node *parent = old_repr->parent();
-                            Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
-                            parent->appendChild(copy);
-
-                            SPObject *new_obj = doc->getObjectByRepr(copy);
-                            item_copied = (SPItem *) new_obj;   //convertion object->item
-                            Geom::Point center=item->getCenter();
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
-
-                            sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
-                            Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move the cursor p
-                            sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+        SPItem *father;         //initial Object
+        SPItem *item_copied;    //Projected Object
+        SPItem *unionResult;    //previous union
+        SPItem *son;            //father copy
 
+        int i=1;
+        for (GSList *items = g_slist_copy((GSList *) selection->itemList());
+                items != NULL;
+                items = items->next) {
 
-
-
-
-                        did = true;
-                        }
+            SPItem *item1 = (SPItem *) items->data;
+            if (i==1) {
+                father=item1;
             }
-
-        } else if (mode == SPRAY_MODE_SINGLE_PATH) {
-
-
-            SPItem *Pere; //Objet initial
-            SPItem *item_copied;//Objet projeté
-            SPItem *Union;//Union précédente
-            SPItem *fils;//Copie du père
-
-           // GSList *items = g_slist_copy((GSList *) selection->itemList()); //Récupère la liste des objects sélectionnés
-//Pere = (SPItem *) items->data;//Le premier objet est le père du spray
-
-            int i=1;
-            for (GSList *items = g_slist_copy((GSList *) selection->itemList());
-                    items != NULL;
-                    items = items->next) {
-
-                SPItem *item1 = (SPItem *) items->data;
-                if (i==1) {
-                    Pere=item1;
-                }
-                if (i==2) {
-                    Union=item1;
-                }
-                i++;
+            if (i==2) {
+                unionResult=item1;
             }
-            SPDocument *doc = SP_OBJECT_DOCUMENT(Pere);
-            Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
-            Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(Pere);
-            //SPObject *old_obj = doc->getObjectByRepr(old_repr);
-            Inkscape::XML::Node *parent = old_repr->parent();
-
-            Geom::OptRect a = Pere->getBounds(sp_item_i2doc_affine(Pere));
-            if (a) {
-                double dr; double dp; //initialisation des variables
-                random_position(dr,dp,mean,standard_deviation,_distrib);
-                dr=dr*radius;
-                double _fid = g_random_double_range(0,1);
-                double angle = (g_random_double_range(rot_min, rot_max));
-                double _scale = g_random_double_range(scale_min, scale_max);
-                if (i==2) {
-                    Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc);
-                    parent->appendChild(copy1);
-                    SPObject *new_obj1 = doc->getObjectByRepr(copy1);
-                    fils = (SPItem *) new_obj1;   //conversion object->item
-                    Union=fils;
-                    Inkscape::GC::release(copy1);
-                   }
-
-                if (_fid<=population) { //Rules the population of objects sprayed
-                    // duplicates the father
-                    Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc);
-                    parent->appendChild(copy2);
-                    SPObject *new_obj2 = doc->getObjectByRepr(copy2);
-                    item_copied = (SPItem *) new_obj2;
-
-                    Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move around the cursor
-
-                            Geom::Point center=Pere->getCenter();
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
-                            sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
-                            sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
-
-//UNION et surduplication
-                    selection->clear();
-                    selection->add(item_copied);
-                    selection->add(Union);
-                    sp_selected_path_union(selection->desktop());
-                    selection->add(Pere);
-                    Inkscape::GC::release(copy2);
-                    did = true;
-                }
+            i++;
+        }
+        SPDocument *doc = SP_OBJECT_DOCUMENT(father);
+        Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+        Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(father);
+        Inkscape::XML::Node *parent = old_repr->parent();
+
+        Geom::OptRect a = father->getBounds(sp_item_i2doc_affine(father));
+        if (a) {
+            if (i==2) {
+                Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc);
+                parent->appendChild(copy1);
+                SPObject *new_obj1 = doc->getObjectByRepr(copy1);
+                son = (SPItem *) new_obj1;   // conversion object->item
+                unionResult=son;
+                Inkscape::GC::release(copy1);
+               }
 
+            if (_fid<=population) { // Rules the population of objects sprayed
+                // duplicates the father
+                Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc);
+                parent->appendChild(copy2);
+                SPObject *new_obj2 = doc->getObjectByRepr(copy2);
+                item_copied = (SPItem *) new_obj2;
+
+                // Move around the cursor
+                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); 
+
+                Geom::Point center=father->getCenter();
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+                sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+
+                // union and duplication
+                selection->clear();
+                selection->add(item_copied);
+                selection->add(unionResult);
+                sp_selected_path_union(selection->desktop());
+                selection->add(father);
+                Inkscape::GC::release(copy2);
+                did = true;
             }
-        } else if (mode == SPRAY_MODE_CLONE) {
-
+        }
+    } else if (mode == SPRAY_MODE_CLONE) {
         Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item));
-                if (a) {
-                double dr; double dp;
-                random_position(dr,dp,mean,standard_deviation,_distrib);
-                dr=dr*radius;
-                double _fid = g_random_double_range(0,1);
-                double angle = (g_random_double_range(rot_min, rot_max));
-                double _scale = g_random_double_range(scale_min, scale_max);
-
-        if(_fid<=population)
-                {
-                            SPItem *item_copied;
-                            SPDocument *doc = SP_OBJECT_DOCUMENT(item);
-                            Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
-                            Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
-                            Inkscape::XML::Node *parent = old_repr->parent();
-
-                            //Creation of the clone
-                            Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
-                            parent->appendChild(clone); //Ajout du clone à la liste d'enfants du père (selection initiale
-                            clone->setAttribute("xlink:href", g_strdup_printf("#%s", old_repr->attribute("id")), false); //Génère le lien entre les attributs du père et du fils
-
-                            SPObject *clone_object = doc->getObjectByRepr(clone);
-                            item_copied = (SPItem *) clone_object;//conversion object->item
-                              Geom::Point center=item->getCenter();
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
-                            sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
-                            sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
-                            Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
-                            sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
-
-                            Inkscape::GC::release(clone);
-
-                            did = true;
-                } }}
-                return did;
+        if (a) {
+            if(_fid<=population) {
+                SPItem *item_copied;
+                SPDocument *doc = SP_OBJECT_DOCUMENT(item);
+                Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
+                Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item);
+                Inkscape::XML::Node *parent = old_repr->parent();
+
+                // Creation of the clone
+                Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
+                // Ad the clone to the list of the father's sons
+                parent->appendChild(clone);
+                // Generates the link between father and son attributes
+                clone->setAttribute("xlink:href", g_strdup_printf("#%s", old_repr->attribute("id")), false); 
+
+                SPObject *clone_object = doc->getObjectByRepr(clone);
+                // conversion object->item
+                item_copied = (SPItem *) clone_object;
+                Geom::Point center=item->getCenter();
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale));
+                sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale));
+                sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
+                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
+                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+
+                Inkscape::GC::release(clone);
 
+                did = true;
+            }
+        }
+    }
+
+    return did;
 }
 
 
@@ -751,23 +671,6 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p,
     guint32 stroke_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", false, &do_stroke);
     double opacity_goal = sp_desktop_get_master_opacity_tool(desktop, "/tools/spray", &do_opacity);
     if (reverse) {
-#if 0
-        // HSL inversion
-        float hsv[3];
-        float rgb[3];
-        sp_color_rgb_to_hsv_floatv (hsv,
-                                    SP_RGBA32_R_F(fill_goal),
-                                    SP_RGBA32_G_F(fill_goal),
-                                    SP_RGBA32_B_F(fill_goal));
-        sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]);
-        fill_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1);
-        sp_color_rgb_to_hsv_floatv (hsv,
-                                    SP_RGBA32_R_F(stroke_goal),
-                                    SP_RGBA32_G_F(stroke_goal),
-                                    SP_RGBA32_B_F(stroke_goal));
-        sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]);
-        stroke_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1);
-#else
         // RGB inversion
         fill_goal = SP_RGBA32_U_COMPOSE(
             (255 - SP_RGBA32_R_U(fill_goal)),
@@ -779,7 +682,6 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p,
             (255 - SP_RGBA32_G_U(stroke_goal)),
             (255 - SP_RGBA32_B_U(stroke_goal)),
             (255 - SP_RGBA32_A_U(stroke_goal)));
-#endif
         opacity_goal = 1 - opacity_goal;
     }
 
@@ -806,21 +708,11 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p,
 
         SPItem *item = (SPItem *) items->data;
 
-        /*if (is_color_modes (tc->mode)) {
-            if (do_fill || do_stroke || do_opacity) {
-                if (sp_spray_color_recursive (tc->mode, item, item_at_point,
-                                          fill_goal, do_fill,
-                                          stroke_goal, do_stroke,
-                                          opacity_goal, do_opacity,
-                                          tc->mode == SPRAY_MODE_BLUR, reverse,
-                                          p, radius, color_force, tc->do_h, tc->do_s, tc->do_l, tc->do_o))
-                did = true;
-            }
-        }else*/ if (is_transform_modes(tc->mode)) {
-            if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, move_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, move_mean, move_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib))
+        if (is_transform_modes(tc->mode)) {
+            if (sp_spray_recursive (desktop,selection, item, p, vector, tc->mode, radius, move_force, tc->population,tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation,tc->ratio,tc->tilt, tc->rotation_variation, tc->distrib))
                 did = true;
         } else {
-            if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, path_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, path_mean, path_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib))
+            if (sp_spray_recursive (desktop,selection, item, p, vector, tc->mode, radius, path_force, tc->population,tc->scale, tc->scale_variation, reverse, path_mean, path_standard_deviation,tc->ratio,tc->tilt, tc->rotation_variation, tc->distrib))
                 did = true;
         }
     }
index f8822ce39551506122e2d5438e247a9d3eb8d202..ab24342231f0fed9c052da2db45b5da634b08bf5 100644 (file)
@@ -71,12 +71,10 @@ struct SPSprayContext
     double width;
     double ratio;
     double tilt;
-    double rot_min;
-    double rot_max;
+    double rotation_variation;
     double force;
     double population;
-    double scale_min;
-    double scale_max;
+    double scale_variation;
     double scale;
     double mean;
     double standard_deviation;
index ff5a6c2d34ba2b4acc7ded68b0ce3a9675982ae2..7d43b68eef18d75c2e82c6f7d4e967ceb1f2ee95 100644 (file)
@@ -464,6 +464,7 @@ sp_svg_create_color_hash()
     return colors;
 }
 
+#if ENABLE_LCMS
 //helper function borrowed from src/widgets/sp-color-icc-selector.cpp:
 void getThings( DWORD space, gchar const**& namers, gchar const**& tippies, guint const*& scalies );
 
@@ -497,6 +498,7 @@ g_message("transform to sRGB done");
         }
     }
 }
+#endif //ENABLE_LCMS
 
 /*
  * Some discussion at http://markmail.org/message/bhfvdfptt25kgtmj
index b7cd278d4febfdf28b665b89629655843bcdb180..6b49dc44aa70a8f6cdaf41a0156202721ae833bc 100644 (file)
@@ -115,6 +115,7 @@ TransfMat3x4::pt_to_str (Proj::Axis axis) {
     return g_strdup(os.str().c_str());
 }
 
+/* Check for equality (with a small tolerance epsilon) */
 bool
 TransfMat3x4::operator==(const TransfMat3x4 &rhs) const
 {
@@ -129,29 +130,16 @@ TransfMat3x4::operator==(const TransfMat3x4 &rhs) const
     return true;
 }
 
-/* multiply a projective matrix by an affine matrix */
+/* Multiply a projective matrix by an affine matrix (by only multiplying the 'affine part' of the
+ * projective matrix) */
 TransfMat3x4
 TransfMat3x4::operator*(Geom::Matrix const &A) const {
     TransfMat3x4 ret;
 
-    // Is it safe to always use the currently active document?
-    double h = sp_document_height(inkscape_active_document());
-
-    /*
-     * Note: The strange multiplication involving the document height is due to the buggy
-     *       intertwining of SVG and document coordinates. Essentially, what we do is first
-     *       convert from "real-world" to SVG coordinates, then apply the transformation A
-     *       (by multiplying with the Geom::Matrix) and then convert back from SVG to real-world
-     *       coordinates. Maybe there is even a more Inkscape-ish way to achieve this?
-     *       Once Inkscape has gotton rid of the two different coordiate systems, we can change
-     *       this function to an ordinary matrix multiplication.
-     */
     for (int j = 0; j < 4; ++j) {
-        ret.tmat[0][j] = A[0]*tmat[0][j] + A[2]*(h*tmat[2][j] - tmat[1][j]) + A[4]*tmat[2][j];
-        ret.tmat[1][j] = A[1]*tmat[0][j] + A[3]*(h*tmat[2][j] - tmat[1][j]) + A[5]*tmat[2][j];
+        ret.tmat[0][j] = A[0]*tmat[0][j] + A[2]*tmat[1][j] + A[4]*tmat[2][j];
+        ret.tmat[1][j] = A[1]*tmat[0][j] + A[3]*tmat[1][j] + A[5]*tmat[2][j];
         ret.tmat[2][j] = tmat[2][j];
-
-        ret.tmat[1][j] = h*ret.tmat[2][j] - ret.tmat[1][j]; // switch back from SVG to desktop coordinates
     }
 
     return ret;
index 024d4b2f12dff91a762342732b72c57d1f586bde..2bba0a0f8e22d6c85cd3c401828d861d69c3a5ef 100644 (file)
@@ -705,14 +705,16 @@ private :
         {
             if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) {
                 Inkscape::Text::Layout const *layout = te_get_layout(*it);
-                Geom::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it);
-                if (base[Geom::X] < b_min[Geom::X]) b_min[Geom::X] = base[Geom::X];
-                if (base[Geom::Y] < b_min[Geom::Y]) b_min[Geom::Y] = base[Geom::Y];
-                if (base[Geom::X] > b_max[Geom::X]) b_max[Geom::X] = base[Geom::X];
-                if (base[Geom::Y] > b_max[Geom::Y]) b_max[Geom::Y] = base[Geom::Y];
-
-                Baselines b (*it, base, _orientation);
-                sorted.push_back(b);
+                boost::optional<Geom::Point> pt = layout->baselineAnchorPoint();
+                if (pt) {
+                    Geom::Point base = *pt * sp_item_i2d_affine(*it);
+                    if (base[Geom::X] < b_min[Geom::X]) b_min[Geom::X] = base[Geom::X];
+                    if (base[Geom::Y] < b_min[Geom::Y]) b_min[Geom::Y] = base[Geom::Y];
+                    if (base[Geom::X] > b_max[Geom::X]) b_max[Geom::X] = base[Geom::X];
+                    if (base[Geom::Y] > b_max[Geom::Y]) b_max[Geom::Y] = base[Geom::Y];
+                    Baselines b (*it, base, _orientation);
+                    sorted.push_back(b);
+                }
             }
         }
 
@@ -746,11 +748,14 @@ private :
             {
                 if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) {
                     Inkscape::Text::Layout const *layout = te_get_layout(*it);
-                    Geom::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it);
-                    Geom::Point t(0.0, 0.0);
-                    t[_orientation] = b_min[_orientation] - base[_orientation];
-                    sp_item_move_rel(*it, Geom::Translate(t));
-                    changed = true;
+                    boost::optional<Geom::Point> pt = layout->baselineAnchorPoint();
+                    if (pt) {
+                        Geom::Point base = *pt * sp_item_i2d_affine(*it);
+                        Geom::Point t(0.0, 0.0);
+                        t[_orientation] = b_min[_orientation] - base[_orientation];
+                        sp_item_move_rel(*it, Geom::Translate(t));
+                        changed = true;
+                    }
                 }
             }
 
index 982fb341536b8e07b9d1abbd4129fc4fc0f283f9..a7241ea405831e342b06dba912a205cb3382b350 100644 (file)
@@ -353,6 +353,7 @@ DocumentProperties::populate_available_profiles(){
                 while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) {
                     gchar* full = g_build_filename(it->c_str(), filename, NULL);
                     if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) {
+                        cmsErrorAction( LCMS_ERROR_SHOW );
                         cmsHPROFILE hProfile = cmsOpenProfileFromFile(full, "r");
                         if (hProfile != NULL){
                             const gchar* name;
index ab46b21a6c955ee8c69fead5af637fa15cad043d..78ceec4671178a2bf4fb33535d7f0137eeab7af4 100644 (file)
@@ -103,7 +103,7 @@ vp_knot_moved_handler (SPKnot */*knot*/, Geom::Point const *ppointer, guint stat
                 sel_boxes = (*vp)->selectedBoxes(sp_desktop_selection(inkscape_active_desktop()));
 
                 // we create a new perspective ...
-                Persp3D *new_persp = persp3d_create_xml_element (dragger->parent->document, old_persp);
+                Persp3D *new_persp = persp3d_create_xml_element (dragger->parent->document, old_persp->perspective_impl);
 
                 /* ... unlink the boxes from the old one and
                    FIXME: We need to unlink the _un_selected boxes of each VP so that
@@ -230,7 +230,7 @@ unsigned int VanishingPoint::global_counter = 0;
 void
 VanishingPoint::set_pos(Proj::Pt2 const &pt) {
     g_return_if_fail (_persp);
-    _persp->tmat.set_image_pt (_axis, pt);
+    _persp->perspective_impl->tmat.set_image_pt (_axis, pt);
 }
 
 std::list<SPBox3D *>
index 56b60d1206e678074bead2d82a6158e68fe220c6..3ba39dd30aae8e8854756450399962e97a01f48b 100644 (file)
@@ -374,8 +374,10 @@ void ColorNotebook::init()
        sp_set_font_size_smaller (rgbabox);
        gtk_widget_show_all (rgbabox);
 
+#if ENABLE_LCMS
         //the "too much ink" icon is initially hidden
         gtk_widget_hide(GTK_WIDGET(_box_toomuchink));
+#endif //ENABLE_LCMS
 
         gtk_table_attach (GTK_TABLE (table), rgbabox, 0, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD);
 
index 4362139464d0921768721fc4a5aef0d730ba076c..9fc0777785a0f3abb7d51bf10570d5bf1a9bcb87 100644 (file)
@@ -304,19 +304,19 @@ static gchar const * ui_descr =
         "    <toolitem action='TweakDoO' />"
         "  </toolbar>"
 
-  "  <toolbar name='SprayToolbar'>"
+        "  <toolbar name='SprayToolbar'>"
         "    <toolitem action='SprayModeAction' />"
         "    <separator />"
-        "    <toolitem action='SprayWidthAction' />"
         "    <separator />"
+        "    <toolitem action='SprayWidthAction' />"
         "    <toolitem action='SprayPressureAction' />"
-        "    <separator />"
         "    <toolitem action='SprayPopulationAction' />"
         "    <separator />"
-        "    <toolitem action='SprayMeanAction' />"
-        "    <toolitem action='SprayStandard_deviationAction' />"
+        "    <toolitem action='SprayRotationAction' />"
+        "    <toolitem action='SprayScaleAction' />"
         "    <separator />"
-        "    <toolitem action='DialogSprayOption' />"
+        "    <toolitem action='SprayStandard_deviationAction' />"
+        "    <toolitem action='SprayMeanAction' />"
         "  </toolbar>"
 
         "  <toolbar name='ZoomToolbar'>"
@@ -743,7 +743,6 @@ Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
         //SP_VERB_EDIT_TILE,
         //SP_VERB_EDIT_UNTILE,
         SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
-        SP_VERB_DIALOG_SPRAY_OPTION,
         SP_VERB_DIALOG_DISPLAY,
         SP_VERB_DIALOG_FILL_STROKE,
         SP_VERB_DIALOG_NAMEDVIEW,
@@ -926,11 +925,11 @@ sp_commands_toolbox_new()
 GtkWidget *
 sp_snap_toolbox_new()
 {
-       GtkWidget *tb = gtk_vbox_new(FALSE, 0);
-       gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
-       g_object_set_data(G_OBJECT(tb), "desktop", NULL);
+    GtkWidget *tb = gtk_vbox_new(FALSE, 0);
+    gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
+    g_object_set_data(G_OBJECT(tb), "desktop", NULL);
 
-       //GtkWidget *tb = gtk_toolbar_new();
+    //GtkWidget *tb = gtk_toolbar_new();
     //g_object_set_data(G_OBJECT(tb), "desktop", NULL);
 
     gtk_widget_set_sensitive(tb, FALSE);
@@ -1904,314 +1903,314 @@ update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/
 
 void toggle_snap_callback (GtkToggleAction *act, gpointer data) { //data points to the toolbox
 
-       if (g_object_get_data(G_OBJECT(data), "freeze" )) {
-               return;
-       }
-
-       gpointer ptr = g_object_get_data(G_OBJECT(data), "desktop");
-       g_assert(ptr != NULL);
-
-       SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr);
-       SPNamedView *nv = sp_desktop_namedview(dt);
-       SPDocument *doc = SP_OBJECT_DOCUMENT(nv);
-
-       if (dt == NULL || nv == NULL) {
-               g_warning("No desktop or namedview specified (in toggle_snap_callback)!");
-               return;
-       }
-
-       Inkscape::XML::Node *repr = SP_OBJECT_REPR(nv);
-
-       if (repr == NULL) {
-               g_warning("This namedview doesn't have a xml representation attached!");
-               return;
-       }
-
-       bool saved = sp_document_get_undo_sensitive(doc);
-       sp_document_set_undo_sensitive(doc, false);
-
-       bool v = false;
-       SPAttributeEnum attr = (SPAttributeEnum) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(act), "SP_ATTR_INKSCAPE"));
-
-       switch (attr) {
-       case SP_ATTR_INKSCAPE_SNAP_GLOBAL:
-               dt->toggleSnapGlobal();
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_BBOX:
-               v = nv->snap_manager.snapprefs.getSnapModeBBox();
-               sp_repr_set_boolean(repr, "inkscape:snap-bbox", !v);
-               break;
-       case SP_ATTR_INKSCAPE_BBOX_PATHS:
-               v = nv->snap_manager.snapprefs.getSnapToBBoxPath();
-               sp_repr_set_boolean(repr, "inkscape:bbox-paths", !v);
-               break;
-       case SP_ATTR_INKSCAPE_BBOX_NODES:
-               v = nv->snap_manager.snapprefs.getSnapToBBoxNode();
-               sp_repr_set_boolean(repr, "inkscape:bbox-nodes", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_NODES:
-               v = nv->snap_manager.snapprefs.getSnapModeNode();
-               sp_repr_set_boolean(repr, "inkscape:snap-nodes", !v);
-               break;
-       case SP_ATTR_INKSCAPE_OBJECT_PATHS:
-               v = nv->snap_manager.snapprefs.getSnapToItemPath();
-               sp_repr_set_boolean(repr, "inkscape:object-paths", !v);
-               break;
-       case SP_ATTR_INKSCAPE_OBJECT_NODES:
-               v = nv->snap_manager.snapprefs.getSnapToItemNode();
-               sp_repr_set_boolean(repr, "inkscape:object-nodes", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
-               v = nv->snap_manager.snapprefs.getSnapSmoothNodes();
-               sp_repr_set_boolean(repr, "inkscape:snap-smooth-nodes", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS:
-               v = nv->snap_manager.snapprefs.getSnapIntersectionCS();
-               sp_repr_set_boolean(repr, "inkscape:snap-intersection-paths", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_CENTER:
-               v = nv->snap_manager.snapprefs.getIncludeItemCenter();
-               sp_repr_set_boolean(repr, "inkscape:snap-center", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_GRIDS:
-               v = nv->snap_manager.snapprefs.getSnapToGrids();
-               sp_repr_set_boolean(repr, "inkscape:snap-grids", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_TO_GUIDES:
-               v = nv->snap_manager.snapprefs.getSnapToGuides();
-               sp_repr_set_boolean(repr, "inkscape:snap-to-guides", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_PAGE:
-               v = nv->snap_manager.snapprefs.getSnapToPageBorder();
-               sp_repr_set_boolean(repr, "inkscape:snap-page", !v);
-               break;
-       /*case SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE:
-               v = nv->snap_manager.snapprefs.getSnapIntersectionGG();
-               sp_repr_set_boolean(repr, "inkscape:snap-intersection-grid-guide", !v);
-               break;*/
-       case SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS:
-               v = nv->snap_manager.snapprefs.getSnapLineMidpoints();
-               sp_repr_set_boolean(repr, "inkscape:snap-midpoints", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS:
-               v = nv->snap_manager.snapprefs.getSnapObjectMidpoints();
-               sp_repr_set_boolean(repr, "inkscape:snap-object-midpoints", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS:
-               v = nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints();
-               sp_repr_set_boolean(repr, "inkscape:snap-bbox-edge-midpoints", !v);
-               break;
-       case SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS:
-               v = nv->snap_manager.snapprefs.getSnapBBoxMidpoints();
-               sp_repr_set_boolean(repr, "inkscape:snap-bbox-midpoints", !v);
-               break;
-       default:
-               g_warning("toggle_snap_callback has been called with an ID for which no action has been defined");
-               break;
-       }
-
-       // The snapping preferences are stored in the document, and therefore toggling makes the document dirty
-       doc->setModifiedSinceSave();
-
-       sp_document_set_undo_sensitive(doc, saved);
+    if (g_object_get_data(G_OBJECT(data), "freeze" )) {
+        return;
+    }
+
+    gpointer ptr = g_object_get_data(G_OBJECT(data), "desktop");
+    g_assert(ptr != NULL);
+
+    SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr);
+    SPNamedView *nv = sp_desktop_namedview(dt);
+    SPDocument *doc = SP_OBJECT_DOCUMENT(nv);
+
+    if (dt == NULL || nv == NULL) {
+        g_warning("No desktop or namedview specified (in toggle_snap_callback)!");
+        return;
+    }
+
+    Inkscape::XML::Node *repr = SP_OBJECT_REPR(nv);
+
+    if (repr == NULL) {
+        g_warning("This namedview doesn't have a xml representation attached!");
+        return;
+    }
+
+    bool saved = sp_document_get_undo_sensitive(doc);
+    sp_document_set_undo_sensitive(doc, false);
+
+    bool v = false;
+    SPAttributeEnum attr = (SPAttributeEnum) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(act), "SP_ATTR_INKSCAPE"));
+
+    switch (attr) {
+        case SP_ATTR_INKSCAPE_SNAP_GLOBAL:
+            dt->toggleSnapGlobal();
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_BBOX:
+            v = nv->snap_manager.snapprefs.getSnapModeBBox();
+            sp_repr_set_boolean(repr, "inkscape:snap-bbox", !v);
+            break;
+        case SP_ATTR_INKSCAPE_BBOX_PATHS:
+            v = nv->snap_manager.snapprefs.getSnapToBBoxPath();
+            sp_repr_set_boolean(repr, "inkscape:bbox-paths", !v);
+            break;
+        case SP_ATTR_INKSCAPE_BBOX_NODES:
+            v = nv->snap_manager.snapprefs.getSnapToBBoxNode();
+            sp_repr_set_boolean(repr, "inkscape:bbox-nodes", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_NODES:
+            v = nv->snap_manager.snapprefs.getSnapModeNode();
+            sp_repr_set_boolean(repr, "inkscape:snap-nodes", !v);
+            break;
+        case SP_ATTR_INKSCAPE_OBJECT_PATHS:
+            v = nv->snap_manager.snapprefs.getSnapToItemPath();
+            sp_repr_set_boolean(repr, "inkscape:object-paths", !v);
+            break;
+        case SP_ATTR_INKSCAPE_OBJECT_NODES:
+            v = nv->snap_manager.snapprefs.getSnapToItemNode();
+            sp_repr_set_boolean(repr, "inkscape:object-nodes", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
+            v = nv->snap_manager.snapprefs.getSnapSmoothNodes();
+            sp_repr_set_boolean(repr, "inkscape:snap-smooth-nodes", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS:
+            v = nv->snap_manager.snapprefs.getSnapIntersectionCS();
+            sp_repr_set_boolean(repr, "inkscape:snap-intersection-paths", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_CENTER:
+            v = nv->snap_manager.snapprefs.getIncludeItemCenter();
+            sp_repr_set_boolean(repr, "inkscape:snap-center", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_GRIDS:
+            v = nv->snap_manager.snapprefs.getSnapToGrids();
+            sp_repr_set_boolean(repr, "inkscape:snap-grids", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_TO_GUIDES:
+            v = nv->snap_manager.snapprefs.getSnapToGuides();
+            sp_repr_set_boolean(repr, "inkscape:snap-to-guides", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_PAGE:
+            v = nv->snap_manager.snapprefs.getSnapToPageBorder();
+            sp_repr_set_boolean(repr, "inkscape:snap-page", !v);
+            break;
+            /*case SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE:
+              v = nv->snap_manager.snapprefs.getSnapIntersectionGG();
+              sp_repr_set_boolean(repr, "inkscape:snap-intersection-grid-guide", !v);
+              break;*/
+        case SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS:
+            v = nv->snap_manager.snapprefs.getSnapLineMidpoints();
+            sp_repr_set_boolean(repr, "inkscape:snap-midpoints", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS:
+            v = nv->snap_manager.snapprefs.getSnapObjectMidpoints();
+            sp_repr_set_boolean(repr, "inkscape:snap-object-midpoints", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS:
+            v = nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints();
+            sp_repr_set_boolean(repr, "inkscape:snap-bbox-edge-midpoints", !v);
+            break;
+        case SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS:
+            v = nv->snap_manager.snapprefs.getSnapBBoxMidpoints();
+            sp_repr_set_boolean(repr, "inkscape:snap-bbox-midpoints", !v);
+            break;
+        default:
+            g_warning("toggle_snap_callback has been called with an ID for which no action has been defined");
+            break;
+    }
+
+    // The snapping preferences are stored in the document, and therefore toggling makes the document dirty
+    doc->setModifiedSinceSave();
+
+    sp_document_set_undo_sensitive(doc, saved);
 }
 
 void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 {
-       Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-       Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
-
-       gchar const * descr =
-               "<ui>"
-               "  <toolbar name='SnapToolbar'>"
-               "    <toolitem action='ToggleSnapGlobal' />"
-                       "    <separator />"
-                       "    <toolitem action='ToggleSnapFromBBoxCorner' />"
-                       "    <toolitem action='ToggleSnapToBBoxPath' />"
-                       "    <toolitem action='ToggleSnapToBBoxNode' />"
-                       "    <toolitem action='ToggleSnapToFromBBoxEdgeMidpoints' />"
-                       "    <toolitem action='ToggleSnapToFromBBoxCenters' />"
-                       "    <separator />"
-                       "    <toolitem action='ToggleSnapFromNode' />"
-                       "    <toolitem action='ToggleSnapToItemPath' />"
-                       "    <toolitem action='ToggleSnapToPathIntersections' />"
-                       "    <toolitem action='ToggleSnapToItemNode' />"
-                       "    <toolitem action='ToggleSnapToSmoothNodes' />"
-                       "    <toolitem action='ToggleSnapToFromLineMidpoints' />"
-                       "    <toolitem action='ToggleSnapToFromObjectCenters' />"
-                       "    <toolitem action='ToggleSnapToFromRotationCenter' />"
-                       "    <separator />"
-                       "    <toolitem action='ToggleSnapToPageBorder' />"
-                       "    <toolitem action='ToggleSnapToGrids' />"
-                       "    <toolitem action='ToggleSnapToGuides' />"
-                 //"    <toolitem action='ToggleSnapToGridGuideIntersections' />"
-                       "  </toolbar>"
-               "</ui>";
-
-       Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapGlobal",
-                   _("Snap"), _("Enable snapping"), INKSCAPE_ICON_SNAP, secondarySize,
-                   SP_ATTR_INKSCAPE_SNAP_GLOBAL);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromBBoxCorner",
-                   _("Bounding box"), _("Snap bounding box corners"), INKSCAPE_ICON_SNAP_BOUNDING_BOX,
-                   secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxPath",
-                   _("Bounding box edges"), _("Snap to edges of a bounding box"),
-                   INKSCAPE_ICON_SNAP_BOUNDING_BOX_EDGES, secondarySize, SP_ATTR_INKSCAPE_BBOX_PATHS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxNode",
-                   _("Bounding box corners"), _("Snap to bounding box corners"),
-                   INKSCAPE_ICON_SNAP_BOUNDING_BOX_CORNERS, secondarySize, SP_ATTR_INKSCAPE_BBOX_NODES);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxEdgeMidpoints",
-                   _("BBox Edge Midpoints"), _("Snap from and to midpoints of bounding box edges"),
-                   INKSCAPE_ICON_SNAP_BOUNDING_BOX_MIDPOINTS, secondarySize,
-                   SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxCenters",
-                   _("BBox Centers"), _("Snapping from and to centers of bounding boxes"),
-                   INKSCAPE_ICON_SNAP_BOUNDING_BOX_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromNode",
-                   _("Nodes"), _("Snap nodes or handles"), INKSCAPE_ICON_SNAP_NODES, secondarySize, SP_ATTR_INKSCAPE_SNAP_NODES);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemPath",
-                   _("Paths"), _("Snap to paths"), INKSCAPE_ICON_SNAP_NODES_PATH, secondarySize,
-                   SP_ATTR_INKSCAPE_OBJECT_PATHS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPathIntersections",
-                   _("Path intersections"), _("Snap to path intersections"),
-                   INKSCAPE_ICON_SNAP_NODES_INTERSECTION, secondarySize, SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemNode",
-                   _("To nodes"), _("Snap to cusp nodes"), INKSCAPE_ICON_SNAP_NODES_CUSP, secondarySize,
-                   SP_ATTR_INKSCAPE_OBJECT_NODES);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToSmoothNodes",
-                   _("Smooth nodes"), _("Snap to smooth nodes"), INKSCAPE_ICON_SNAP_NODES_SMOOTH,
-                   secondarySize, SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromLineMidpoints",
-                   _("Line Midpoints"), _("Snap from and to midpoints of line segments"),
-                   INKSCAPE_ICON_SNAP_NODES_MIDPOINT, secondarySize, SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromObjectCenters",
-                   _("Object Centers"), _("Snap from and to centers of objects"),
-                   INKSCAPE_ICON_SNAP_NODES_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromRotationCenter",
-                   _("Rotation Centers"), _("Snap from and to an item's rotation center"),
-                   INKSCAPE_ICON_SNAP_NODES_ROTATION_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_CENTER);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPageBorder",
-                   _("Page border"), _("Snap to the page border"), INKSCAPE_ICON_SNAP_PAGE,
-                   secondarySize, SP_ATTR_INKSCAPE_SNAP_PAGE);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGrids",
-                   _("Grids"), _("Snap to grids"), INKSCAPE_ICON_GRID_RECTANGULAR, secondarySize,
-                   SP_ATTR_INKSCAPE_SNAP_GRIDS);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       {
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGuides",
-                   _("Guides"), _("Snap to guides"), INKSCAPE_ICON_GUIDES, secondarySize,
-                   SP_ATTR_INKSCAPE_SNAP_TO_GUIDES);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }
-
-       /*{
-               InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGridGuideIntersections",
-                   _("Grid/guide intersections"), _("Snap to intersections of a grid with a guide"),
-                   INKSCAPE_ICON_SNAP_GRID_GUIDE_INTERSECTIONS, secondarySize,
-                   SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE);
-
-               gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
-               g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
-       }*/
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
+
+    gchar const * descr =
+        "<ui>"
+        "  <toolbar name='SnapToolbar'>"
+        "    <toolitem action='ToggleSnapGlobal' />"
+        "    <separator />"
+        "    <toolitem action='ToggleSnapFromBBoxCorner' />"
+        "    <toolitem action='ToggleSnapToBBoxPath' />"
+        "    <toolitem action='ToggleSnapToBBoxNode' />"
+        "    <toolitem action='ToggleSnapToFromBBoxEdgeMidpoints' />"
+        "    <toolitem action='ToggleSnapToFromBBoxCenters' />"
+        "    <separator />"
+        "    <toolitem action='ToggleSnapFromNode' />"
+        "    <toolitem action='ToggleSnapToItemPath' />"
+        "    <toolitem action='ToggleSnapToPathIntersections' />"
+        "    <toolitem action='ToggleSnapToItemNode' />"
+        "    <toolitem action='ToggleSnapToSmoothNodes' />"
+        "    <toolitem action='ToggleSnapToFromLineMidpoints' />"
+        "    <toolitem action='ToggleSnapToFromObjectCenters' />"
+        "    <toolitem action='ToggleSnapToFromRotationCenter' />"
+        "    <separator />"
+        "    <toolitem action='ToggleSnapToPageBorder' />"
+        "    <toolitem action='ToggleSnapToGrids' />"
+        "    <toolitem action='ToggleSnapToGuides' />"
+        //"    <toolitem action='ToggleSnapToGridGuideIntersections' />"
+        "  </toolbar>"
+        "</ui>";
+
+    Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapGlobal",
+                                                     _("Snap"), _("Enable snapping"), INKSCAPE_ICON_SNAP, secondarySize,
+                                                     SP_ATTR_INKSCAPE_SNAP_GLOBAL);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromBBoxCorner",
+                                                     _("Bounding box"), _("Snap bounding box corners"), INKSCAPE_ICON_SNAP_BOUNDING_BOX,
+                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxPath",
+                                                     _("Bounding box edges"), _("Snap to edges of a bounding box"),
+                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_EDGES, secondarySize, SP_ATTR_INKSCAPE_BBOX_PATHS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxNode",
+                                                     _("Bounding box corners"), _("Snap to bounding box corners"),
+                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_CORNERS, secondarySize, SP_ATTR_INKSCAPE_BBOX_NODES);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxEdgeMidpoints",
+                                                     _("BBox Edge Midpoints"), _("Snap from and to midpoints of bounding box edges"),
+                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_MIDPOINTS, secondarySize,
+                                                     SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxCenters",
+                                                     _("BBox Centers"), _("Snapping from and to centers of bounding boxes"),
+                                                     INKSCAPE_ICON_SNAP_BOUNDING_BOX_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromNode",
+                                                     _("Nodes"), _("Snap nodes or handles"), INKSCAPE_ICON_SNAP_NODES, secondarySize, SP_ATTR_INKSCAPE_SNAP_NODES);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemPath",
+                                                     _("Paths"), _("Snap to paths"), INKSCAPE_ICON_SNAP_NODES_PATH, secondarySize,
+                                                     SP_ATTR_INKSCAPE_OBJECT_PATHS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPathIntersections",
+                                                     _("Path intersections"), _("Snap to path intersections"),
+                                                     INKSCAPE_ICON_SNAP_NODES_INTERSECTION, secondarySize, SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemNode",
+                                                     _("To nodes"), _("Snap to cusp nodes"), INKSCAPE_ICON_SNAP_NODES_CUSP, secondarySize,
+                                                     SP_ATTR_INKSCAPE_OBJECT_NODES);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToSmoothNodes",
+                                                     _("Smooth nodes"), _("Snap to smooth nodes"), INKSCAPE_ICON_SNAP_NODES_SMOOTH,
+                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromLineMidpoints",
+                                                     _("Line Midpoints"), _("Snap from and to midpoints of line segments"),
+                                                     INKSCAPE_ICON_SNAP_NODES_MIDPOINT, secondarySize, SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromObjectCenters",
+                                                     _("Object Centers"), _("Snap from and to centers of objects"),
+                                                     INKSCAPE_ICON_SNAP_NODES_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromRotationCenter",
+                                                     _("Rotation Centers"), _("Snap from and to an item's rotation center"),
+                                                     INKSCAPE_ICON_SNAP_NODES_ROTATION_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_CENTER);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPageBorder",
+                                                     _("Page border"), _("Snap to the page border"), INKSCAPE_ICON_SNAP_PAGE,
+                                                     secondarySize, SP_ATTR_INKSCAPE_SNAP_PAGE);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGrids",
+                                                     _("Grids"), _("Snap to grids"), INKSCAPE_ICON_GRID_RECTANGULAR, secondarySize,
+                                                     SP_ATTR_INKSCAPE_SNAP_GRIDS);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    {
+        InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGuides",
+                                                     _("Guides"), _("Snap to guides"), INKSCAPE_ICON_GUIDES, secondarySize,
+                                                     SP_ATTR_INKSCAPE_SNAP_TO_GUIDES);
+
+        gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+    }
+
+    /*{
+      InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGridGuideIntersections",
+      _("Grid/guide intersections"), _("Snap to intersections of a grid with a guide"),
+      INKSCAPE_ICON_SNAP_GRID_GUIDE_INTERSECTIONS, secondarySize,
+      SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE);
+
+      gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
+      g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
+      }*/
 
     GtkUIManager* mgr = gtk_ui_manager_new();
     GError* errVal = 0;
@@ -2243,94 +2242,94 @@ void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 
 void update_snap_toolbox(SPDesktop *desktop, SPEventContext */*eventcontext*/, GtkWidget *toolbox)
 {
-       g_assert(desktop != NULL);
-       g_assert(toolbox != NULL);
-
-       SPNamedView *nv = sp_desktop_namedview(desktop);
-       if (nv == NULL) {
-               g_warning("Namedview cannot be retrieved (in update_snap_toolbox)!");
-               return;
-       }
-
-       Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
-
-       Glib::RefPtr<Gtk::Action> act1 = mainActions->get_action("ToggleSnapGlobal");
-       Glib::RefPtr<Gtk::Action> act2 = mainActions->get_action("ToggleSnapFromBBoxCorner");
-       Glib::RefPtr<Gtk::Action> act3 = mainActions->get_action("ToggleSnapToBBoxPath");
-       Glib::RefPtr<Gtk::Action> act4 = mainActions->get_action("ToggleSnapToBBoxNode");
-       Glib::RefPtr<Gtk::Action> act4b = mainActions->get_action("ToggleSnapToFromBBoxEdgeMidpoints");
-       Glib::RefPtr<Gtk::Action> act4c = mainActions->get_action("ToggleSnapToFromBBoxCenters");
-       Glib::RefPtr<Gtk::Action> act5 = mainActions->get_action("ToggleSnapFromNode");
-       Glib::RefPtr<Gtk::Action> act6 = mainActions->get_action("ToggleSnapToItemPath");
-       Glib::RefPtr<Gtk::Action> act6b = mainActions->get_action("ToggleSnapToPathIntersections");
-       Glib::RefPtr<Gtk::Action> act7 = mainActions->get_action("ToggleSnapToItemNode");
-       Glib::RefPtr<Gtk::Action> act8 = mainActions->get_action("ToggleSnapToSmoothNodes");
-       Glib::RefPtr<Gtk::Action> act9 = mainActions->get_action("ToggleSnapToFromLineMidpoints");
-       Glib::RefPtr<Gtk::Action> act10 = mainActions->get_action("ToggleSnapToFromObjectCenters");
-       Glib::RefPtr<Gtk::Action> act11 = mainActions->get_action("ToggleSnapToFromRotationCenter");
-       Glib::RefPtr<Gtk::Action> act12 = mainActions->get_action("ToggleSnapToPageBorder");
-       //Glib::RefPtr<Gtk::Action> act13 = mainActions->get_action("ToggleSnapToGridGuideIntersections");
-       Glib::RefPtr<Gtk::Action> act14 = mainActions->get_action("ToggleSnapToGrids");
-       Glib::RefPtr<Gtk::Action> act15 = mainActions->get_action("ToggleSnapToGuides");
-
-
-       if (!act1) {
-               return; // The snap actions haven't been defined yet (might be the case during startup)
-       }
-
-       // The ..._set_active calls below will toggle the buttons, but this shouldn't lead to
-       // changes in our document because we're only updating the UI;
-       // Setting the "freeze" parameter to true will block the code in toggle_snap_callback()
-       g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(TRUE));
-
-       bool const c1 = nv->snap_manager.snapprefs.getSnapEnabledGlobally();
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act1->gobj()), c1);
-
-       bool const c2 = nv->snap_manager.snapprefs.getSnapModeBBox();
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act2->gobj()), c2);
-       gtk_action_set_sensitive(GTK_ACTION(act2->gobj()), c1);
-
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act3->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxPath());
-       gtk_action_set_sensitive(GTK_ACTION(act3->gobj()), c1 && c2);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxNode());
-       gtk_action_set_sensitive(GTK_ACTION(act4->gobj()), c1 && c2);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4b->gobj()), nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints());
-       gtk_action_set_sensitive(GTK_ACTION(act4b->gobj()), c1 && c2);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4c->gobj()), nv->snap_manager.snapprefs.getSnapBBoxMidpoints());
-       gtk_action_set_sensitive(GTK_ACTION(act4c->gobj()), c1 && c2);
-
-       bool const c3 = nv->snap_manager.snapprefs.getSnapModeNode();
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act5->gobj()), c3);
-       gtk_action_set_sensitive(GTK_ACTION(act5->gobj()), c1);
-
-       bool const c4 = nv->snap_manager.snapprefs.getSnapToItemPath();
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6->gobj()), c4);
-       gtk_action_set_sensitive(GTK_ACTION(act6->gobj()), c1 && c3);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6b->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionCS());
-       gtk_action_set_sensitive(GTK_ACTION(act6b->gobj()), c1 && c3 && c4);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act7->gobj()), nv->snap_manager.snapprefs.getSnapToItemNode());
-       gtk_action_set_sensitive(GTK_ACTION(act7->gobj()), c1 && c3);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act8->gobj()), nv->snap_manager.snapprefs.getSnapSmoothNodes());
-       gtk_action_set_sensitive(GTK_ACTION(act8->gobj()), c1 && c3);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act9->gobj()), nv->snap_manager.snapprefs.getSnapLineMidpoints());
-       gtk_action_set_sensitive(GTK_ACTION(act9->gobj()), c1 && c3);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act10->gobj()), nv->snap_manager.snapprefs.getSnapObjectMidpoints());
-       gtk_action_set_sensitive(GTK_ACTION(act10->gobj()), c1 && c3);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act11->gobj()), nv->snap_manager.snapprefs.getIncludeItemCenter());
-       gtk_action_set_sensitive(GTK_ACTION(act11->gobj()), c1 && c3);
-
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act12->gobj()), nv->snap_manager.snapprefs.getSnapToPageBorder());
-       gtk_action_set_sensitive(GTK_ACTION(act12->gobj()), c1);
-       //gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act13->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionGG());
-       //gtk_action_set_sensitive(GTK_ACTION(act13->gobj()), c1);
-
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act14->gobj()), nv->snap_manager.snapprefs.getSnapToGrids());
-       gtk_action_set_sensitive(GTK_ACTION(act14->gobj()), c1);
-       gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act15->gobj()), nv->snap_manager.snapprefs.getSnapToGuides());
-       gtk_action_set_sensitive(GTK_ACTION(act15->gobj()), c1);
-
-
-       g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(FALSE)); // unfreeze (see above)
+    g_assert(desktop != NULL);
+    g_assert(toolbox != NULL);
+
+    SPNamedView *nv = sp_desktop_namedview(desktop);
+    if (nv == NULL) {
+        g_warning("Namedview cannot be retrieved (in update_snap_toolbox)!");
+        return;
+    }
+
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
+
+    Glib::RefPtr<Gtk::Action> act1 = mainActions->get_action("ToggleSnapGlobal");
+    Glib::RefPtr<Gtk::Action> act2 = mainActions->get_action("ToggleSnapFromBBoxCorner");
+    Glib::RefPtr<Gtk::Action> act3 = mainActions->get_action("ToggleSnapToBBoxPath");
+    Glib::RefPtr<Gtk::Action> act4 = mainActions->get_action("ToggleSnapToBBoxNode");
+    Glib::RefPtr<Gtk::Action> act4b = mainActions->get_action("ToggleSnapToFromBBoxEdgeMidpoints");
+    Glib::RefPtr<Gtk::Action> act4c = mainActions->get_action("ToggleSnapToFromBBoxCenters");
+    Glib::RefPtr<Gtk::Action> act5 = mainActions->get_action("ToggleSnapFromNode");
+    Glib::RefPtr<Gtk::Action> act6 = mainActions->get_action("ToggleSnapToItemPath");
+    Glib::RefPtr<Gtk::Action> act6b = mainActions->get_action("ToggleSnapToPathIntersections");
+    Glib::RefPtr<Gtk::Action> act7 = mainActions->get_action("ToggleSnapToItemNode");
+    Glib::RefPtr<Gtk::Action> act8 = mainActions->get_action("ToggleSnapToSmoothNodes");
+    Glib::RefPtr<Gtk::Action> act9 = mainActions->get_action("ToggleSnapToFromLineMidpoints");
+    Glib::RefPtr<Gtk::Action> act10 = mainActions->get_action("ToggleSnapToFromObjectCenters");
+    Glib::RefPtr<Gtk::Action> act11 = mainActions->get_action("ToggleSnapToFromRotationCenter");
+    Glib::RefPtr<Gtk::Action> act12 = mainActions->get_action("ToggleSnapToPageBorder");
+    //Glib::RefPtr<Gtk::Action> act13 = mainActions->get_action("ToggleSnapToGridGuideIntersections");
+    Glib::RefPtr<Gtk::Action> act14 = mainActions->get_action("ToggleSnapToGrids");
+    Glib::RefPtr<Gtk::Action> act15 = mainActions->get_action("ToggleSnapToGuides");
+
+
+    if (!act1) {
+        return; // The snap actions haven't been defined yet (might be the case during startup)
+    }
+
+    // The ..._set_active calls below will toggle the buttons, but this shouldn't lead to
+    // changes in our document because we're only updating the UI;
+    // Setting the "freeze" parameter to true will block the code in toggle_snap_callback()
+    g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(TRUE));
+
+    bool const c1 = nv->snap_manager.snapprefs.getSnapEnabledGlobally();
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act1->gobj()), c1);
+
+    bool const c2 = nv->snap_manager.snapprefs.getSnapModeBBox();
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act2->gobj()), c2);
+    gtk_action_set_sensitive(GTK_ACTION(act2->gobj()), c1);
+
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act3->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxPath());
+    gtk_action_set_sensitive(GTK_ACTION(act3->gobj()), c1 && c2);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxNode());
+    gtk_action_set_sensitive(GTK_ACTION(act4->gobj()), c1 && c2);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4b->gobj()), nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints());
+    gtk_action_set_sensitive(GTK_ACTION(act4b->gobj()), c1 && c2);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4c->gobj()), nv->snap_manager.snapprefs.getSnapBBoxMidpoints());
+    gtk_action_set_sensitive(GTK_ACTION(act4c->gobj()), c1 && c2);
+
+    bool const c3 = nv->snap_manager.snapprefs.getSnapModeNode();
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act5->gobj()), c3);
+    gtk_action_set_sensitive(GTK_ACTION(act5->gobj()), c1);
+
+    bool const c4 = nv->snap_manager.snapprefs.getSnapToItemPath();
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6->gobj()), c4);
+    gtk_action_set_sensitive(GTK_ACTION(act6->gobj()), c1 && c3);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6b->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionCS());
+    gtk_action_set_sensitive(GTK_ACTION(act6b->gobj()), c1 && c3 && c4);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act7->gobj()), nv->snap_manager.snapprefs.getSnapToItemNode());
+    gtk_action_set_sensitive(GTK_ACTION(act7->gobj()), c1 && c3);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act8->gobj()), nv->snap_manager.snapprefs.getSnapSmoothNodes());
+    gtk_action_set_sensitive(GTK_ACTION(act8->gobj()), c1 && c3);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act9->gobj()), nv->snap_manager.snapprefs.getSnapLineMidpoints());
+    gtk_action_set_sensitive(GTK_ACTION(act9->gobj()), c1 && c3);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act10->gobj()), nv->snap_manager.snapprefs.getSnapObjectMidpoints());
+    gtk_action_set_sensitive(GTK_ACTION(act10->gobj()), c1 && c3);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act11->gobj()), nv->snap_manager.snapprefs.getIncludeItemCenter());
+    gtk_action_set_sensitive(GTK_ACTION(act11->gobj()), c1 && c3);
+
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act12->gobj()), nv->snap_manager.snapprefs.getSnapToPageBorder());
+    gtk_action_set_sensitive(GTK_ACTION(act12->gobj()), c1);
+    //gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act13->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionGG());
+    //gtk_action_set_sensitive(GTK_ACTION(act13->gobj()), c1);
+
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act14->gobj()), nv->snap_manager.snapprefs.getSnapToGrids());
+    gtk_action_set_sensitive(GTK_ACTION(act14->gobj()), c1);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act15->gobj()), nv->snap_manager.snapprefs.getSnapToGuides());
+    gtk_action_set_sensitive(GTK_ACTION(act15->gobj()), c1);
+
+
+    g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(FALSE)); // unfreeze (see above)
 }
 
 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
@@ -2412,8 +2411,8 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl
 
     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
         if (!IS_NAN(adj->value)) {
-                       Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-                       prefs->setDouble("/tools/shapes/star/proportion", adj->value);
+            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+            prefs->setDouble("/tools/shapes/star/proportion", adj->value);
         }
     }
 
@@ -3226,7 +3225,7 @@ box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
     // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
     //       have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
     //       are reset).
-    bool is_infinite = !persp3d_VP_is_finite(persp, axis);
+    bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis);
 
     if (is_infinite) {
         gtk_toggle_action_set_active(tact, TRUE);
@@ -3254,6 +3253,10 @@ box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
     GtkAction *act = 0;
     GtkToggleAction *tact = 0;
     Persp3D *persp = persp3d_get_from_repr(persp_repr);
+    if (!persp) {
+        // Hmm, is it an error if this happens?
+        return;
+    }
     {
         adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
         act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
@@ -3340,7 +3343,7 @@ box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
             sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
         }
 
-        inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
+        inkscape_active_document()->setCurrentPersp3D(persp3d_get_from_repr(persp_repr));
         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
         prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id"));
 
@@ -3364,7 +3367,6 @@ box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis ax
     // in turn, prevent listener from responding
     g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
 
-    //Persp3D *persp = document->current_persp3d;
     std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList();
     if (sel_persps.empty()) {
         // this can happen when the document is created; we silently ignore it
@@ -3372,7 +3374,7 @@ box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis ax
     }
     Persp3D *persp = sel_persps.front();
 
-    persp->tmat.set_infinite_direction (axis, adj->value);
+    persp->perspective_impl->tmat.set_infinite_direction (axis, adj->value);
     SP_OBJECT(persp)->updateRepr();
 
     // TODO: use the correct axis here, too
@@ -3435,7 +3437,7 @@ static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions,
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     EgeAdjustmentAction* eact = 0;
     SPDocument *document = sp_desktop_document (desktop);
-    Persp3D *persp = document->current_persp3d;
+    Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl();
 
     EgeAdjustmentAction* box3d_angle_x = 0;
     EgeAdjustmentAction* box3d_angle_y = 0;
@@ -3459,7 +3461,7 @@ static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions,
         box3d_angle_x = eact;
     }
 
-    if (!persp3d_VP_is_finite(persp, Proj::X)) {
+    if (!persp3d_VP_is_finite(persp_impl, Proj::X)) {
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     } else {
         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
@@ -3499,7 +3501,7 @@ static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions,
         box3d_angle_y = eact;
     }
 
-    if (!persp3d_VP_is_finite(persp, Proj::Y)) {
+    if (!persp3d_VP_is_finite(persp_impl, Proj::Y)) {
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     } else {
         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
@@ -3538,7 +3540,7 @@ static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions,
         box3d_angle_z = eact;
     }
 
-    if (!persp3d_VP_is_finite(persp, Proj::Z)) {
+    if (!persp3d_VP_is_finite(persp_impl, Proj::Z)) {
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     } else {
         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
@@ -3988,6 +3990,7 @@ sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
 }
 
+/*
 class PencilToleranceObserver : public Inkscape::Preferences::Observer {
 public:
     PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x)
@@ -3996,7 +3999,7 @@ public:
     }
     virtual ~PencilToleranceObserver() {
         if (g_object_get_data(_obj, "prefobserver") == this) {
-               g_object_set_data(_obj, "prefobserver", NULL);
+            g_object_set_data(_obj, "prefobserver", NULL);
         }
     }
     virtual void notify(Inkscape::Preferences::Entry const &val) {
@@ -4015,7 +4018,7 @@ public:
 private:
     GObject *_obj;
 };
-
+*/
 
 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 {
@@ -4040,9 +4043,6 @@ static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
                                          1, 2);
         ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
-
-        PencilToleranceObserver *obs =
-            new PencilToleranceObserver("/tools/freehand/pencil/tolerance", G_OBJECT(holder));
     }
 
     /* advanced shape options */
@@ -4408,14 +4408,6 @@ static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
     prefs->setDouble( "/tools/spray/width", adj->value );
 }
 
-/*
-static void sp_spray_force_value_changed( GtkAdjustment * / *adj* /, GObject * / *tbl* / )
-{
-    //Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    //prefs->setDouble( "/tools/spray/force", adj->value * 0.01 );
-}
-*/
-
 static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
 {
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -4447,23 +4439,19 @@ static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject */*tb
     prefs->setDouble( "/tools/spray/population", adj->value );
 }
 
-/*static void spray_toggle_doh (GtkToggleAction *act, gpointer ) {
-    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    prefs->setBool("/tools/spray/doh", gtk_toggle_action_get_active(act));
-}
-static void spray_toggle_dos (GtkToggleAction *act, gpointer ) {
-    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    prefs->setBool("/tools/spray/dos", gtk_toggle_action_get_active(act));
-}
-static void spray_toggle_dol (GtkToggleAction *act, gpointer ) {
+static void sp_spray_rotation_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
+{
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    prefs->setBool("/tools/spray/dol", gtk_toggle_action_get_active(act));
+    prefs->setDouble( "/tools/spray/rotation_variation", adj->value );
 }
-static void spray_toggle_doo (GtkToggleAction *act, gpointer ) {
+
+static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
+{
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    prefs->setBool("/tools/spray/doo", gtk_toggle_action_get_active(act));
+    prefs->setDouble( "/tools/spray/scale_variation", adj->value );
 }
-*/
+
+
 static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 {
     Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
@@ -4490,10 +4478,10 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
         gchar const* labels[] = {_("(minimum mean)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum mean)")};
         gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
         EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction",
-                                                              _("Mean"), _("Mean:"), _("The mean of the spray action"),
-                                                              "/tools/spray/mean", 20,
+                                                              _("Focus"), _("Focus:"), _("0 to spray a spot. Increase to enlarge the ring radius."),
+                                                              "/tools/spray/mean", 0,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean",
-                                                              1, 100, 1.0, 10.0,
+                                                              0, 100, 1.0, 10.0,
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_spray_mean_value_changed,  1, 0 );
         ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
@@ -4503,11 +4491,11 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
 
     {
         /* Standard_deviation */
-        gchar const* labels[] = {_("(minimum standard_deviation)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum standard_deviation)")};
+        gchar const* labels[] = {_("(minimum scatter)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum scatter)")};
         gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
         EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction",
-                                                              _("SD"), _("SD:"), _("The standard deviation of the spray action"),
-                                                              "/tools/spray/standard_deviation", 20,
+                                                              _("Scatter"), _("Scatter:"), _("Increase to scatter sprayed objects."),
+                                                              "/tools/spray/standard_deviation", 70,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation",
                                                               1, 100, 1.0, 10.0,
                                                               labels, values, G_N_ELEMENTS(labels),
@@ -4555,7 +4543,7 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
         ege_select_one_action_set_icon_size( act, secondarySize );
         ege_select_one_action_set_tooltip_column( act, 1  );
 
-        gint mode = prefs->getInt("/tools/spray/mode", 0);
+        gint mode = prefs->getInt("/tools/spray/mode", 1);
         ege_select_one_action_set_active( act, mode );
         g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder );
 
@@ -4566,9 +4554,9 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
         gchar const* labels[] = {_("(low population)"), 0, 0, _("(default)"), 0, 0, _("(high population)")};
         gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
         EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction",
-                                                              _("Population"), _("Population:"),
-                                                              _("This setting adjusts the number of items sprayed"),
-                                                              "/tools/spray/population", 50,
+                                                              _("Amount"), _("Amount:"),
+                                                              _("Adjusts the number of items sprayed per clic."),
+                                                              "/tools/spray/population", 70,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population",
                                                               1, 100, 1.0, 10.0,
                                                               labels, values, G_N_ELEMENTS(labels),
@@ -4582,13 +4570,48 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
     {
         InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction",
                                                       _("Pressure"),
-                                                      _("Use the pressure of the input device to alter the force of spray action"),
+                                                      _("Use the pressure of the input device to alter the amount of sprayed objects."),
                                                       "use_pressure",
                                                       Inkscape::ICON_SIZE_DECORATION );
         gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
         g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_spray_pressure_state_changed), NULL);
         gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressure", true) );
     }
+
+    {   /* Rotation */
+        gchar const* labels[] = {_("(low rotation variation)"), 0, 0, _("(default)"), 0, 0, _("(high rotation variation)")};
+        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
+        EgeAdjustmentAction *eact = create_adjustment_action( "SprayRotationAction",
+                                                              _("Rotation"), _("Rotation:"),
+                                                              _("Variation of the rotation of the sprayed objects. 0% for the same rotation than the original object."),
+                                                              "/tools/spray/rotation_variation", 0,
+                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-rotation",
+                                                              0, 100, 1.0, 10.0,
+                                                              labels, values, G_N_ELEMENTS(labels),
+                                                              sp_spray_rotation_value_changed,  1, 0 );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+        g_object_set_data( holder, "spray_rotation", eact );
+    }
+
+    {   /* Scale */
+        gchar const* labels[] = {_("(low scale variation)"), 0, 0, _("(default)"), 0, 0, _("(high scale variation)")};
+        gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
+        EgeAdjustmentAction *eact = create_adjustment_action( "SprayScaleAction",
+                                                              _("Scale"), _("Scale:"),
+                                                              _("Variation in the scale of the sprayed objects. 0% for the same scale than the original object."),
+                                                              "/tools/spray/scale_variation", 0,
+                                                              GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-scale",
+                                                              0, 100, 1.0, 10.0,
+                                                              labels, values, G_N_ELEMENTS(labels),
+                                                              sp_spray_scale_value_changed,  1, 0 );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+        g_object_set_data( holder, "spray_scale", eact );
+    }
+
+
+
 }
 
 
@@ -4639,9 +4662,9 @@ static void update_presets_list (GObject *tbl)
                     }
                 }
             }
-       }
+        }
 
-       if (match) {
+        if (match) {
             // newly added item is at the same index as the
             // save command, so we need to change twice for it to take effect
             ege_select_one_action_set_active(sel, 0);
@@ -4770,7 +4793,7 @@ static void sp_dcc_build_presets_list(GObject *tbl)
     int ii=1;
 
     for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) {
-       GtkTreeIter iter;
+        GtkTreeIter iter;
         Glib::ustring preset_name = prefs->getString(*i + "/name");
         gtk_list_store_append( model, &iter );
         gtk_list_store_set( model, &iter, 0, _(preset_name.data()), 1, ii++, -1 );
@@ -4822,12 +4845,12 @@ static void sp_dcc_save_profile (GtkWidget */*widget*/, GObject *tbl)
 
     int temp_index = 0;
     for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) {
-       Glib::ustring name = prefs->getString(*i + "/name");
-       if (!name.empty() && profile_name == name) {
-           new_index = temp_index;
+        Glib::ustring name = prefs->getString(*i + "/name");
+        if (!name.empty() && profile_name == name) {
+            new_index = temp_index;
             save_path = *i;
             break;
-       }
+        }
     }
 
     if (new_index == -1) {
@@ -6065,9 +6088,9 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *
     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
         // there are no texts in selection, read from prefs
 
-           sp_style_read_from_prefs(query, "/tools/text");
+        sp_style_read_from_prefs(query, "/tools/text");
 
-           if (g_object_get_data(tbl, "text_style_from_prefs")) {
+        if (g_object_get_data(tbl, "text_style_from_prefs")) {
             // do not reset the toolbar style from prefs if we already did it last time
             sp_style_unref(query);
             g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
@@ -6218,7 +6241,7 @@ sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flag
 }
 
 void
-sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
+sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl)
 {
     sp_text_toolbox_selection_changed (NULL, tbl);
 }
@@ -6344,8 +6367,85 @@ sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
     int prop = GPOINTER_TO_INT(data);
 
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-    SPCSSAttr *css = sp_repr_css_attr_new ();
 
+    // move the x of all texts to preserve the same bbox
+    Inkscape::Selection *selection = sp_desktop_selection(desktop);
+    for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
+        if (SP_IS_TEXT((SPItem *) items->data)) {
+            SPItem *item = SP_ITEM(items->data);
+
+            unsigned writing_mode = SP_OBJECT_STYLE(item)->writing_mode.value;
+            // below, variable names suggest horizontal move, but we check the writing direction
+            // and move in the corresponding axis
+            int axis;
+            if (writing_mode == SP_CSS_WRITING_MODE_LR_TB || writing_mode == SP_CSS_WRITING_MODE_RL_TB) {
+                axis = NR::X;
+            } else {
+                axis = NR::Y;
+            }
+
+            Geom::OptRect bbox
+                  = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
+            if (!bbox)
+                continue;
+            double width = bbox->dimensions()[axis];
+            // If you want to align within some frame, other than the text's own bbox, calculate
+            // the left and right (or top and bottom for tb text) slacks of the text inside that
+            // frame (currently unused)
+            double left_slack = 0;
+            double right_slack = 0;
+            unsigned old_align = SP_OBJECT_STYLE(item)->text_align.value;
+            double move = 0;
+            if (old_align == SP_CSS_TEXT_ALIGN_START || old_align == SP_CSS_TEXT_ALIGN_LEFT) {
+                switch (prop) {
+                    case 0:
+                        move = -left_slack;
+                        break;
+                    case 1:
+                        move = width/2 + (right_slack - left_slack)/2;
+                        break;
+                    case 2:
+                        move = width + right_slack;
+                        break;
+                }
+            } else if (old_align == SP_CSS_TEXT_ALIGN_CENTER) {
+                switch (prop) {
+                    case 0:
+                        move = -width/2 - left_slack;
+                        break;
+                    case 1:
+                        move = (right_slack - left_slack)/2;
+                        break;
+                    case 2:
+                        move = width/2 + right_slack;
+                        break;
+                }
+            } else if (old_align == SP_CSS_TEXT_ALIGN_END || old_align == SP_CSS_TEXT_ALIGN_RIGHT) {
+                switch (prop) {
+                    case 0:
+                        move = -width - left_slack;
+                        break;
+                    case 1:
+                        move = -width/2 + (right_slack - left_slack)/2;
+                        break;
+                    case 2:
+                        move = right_slack;
+                        break;
+                }
+            }
+            Geom::Point XY = SP_TEXT(item)->attributes.firstXY();
+            if (axis == NR::X) {
+                XY = XY + Geom::Point (move, 0);
+            } else {
+                XY = XY + Geom::Point (0, move);
+            }
+            SP_TEXT(item)->attributes.setFirstXY(XY);
+            SP_OBJECT(item)->updateRepr();
+            SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        }
+    }
+
+    SPCSSAttr *css = sp_repr_css_attr_new ();
     switch (prop)
     {
         case 0:
@@ -6384,8 +6484,8 @@ sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
     if (result_numbers == QUERY_STYLE_NOTHING)
     {
-       Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-       prefs->mergeStyle("/tools/text/style", css);
+        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+        prefs->mergeStyle("/tools/text/style", css);
     }
 
     sp_style_unref(query);
@@ -6488,8 +6588,8 @@ sp_text_toolbox_style_toggled (GtkToggleButton  *button,
     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
     if (result_fontspec == QUERY_STYLE_NOTHING)
     {
-       Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-       prefs->mergeStyle("/tools/text/style", css);
+        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+        prefs->mergeStyle("/tools/text/style", css);
     }
 
     sp_style_unref(query);
@@ -6538,7 +6638,7 @@ sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
     if (result_numbers == QUERY_STYLE_NOTHING)
     {
         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-       prefs->mergeStyle("/tools/text/style", css);
+        prefs->mergeStyle("/tools/text/style", css);
     }
 
     sp_desktop_set_style (desktop, css, true, true);
@@ -6650,7 +6750,7 @@ sp_text_toolbox_size_changed  (GtkComboBox *cbox,
     if (result_numbers == QUERY_STYLE_NOTHING)
     {
         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-       prefs->mergeStyle("/tools/text/style", css);
+        prefs->mergeStyle("/tools/text/style", css);
     }
 
     sp_style_unref(query);