Code

Connector tool: make connectors avoid the convex hull of shapes.
[inkscape.git] / src / selection-chemistry.cpp
index a57e5cfebd5a5d08f6a9edae863210e5d5c92bbd..31e899d8a34c703866ae9dbc40c6b51244fdb8dc 100644 (file)
@@ -27,6 +27,7 @@
 #include "svg/svg.h"
 #include "desktop.h"
 #include "desktop-style.h"
+#include "dir-util.h"
 #include "selection.h"
 #include "tools-switch.h"
 #include "desktop-handles.h"
@@ -52,6 +53,7 @@
 #include <libnr/nr-matrix-ops.h>
 #include <2geom/transforms.h>
 #include "xml/repr.h"
+#include "xml/rebase-hrefs.h"
 #include "style.h"
 #include "document-private.h"
 #include "sp-gradient.h"
@@ -74,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"
@@ -728,7 +731,9 @@ sp_selection_raise(SPDesktop *desktop)
     }
 
     sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_RAISE,
-                     //TRANSLATORS: Only put the word "Raise" in the translation. Means "to raise an object" in the undo history
+                     //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
                      Q_("undo_action|Raise"));
 }
 
@@ -1167,18 +1172,40 @@ 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
 that case, items are already in the new position, but the repr is in the old, and this function
 then simply updates the repr from item->transform.
  */
-void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix const &affine, bool set_i2d)
+void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix const &affine, bool set_i2d, bool compensate)
 {
     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);
 
@@ -1238,7 +1265,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons
                     continue;
                 for (SPObject *use = region->firstChild() ; use ; use = SP_OBJECT_NEXT(use)) {
                     if (!SP_IS_USE(use)) continue;
-                    sp_item_write_transform(SP_USE(use), SP_OBJECT_REPR(use), item->transform.inverse(), NULL);
+                    sp_item_write_transform(SP_USE(use), SP_OBJECT_REPR(use), item->transform.inverse(), NULL, compensate);
                 }
             }
         } else if (transform_clone_with_original) {
@@ -1264,30 +1291,30 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons
 
                 if (prefs_parallel) {
                     Geom::Matrix move = result * clone_move * t_inv;
-                    sp_item_write_transform(item, SP_OBJECT_REPR(item), move, &move);
+                    sp_item_write_transform(item, SP_OBJECT_REPR(item), move, &move, compensate);
 
                 } else if (prefs_unmoved) {
                     //if (SP_IS_USE(sp_use_get_original(SP_USE(item))))
                     //    clone_move = Geom::identity();
                     Geom::Matrix move = result * clone_move;
-                    sp_item_write_transform(item, SP_OBJECT_REPR(item), move, &t);
+                    sp_item_write_transform(item, SP_OBJECT_REPR(item), move, &t, compensate);
                 }
 
             } else {
                 // just apply the result
-                sp_item_write_transform(item, SP_OBJECT_REPR(item), result, &t);
+                sp_item_write_transform(item, SP_OBJECT_REPR(item), result, &t, compensate);
             }
 
         } else {
             if (set_i2d) {
                 sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * (Geom::Matrix)affine);
             }
-            sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform, NULL);
+            sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform, NULL, compensate);
         }
 
         // if we're moving the actual object, not just updating the repr, we can transform the
         // center by the same matrix (only necessary for non-translations)
-        if (set_i2d && item->isCenterSet() && !affine.isTranslation()) {
+        if (set_i2d && item->isCenterSet() && !(affine.isTranslation() || affine.isIdentity())) {
             item->setCenter(old_center * affine);
             SP_OBJECT(item)->updateRepr();
         }
@@ -1382,9 +1409,9 @@ sp_selection_skew_relative(Inkscape::Selection *selection, Geom::Point const &al
     sp_selection_apply_affine(selection, final);
 }
 
-void sp_selection_move_relative(Inkscape::Selection *selection, Geom::Point const &move)
+void sp_selection_move_relative(Inkscape::Selection *selection, Geom::Point const &move, bool compensate)
 {
-    sp_selection_apply_affine(selection, Geom::Matrix(Geom::Translate(move)));
+    sp_selection_apply_affine(selection, Geom::Matrix(Geom::Translate(move)), true, compensate);
 }
 
 void sp_selection_move_relative(Inkscape::Selection *selection, double dx, double dy)
@@ -2634,8 +2661,12 @@ sp_selection_create_bitmap_copy(SPDesktop *desktop)
     if (pb) {
         // Create the repr for the image
         Inkscape::XML::Node * repr = xml_doc->createElement("svg:image");
-        repr->setAttribute("xlink:href", basename);
-        repr->setAttribute("sodipodi:absref", filepath);
+        {
+            repr->setAttribute("sodipodi:absref", filepath);
+            gchar *abs_base = Inkscape::XML::calc_abs_doc_base(document->base);
+            repr->setAttribute("xlink:href", sp_relative_path_from_path(filepath, abs_base));
+            g_free(abs_base);
+        }
         if (res == PX_PER_IN) { // for default 90 dpi, snap it to pixel grid
             sp_repr_set_svg_double(repr, "width", width);
             sp_repr_set_svg_double(repr, "height", height);