Code

use touchpath selection when rubberbanding with Alt; do move-selected with Alt only...
[inkscape.git] / src / sp-offset.cpp
index a9730653c247e4ac11f3118113197c9bc2aea9c9..e682f394bb74c41029ce91c6aec088aa84c729ba 100644 (file)
@@ -46,24 +46,24 @@ class SPDocument;
 
 /** \note
  * SPOffset is a derivative of SPShape, much like the SPSpiral or SPRect.
- * The goal is to have a source shape (= originalPath), an offset (= radius) 
- * and compute the offset of the source by the radius. To get it to work, 
- * one needs to know what the source is and what the radius is, and how it's 
- * stored in the xml representation. The object itself is a "path" element, 
- * to get lots of shape functionality for free. The source is the easy part: 
- * it's stored in a "inkscape:original" attribute in the path. In case of 
+ * The goal is to have a source shape (= originalPath), an offset (= radius)
+ * and compute the offset of the source by the radius. To get it to work,
+ * one needs to know what the source is and what the radius is, and how it's
+ * stored in the xml representation. The object itself is a "path" element,
+ * to get lots of shape functionality for free. The source is the easy part:
+ * it's stored in a "inkscape:original" attribute in the path. In case of
  * "linked" offset, as they've been dubbed, there is an additional
- * "inkscape:href" that contains the id of an element of the svg. 
- * When built, the object will attach a listener vector to that object and 
- * rebuild the "inkscape:original" whenever the href'd object changes. This 
- * is of course grossly inefficient, and also does not react to changes 
- * to the href'd during context stuff (like changing the shape of a star by 
- * dragging control points) unless the path of that object is changed during 
- * the context (seems to be the case for SPEllipse). The computation of the 
- * offset is done in sp_offset_set_shape(), a function that is called whenever 
+ * "inkscape:href" that contains the id of an element of the svg.
+ * When built, the object will attach a listener vector to that object and
+ * rebuild the "inkscape:original" whenever the href'd object changes. This
+ * is of course grossly inefficient, and also does not react to changes
+ * to the href'd during context stuff (like changing the shape of a star by
+ * dragging control points) unless the path of that object is changed during
+ * the context (seems to be the case for SPEllipse). The computation of the
+ * offset is done in sp_offset_set_shape(), a function that is called whenever
  * a change occurs to the offset (change of source or change of radius).
- * just like the sp-star and other, this path derivative can make control 
- * points, or more precisely one control point, that's enough to define the 
+ * just like the sp-star and other, this path derivative can make control
+ * points, or more precisely one control point, that's enough to define the
  * radius (look in object-edit).
  */
 
@@ -179,6 +179,7 @@ sp_offset_init(SPOffset *offset)
     offset->sourceHref = NULL;
     offset->sourceRepr = NULL;
     offset->sourceObject = NULL;
+    new (&offset->_modified_connection) sigc::connection();
     new (&offset->_delete_connection) sigc::connection();
     new (&offset->_changed_connection) sigc::connection();
     new (&offset->_transformed_connection) sigc::connection();
@@ -196,8 +197,14 @@ sp_offset_finalize(GObject *obj)
     SPOffset *offset = (SPOffset *) obj;
 
     delete offset->sourceRef;
+
+    offset->_modified_connection.disconnect();
+    offset->_modified_connection.~connection();
+    offset->_delete_connection.disconnect();
     offset->_delete_connection.~connection();
+    offset->_changed_connection.disconnect();
     offset->_changed_connection.~connection();
+    offset->_transformed_connection.disconnect();
     offset->_transformed_connection.~connection();
 }
 
@@ -209,19 +216,19 @@ sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
 {
     if (((SPObjectClass *) parent_class)->build)
         ((SPObjectClass *) parent_class)->build (object, document, repr);
-  
+
     if (object->repr->attribute("inkscape:radius")) {
         sp_object_read_attr (object, "inkscape:radius");
     } else {
         gchar const *oldA = object->repr->attribute("sodipodi:radius");
         object->repr->setAttribute("inkscape:radius",oldA);
         object->repr->setAttribute("sodipodi:radius",NULL);
-    
+
         sp_object_read_attr (object, "inkscape:radius");
     }
     if (object->repr->attribute("inkscape:original")) {
         sp_object_read_attr (object, "inkscape:original");
-    } else {    
+    } else {
         gchar const *oldA = object->repr->attribute("sodipodi:original");
         object->repr->setAttribute("inkscape:original",oldA);
         object->repr->setAttribute("sodipodi:original",NULL);
@@ -255,7 +262,8 @@ sp_offset_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     SPOffset *offset = SP_OFFSET (object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new ("svg:path");
+        Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(object)->document();
+        repr = xml_doc->createElement("svg:path");
     }
 
     if (flags & SP_OBJECT_WRITE_EXT) {
@@ -277,7 +285,7 @@ sp_offset_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     }
 
     // write that curve to "d"
-    char *d = sp_svg_write_path (((SPShape *) offset)->curve->bpath);
+    char *d = sp_svg_write_path (SP_CURVE_BPATH(((SPShape *) offset)->curve));
     repr->setAttribute("d", d);
     g_free (d);
 
@@ -315,7 +323,7 @@ sp_offset_release(SPObject *object)
 }
 
 /**
- * Set callback: the function that is called whenever a change is made to 
+ * Set callback: the function that is called whenever a change is made to
  * the description of the object.
  */
 static void
@@ -346,7 +354,7 @@ sp_offset_set(SPObject *object, unsigned key, gchar const *value)
                 bpath = sp_svg_read_path (offset->original);
                 curve = sp_curve_new_from_bpath (bpath);       // curve se chargera de detruire bpath
                 g_assert (curve != NULL);
-                offset->originalPath = bpath_to_liv_path (curve->bpath);
+                offset->originalPath = bpath_to_liv_path (SP_CURVE_BPATH(curve));
                 sp_curve_unref (curve);
 
                 offset->knotSet = false;
@@ -430,7 +438,7 @@ sp_offset_description(SPItem *item)
 }
 
 /**
- * Converts an NArtBpath (like the one stored in a SPCurve) into a 
+ * Converts an NArtBpath (like the one stored in a SPCurve) into a
  * livarot Path. Duplicate of splivarot.
  */
 Path *
@@ -438,7 +446,7 @@ bpath_to_liv_path(NArtBpath *bpath)
 {
     if (bpath == NULL)
         return NULL;
-  
+
     Path *dest = new Path;
     dest->SetBackData (false);
     {
@@ -545,7 +553,7 @@ sp_offset_set_shape(SPShape *shape)
         Path *originaux[1];
         Path *res = new Path;
         res->SetBackData (false);
-  
+
         // and now: offset
         float o_width;
         if (offset->rad >= 0)
@@ -576,9 +584,9 @@ sp_offset_set_shape(SPShape *shape)
         theRes->ConvertToForme (orig, 1, originaux);
 
         SPItem *item = shape;
-        NR::Rect bbox = sp_item_bbox_desktop (item);
-        if (!bbox.isEmpty()) {
-            gdouble size = L2(bbox.dimensions());
+        NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (item);
+        if ( bbox && !bbox->isEmpty() ) {
+            gdouble size = L2(bbox->dimensions());
             gdouble const exp = NR::expansion(item->transform);
             if (exp != 0)
                 size /= exp;
@@ -608,8 +616,8 @@ sp_offset_set_shape(SPShape *shape)
         // version par makeoffset
         Shape *theShape = new Shape;
         Shape *theRes = new Shape;
-    
-    
+
+
         // and now: offset
         float o_width;
         if (offset->rad >= 0)
@@ -620,7 +628,7 @@ sp_offset_set_shape(SPShape *shape)
         {
             o_width = -offset->rad;
         }
-    
+
         // one has to have a measure of the details
         if (o_width >= 1.0)
         {
@@ -795,21 +803,21 @@ static void sp_offset_snappoints(SPItem const *item, SnapPointsIter p)
 // utilitaires pour les poignees
 // used to get the distance to the shape: distance to polygon give the fabs(radius), we still need
 // the sign. for edges, it's easy to determine which side the point is on, for points of the polygon
-// it's trickier: we need to identify which angle the point is in; to that effect, we take each 
+// it's trickier: we need to identify which angle the point is in; to that effect, we take each
 // successive clockwise angle (A,C) and check if the vector B given by the point is in the angle or
 // outside.
-// another method would be to use the Winding() function to test whether the point is inside or outside 
+// another method would be to use the Winding() function to test whether the point is inside or outside
 // the polygon (it would be wiser to do so, in fact, but i like being stupid)
 
-/** 
+/**
  *
  * \todo
  * FIXME: This can be done using linear operations, more stably and
  *  faster.  method: transform A and C into B's space, A should be
  *  negative and B should be positive in the orthogonal component.  I
- *  think this is equivalent to 
- *  dot(A, rot90(B))*dot(C, rot90(B)) == -1.  
- *    -- njh 
+ *  think this is equivalent to
+ *  dot(A, rot90(B))*dot(C, rot90(B)) == -1.
+ *    -- njh
  */
 bool
 vectors_are_clockwise (NR::Point A, NR::Point B, NR::Point C)
@@ -851,12 +859,12 @@ vectors_are_clockwise (NR::Point A, NR::Point B, NR::Point C)
     return false;
 }
 
-/** 
- * Distance to the original path; that function is called from object-edit 
+/**
+ * Distance to the original path; that function is called from object-edit
  * to set the radius when the control knot moves.
  *
- * The sign of the result is the radius we're going to offset the shape with, 
- * so result > 0 ==outset and result < 0 ==inset. thus result<0 means 
+ * The sign of the result is the radius we're going to offset the shape with,
+ * so result > 0 ==outset and result < 0 ==inset. thus result<0 means
  * 'px inside source'.
  */
 double
@@ -868,14 +876,14 @@ sp_offset_distance_to_original (SPOffset * offset, NR::Point px)
     double dist = 1.0;
     Shape *theShape = new Shape;
     Shape *theRes = new Shape;
-  
-    /** \todo 
-     * Awfully damn stupid method: uncross the source path EACH TIME you 
-     * need to compute the distance. The good way to do this would be to 
+
+    /** \todo
+     * Awfully damn stupid method: uncross the source path EACH TIME you
+     * need to compute the distance. The good way to do this would be to
      * store the uncrossed source path somewhere, and delete it when the
-     * context is finished. Hopefully this part is much faster than actually 
-     * computing the offset (which happen just after), so the time spent in 
-     * this function should end up being negligible with respect to the 
+     * context is finished. Hopefully this part is much faster than actually
+     * computing the offset (which happen just after), so the time spent in
+     * this function should end up being negligible with respect to the
      * delay of one context.
      */
     // move
@@ -995,8 +1003,8 @@ sp_offset_distance_to_original (SPOffset * offset, NR::Point px)
     return dist;
 }
 
-/** 
- * Computes a point on the offset;  used to set a "seed" position for 
+/**
+ * Computes a point on the offset;  used to set a "seed" position for
  * the control knot.
  *
  * \return the topmost point on the offset.
@@ -1023,7 +1031,7 @@ sp_offset_top_point (SPOffset * offset, NR::Point *px)
             return;
     }
 
-    Path *finalPath = bpath_to_liv_path (curve->bpath);
+    Path *finalPath = bpath_to_liv_path (SP_CURVE_BPATH(curve));
     if (finalPath == NULL)
     {
         sp_curve_unref (curve);
@@ -1057,7 +1065,7 @@ static void sp_offset_start_listening(SPOffset *offset,SPObject* to)
 
     offset->_delete_connection = SP_OBJECT(to)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_offset_delete_self), offset));
     offset->_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_offset_move_compensate), offset));
-    offset->_modified_connection = g_signal_connect (G_OBJECT (to), "modified", G_CALLBACK (sp_offset_source_modified), offset);
+    offset->_modified_connection = SP_OBJECT(to)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_offset_source_modified), offset));
 }
 
 static void sp_offset_quit_listening(SPOffset *offset)
@@ -1065,7 +1073,7 @@ static void sp_offset_quit_listening(SPOffset *offset)
     if ( offset->sourceObject == NULL )
         return;
 
-    g_signal_handler_disconnect (offset->sourceObject, offset->_modified_connection);
+    offset->_modified_connection.disconnect();
     offset->_delete_connection.disconnect();
     offset->_transformed_connection.disconnect();
 
@@ -1142,7 +1150,7 @@ sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *item)
     sp_shape_set_shape ((SPShape *) offset);
 }
 
-static void 
+static void
 refresh_offset_source(SPOffset* offset)
 {
     if ( offset == NULL ) return;
@@ -1167,7 +1175,7 @@ refresh_offset_source(SPOffset* offset)
         if (curve == NULL)
            return;
     }
-    orig = bpath_to_liv_path (curve->bpath);
+    orig = bpath_to_liv_path (SP_CURVE_BPATH(curve));
     sp_curve_unref (curve);
 
 
@@ -1195,21 +1203,21 @@ refresh_offset_source(SPOffset* offset)
         {
             theRes->ConvertToShape (theShape, fill_nonZero);
         }
-    
+
         Path *originaux[1];
         originaux[0] = orig;
         Path *res = new Path;
         theRes->ConvertToForme (res, 1, originaux);
-    
+
         delete theShape;
         delete theRes;
-    
+
         char *res_d = res->svg_dump_path ();
         delete res;
         delete orig;
-    
+
         SP_OBJECT (offset)->repr->setAttribute("inkscape:original", res_d);
-    
+
         free (res_d);
     }
 }