Code

excise never-used code and stale comments
[inkscape.git] / src / nodepath.cpp
index c28ca7b80361f65cbb121f317cf2b594b5ecd6f8..26078ea92d30bb6accf1d635ffc9c42c658d8ae8 100644 (file)
@@ -47,7 +47,7 @@ class NR::Matrix;
 /// evil evil evil. FIXME: conflict of two different Path classes!
 /// There is a conflict in the namespace between two classes named Path.
 /// #include "sp-flowtext.h"
-/// #include "sp-flowregion.h" 
+/// #include "sp-flowregion.h"
 
 #define SP_TYPE_FLOWREGION            (sp_flowregion_get_type ())
 #define SP_IS_FLOWREGION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_FLOWREGION))
@@ -110,6 +110,7 @@ static void node_ctrl_grabbed(SPKnot *knot, guint state, gpointer data);
 static void node_ctrl_ungrabbed(SPKnot *knot, guint state, gpointer data);
 static gboolean node_ctrl_request(SPKnot *knot, NR::Point *p, guint state, gpointer data);
 static void node_ctrl_moved(SPKnot *knot, NR::Point *p, guint state, gpointer data);
+static gboolean node_ctrl_event(SPKnot *knot, GdkEvent *event, Inkscape::NodePath::Node *n);
 
 /* Constructors and destructors */
 
@@ -131,7 +132,7 @@ static NRPathcode sp_node_path_code_from_side(Inkscape::NodePath::Node *node,Ink
 static Inkscape::NodePath::Node *active_node = NULL;
 
 /**
- * \brief Creates new nodepath from item 
+ * \brief Creates new nodepath from item
  */
 Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPItem *item)
 {
@@ -182,7 +183,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPItem *item)
     np->nodeContext = NULL; //Let the context that makes this set it
 
     // we need to update item's transform from the repr here,
-    // because they may be out of sync when we respond 
+    // because they may be out of sync when we respond
     // to a change in repr by regenerating nodepath     --bb
     sp_object_read_attr(SP_OBJECT(item), "transform");
 
@@ -257,7 +258,7 @@ static gint sp_nodepath_get_node_count(Inkscape::NodePath::Path *np)
 
 /**
  * Clean up a nodepath after editing.
- * 
+ *
  * Currently we are deleting trivial subpaths.
  */
 static void sp_nodepath_cleanup(Inkscape::NodePath::Path *nodepath)
@@ -284,11 +285,11 @@ static void sp_nodepath_cleanup(Inkscape::NodePath::Path *nodepath)
 
 
 /**
- * \brief Returns true if the argument nodepath and the d attribute in 
- * its repr do not match. 
+ * \brief Returns true if the argument nodepath and the d attribute in
+ * its repr do not match.
+ *
+ * This may happen if repr was changed in, e.g., XML editor or by undo.
  *
- * This may happen if repr was changed in, e.g., XML editor or by undo. 
- * 
  * \todo
  * UGLY HACK, think how we can eliminate it.
  */
@@ -307,7 +308,7 @@ gboolean nodepath_repr_d_changed(Inkscape::NodePath::Path *np, char const *newd)
     gboolean ret;
     if (attr_d && svgpath)
         ret = strcmp(attr_d, svgpath);
-    else 
+    else
         ret = TRUE;
 
     g_free(svgpath);
@@ -317,8 +318,8 @@ gboolean nodepath_repr_d_changed(Inkscape::NodePath::Path *np, char const *newd)
 }
 
 /**
- * \brief Returns true if the argument nodepath and the sodipodi:nodetypes 
- * attribute in its repr do not match. 
+ * \brief Returns true if the argument nodepath and the sodipodi:nodetypes
+ * attribute in its repr do not match.
  *
  * This may happen if repr was changed in, e.g., the XML editor or by undo.
  */
@@ -681,7 +682,7 @@ static void sp_nodepath_line_midpoint(Inkscape::NodePath::Node *new_path,Inkscap
 }
 
 /**
- * Adds new node on direct line between two nodes, activates handles of all 
+ * Adds new node on direct line between two nodes, activates handles of all
  * three nodes.
  */
 static Inkscape::NodePath::Node *sp_nodepath_line_add_node(Inkscape::NodePath::Node *end, gdouble t)
@@ -834,9 +835,13 @@ static Inkscape::NodePath::Node *sp_nodepath_set_node_type(Inkscape::NodePath::N
     node->type = type;
 
     if (node->type == Inkscape::NodePath::NODE_CUSP) {
-        g_object_set(G_OBJECT(node->knot), "shape", SP_KNOT_SHAPE_DIAMOND, "size", 9, NULL);
+        node->knot->setShape (SP_KNOT_SHAPE_DIAMOND);
+        node->knot->setSize (node->selected? 11 : 9);
+        sp_knot_update_ctrl(node->knot);
     } else {
-        g_object_set(G_OBJECT(node->knot), "shape", SP_KNOT_SHAPE_SQUARE, "size", 7, NULL);
+        node->knot->setShape (SP_KNOT_SHAPE_SQUARE);
+        node->knot->setSize (node->selected? 9 : 7);
+        sp_knot_update_ctrl(node->knot);
     }
 
     sp_node_adjust_knots(node);
@@ -847,7 +852,7 @@ static Inkscape::NodePath::Node *sp_nodepath_set_node_type(Inkscape::NodePath::N
 }
 
 /**
- * Same as sp_nodepath_set_node_type(), but also converts, if necessary, 
+ * Same as sp_nodepath_set_node_type(), but also converts, if necessary,
  * adjacent segments from lines to curves.
 */
 void sp_nodepath_convert_node_type(Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeType type)
@@ -859,7 +864,7 @@ void sp_nodepath_convert_node_type(Inkscape::NodePath::Node *node, Inkscape::Nod
             NR::Point delta;
             if (node->n.other != NULL)
                 delta = node->n.other->pos - node->p.other->pos;
-            else 
+            else
                 delta = node->pos - node->p.other->pos;
             node->p.pos = node->pos - delta / 4;
             sp_node_ensure_ctrls(node);
@@ -871,7 +876,7 @@ void sp_nodepath_convert_node_type(Inkscape::NodePath::Node *node, Inkscape::Nod
             NR::Point delta;
             if (node->p.other != NULL)
                 delta = node->p.other->pos - node->n.other->pos;
-            else 
+            else
                 delta = node->pos - node->n.other->pos;
             node->n.pos = node->pos - delta / 4;
             sp_node_ensure_ctrls(node);
@@ -991,6 +996,33 @@ sp_node_selected_move_screen(gdouble dx, gdouble dy)
     }
 }
 
+/** If they don't yet exist, creates knot and line for the given side of the node */
+static void sp_node_ensure_knot_exists (SPDesktop *desktop, Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeSide *side)
+{
+    if (!side->knot) {
+        side->knot = sp_knot_new(desktop, _("<b>Node handle</b>: drag to shape the curve; with <b>Ctrl</b> to snap angle; with <b>Alt</b> to lock length; with <b>Shift</b> to rotate both handles"));
+
+        side->knot->setShape (SP_KNOT_SHAPE_CIRCLE);
+        side->knot->setSize (7);
+        side->knot->setAnchor (GTK_ANCHOR_CENTER);
+        side->knot->setFill(KNOT_FILL, KNOT_FILL_HI, KNOT_FILL_HI);
+        side->knot->setStroke(KNOT_STROKE, KNOT_STROKE_HI, KNOT_STROKE_HI);
+        sp_knot_update_ctrl(side->knot);
+
+        g_signal_connect(G_OBJECT(side->knot), "clicked", G_CALLBACK(node_ctrl_clicked), node);
+        g_signal_connect(G_OBJECT(side->knot), "grabbed", G_CALLBACK(node_ctrl_grabbed), node);
+        g_signal_connect(G_OBJECT(side->knot), "ungrabbed", G_CALLBACK(node_ctrl_ungrabbed), node);
+        g_signal_connect(G_OBJECT(side->knot), "request", G_CALLBACK(node_ctrl_request), node);
+        g_signal_connect(G_OBJECT(side->knot), "moved", G_CALLBACK(node_ctrl_moved), node);
+        g_signal_connect(G_OBJECT(side->knot), "event", G_CALLBACK(node_ctrl_event), node);
+    }
+
+    if (!side->line) {
+        side->line = sp_canvas_item_new(SP_DT_CONTROLS(desktop),
+                                        SP_TYPE_CTRLLINE, NULL);
+    }
+}
+
 /**
  * Ensure knot on side of node is visible/invisible.
  */
@@ -1004,18 +1036,31 @@ static void sp_node_ensure_knot(Inkscape::NodePath::Node *node, gint which, gboo
     show_knot = show_knot && (code == NR_CURVETO) && (NR::L2(side->pos - node->pos) > 1e-6);
 
     if (show_knot) {
-        if (!SP_KNOT_IS_VISIBLE(side->knot)) {
+        if (!side->knot) {
+            sp_node_ensure_knot_exists(node->subpath->nodepath->desktop, node, side);
+            // Just created, so we shouldn't fire the node_moved callback - instead set the knot position directly
+            side->knot->pos = side->pos;
+            if (side->knot->item) SP_CTRL(side->knot->item)->moveto(side->pos);
+            sp_ctrlline_set_coords(SP_CTRLLINE(side->line), node->pos, side->pos);
             sp_knot_show(side->knot);
+        } else {
+            if (side->knot->pos != side->pos) { // only if it's really moved
+                sp_knot_set_position(side->knot, &side->pos, 0); // this will set coords of the line as well
+            }
+            if (!SP_KNOT_IS_VISIBLE(side->knot)) {
+                sp_knot_show(side->knot);
+            }
         }
-
-        sp_knot_set_position(side->knot, &side->pos, 0);
         sp_canvas_item_show(side->line);
-
     } else {
-        if (SP_KNOT_IS_VISIBLE(side->knot)) {
-            sp_knot_hide(side->knot);
+        if (side->knot) {
+            if (SP_KNOT_IS_VISIBLE(side->knot)) {
+                sp_knot_hide(side->knot);
+            }
+        }
+        if (side->line) {
+            sp_canvas_item_hide(side->line);
         }
-        sp_canvas_item_hide(side->line);
     }
 }
 
@@ -1225,11 +1270,12 @@ sp_nodepath_select_segment_near_point(SPItem * item, NR::Point p, bool toggle)
     Inkscape::NodePath::Node *e = sp_nodepath_get_node_by_index(position.piece);
 
     gboolean force = FALSE;
-    if (!(e->selected && e->p.other->selected)) {
+    if (!(e->selected && (!e->p.other || e->p.other->selected))) {
         force = TRUE;
-    } 
+    }
     sp_nodepath_node_select(e, (gboolean) toggle, force);
-    sp_nodepath_node_select(e->p.other, TRUE, force);
+    if (e->p.other)
+        sp_nodepath_node_select(e->p.other, TRUE, force);
 
     sp_nodepath_ensure_ctrls(nodepath);
 
@@ -1251,7 +1297,7 @@ sp_nodepath_add_node_near_point(SPItem * item, NR::Point p)
 
     //find segment to split
     Inkscape::NodePath::Node *e = sp_nodepath_get_node_by_index(position.piece);
-   
+
     //don't know why but t seems to flip for lines
     if (sp_node_path_code_from_side(e, sp_node_get_side(e, -1)) == NR_LINETO) {
         position.t = 1.0 - position.t;
@@ -1275,7 +1321,7 @@ sp_nodepath_add_node_near_point(SPItem * item, NR::Point p)
  * cf. app/vectors/gimpbezierstroke.c, gimp_bezier_stroke_point_move_relative()
  */
 void
-sp_nodepath_curve_drag(Inkscape::NodePath::Node * e, double t, NR::Point delta, char * key) 
+sp_nodepath_curve_drag(Inkscape::NodePath::Node * e, double t, NR::Point delta, char * key)
 {
     /* feel good is an arbitrary parameter that distributes the delta between handles
      * if t of the drag point is less than 1/6 distance form the endpoint only
@@ -1290,7 +1336,7 @@ sp_nodepath_curve_drag(Inkscape::NodePath::Node * e, double t, NR::Point delta,
         feel_good = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
     else
         feel_good = 1;
-    
+
     //if we're dragging a line convert it to a curve
     if (sp_node_path_code_from_side(e, sp_node_get_side(e, -1))==NR_LINETO) {
         sp_nodepath_set_line_type(e, NR_CURVETO);
@@ -1810,21 +1856,15 @@ static void sp_node_set_selected(Inkscape::NodePath::Node *node, gboolean select
     node->selected = selected;
 
     if (selected) {
-        g_object_set(G_OBJECT(node->knot),
-                     "fill", NODE_FILL_SEL,
-                     "fill_mouseover", NODE_FILL_SEL_HI,
-                     "stroke", NODE_STROKE_SEL,
-                     "stroke_mouseover", NODE_STROKE_SEL_HI,
-                     "size", (node->type == Inkscape::NodePath::NODE_CUSP) ? 11 : 9,
-                     NULL);
+        node->knot->setSize ((node->type == Inkscape::NodePath::NODE_CUSP) ? 11 : 9);
+        node->knot->setFill(NODE_FILL_SEL, NODE_FILL_SEL_HI, NODE_FILL_SEL_HI);
+        node->knot->setStroke(NODE_STROKE_SEL, NODE_STROKE_SEL_HI, NODE_STROKE_SEL_HI);
+        sp_knot_update_ctrl(node->knot);
     } else {
-        g_object_set(G_OBJECT(node->knot),
-                     "fill", NODE_FILL,
-                     "fill_mouseover", NODE_FILL_HI,
-                     "stroke", NODE_STROKE,
-                     "stroke_mouseover", NODE_STROKE_HI,
-                     "size", (node->type == Inkscape::NodePath::NODE_CUSP) ? 9 : 7,
-                     NULL);
+        node->knot->setSize ((node->type == Inkscape::NodePath::NODE_CUSP) ? 9 : 7);
+        node->knot->setFill(NODE_FILL, NODE_FILL_HI, NODE_FILL_HI);
+        node->knot->setStroke(NODE_STROKE, NODE_STROKE_HI, NODE_STROKE_HI);
+        sp_knot_update_ctrl(node->knot);
     }
 
     sp_node_ensure_ctrls(node);
@@ -1845,7 +1885,7 @@ static void sp_nodepath_node_select(Inkscape::NodePath::Node *node, gboolean inc
     if (incremental) {
         if (override) {
             if (!g_list_find(nodepath->selected, node)) {
-                nodepath->selected = g_list_append(nodepath->selected, node);
+                nodepath->selected = g_list_prepend(nodepath->selected, node);
             }
             sp_node_set_selected(node, TRUE);
         } else { // toggle
@@ -1854,13 +1894,13 @@ static void sp_nodepath_node_select(Inkscape::NodePath::Node *node, gboolean inc
                 nodepath->selected = g_list_remove(nodepath->selected, node);
             } else {
                 g_assert(!g_list_find(nodepath->selected, node));
-                nodepath->selected = g_list_append(nodepath->selected, node);
+                nodepath->selected = g_list_prepend(nodepath->selected, node);
             }
             sp_node_set_selected(node, !node->selected);
         }
     } else {
         sp_nodepath_deselect(nodepath);
-        nodepath->selected = g_list_append(nodepath->selected, node);
+        nodepath->selected = g_list_prepend(nodepath->selected, node);
         sp_node_set_selected(node, TRUE);
     }
 
@@ -1900,10 +1940,10 @@ sp_nodepath_select_all(Inkscape::NodePath::Path *nodepath, bool invert)
     }
 }
 
-/** 
- * If nothing selected, does the same as sp_nodepath_select_all(); 
- * otherwise selects/inverts all nodes in all subpaths that have selected nodes 
- * (i.e., similar to "select all in layer", with the "selected" subpaths 
+/**
+ * If nothing selected, does the same as sp_nodepath_select_all();
+ * otherwise selects/inverts all nodes in all subpaths that have selected nodes
+ * (i.e., similar to "select all in layer", with the "selected" subpaths
  * being treated as "layers" in the path).
  */
 void
@@ -1939,7 +1979,7 @@ sp_nodepath_select_all_from_subpath(Inkscape::NodePath::Path *nodepath, bool inv
 }
 
 /**
- * \brief Select the node after the last selected; if none is selected, 
+ * \brief Select the node after the last selected; if none is selected,
  * select the first within path.
  */
 void sp_nodepath_select_next(Inkscape::NodePath::Path *nodepath)
@@ -1996,7 +2036,7 @@ void sp_nodepath_select_next(Inkscape::NodePath::Path *nodepath)
 }
 
 /**
- * \brief Select the node before the first selected; if none is selected, 
+ * \brief Select the node before the first selected; if none is selected,
  * select the last within path
  */
 void sp_nodepath_select_prev(Inkscape::NodePath::Path *nodepath)
@@ -2165,7 +2205,6 @@ static void sp_node_adjust_knot(Inkscape::NodePath::Node *node, gint which_adjus
         if (linelen < 1e-18) return;
 
         me->pos = node->pos + (len / linelen)*delta;
-        sp_knot_set_position(me->knot, &me->pos, 0);
 
         sp_node_ensure_ctrls(node);
         return;
@@ -2174,7 +2213,6 @@ static void sp_node_adjust_knot(Inkscape::NodePath::Node *node, gint which_adjus
     if (node->type == Inkscape::NodePath::NODE_SYMM) {
 
         me->pos = 2 * node->pos - other->pos;
-        sp_knot_set_position(me->knot, &me->pos, 0);
 
         sp_node_ensure_ctrls(node);
         return;
@@ -2188,7 +2226,6 @@ static void sp_node_adjust_knot(Inkscape::NodePath::Node *node, gint which_adjus
     if (otherlen < 1e-18) return;
 
     me->pos = node->pos - (len / otherlen) * delta;
-    sp_knot_set_position(me->knot, &me->pos, 0);
 
     sp_node_ensure_ctrls(node);
 }
@@ -2438,7 +2475,7 @@ node_request(SPKnot *knot, NR::Point *p, guint state, gpointer data)
    Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) data;
 
    // If either (Shift and some handle retracted), or (we're already dragging out a handle)
-   if (((state & GDK_SHIFT_MASK) && ((n->n.other && n->n.pos == n->pos) || (n->p.other && n->p.pos == n->pos))) || n->dragging_out) { 
+   if (((state & GDK_SHIFT_MASK) && ((n->n.other && n->n.pos == n->pos) || (n->p.other && n->p.pos == n->pos))) || n->dragging_out) {
 
        NR::Point mouse = (*p);
 
@@ -2487,6 +2524,10 @@ node_request(SPKnot *knot, NR::Point *p, guint state, gpointer data)
            if (opposite->pos != n->pos) {
                mouse = n->pos - NR::L2(mouse - n->pos) * NR::unit_vector(opposite->pos - n->pos);
            }
+
+           // knots might not be created yet!
+           sp_node_ensure_knot_exists (n->subpath->nodepath->desktop, n, n->dragging_out);
+           sp_node_ensure_knot_exists (n->subpath->nodepath->desktop, n, opposite);
        }
 
        // pass this on to the handle-moved callback
@@ -2949,7 +2990,7 @@ void sp_nodepath_selected_nodes_rotate(Inkscape::NodePath::Path *nodepath, gdoub
 
         Inkscape::NodePath::Node *n0 = (Inkscape::NodePath::Node *) nodepath->selected->data;
         NR::Rect box (n0->pos, n0->pos); // originally includes the first selected node
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             box.expandTo (n->pos); // contain all selected nodes
         }
@@ -2964,12 +3005,12 @@ void sp_nodepath_selected_nodes_rotate(Inkscape::NodePath::Path *nodepath, gdoub
             rot = angle;
         }
 
-        NR::Matrix t = 
-            NR::Matrix (NR::translate(-box.midpoint())) * 
-            NR::Matrix (NR::rotate(rot)) * 
+        NR::Matrix t =
+            NR::Matrix (NR::translate(-box.midpoint())) *
+            NR::Matrix (NR::rotate(rot)) *
             NR::Matrix (NR::translate(box.midpoint()));
 
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             n->pos *= t;
             n->n.pos *= t;
@@ -3001,14 +3042,14 @@ static void node_scale_one (Inkscape::NodePath::Node *n, gdouble grow, int which
     } else if (!n->p.other) {
         me = &(n->n);
         other = &(n->p);
-        if (n->n.other)    
+        if (n->n.other)
             n->n.other->code = NR_CURVETO;
     } else {
         if (which > 0) { // right handle
             if (xn > xp) {
                 me = &(n->n);
                 other = &(n->p);
-                if (n->n.other)    
+                if (n->n.other)
                     n->n.other->code = NR_CURVETO;
             } else {
                 me = &(n->p);
@@ -3019,7 +3060,7 @@ static void node_scale_one (Inkscape::NodePath::Node *n, gdouble grow, int which
             if (xn <= xp) {
                 me = &(n->n);
                 other = &(n->p);
-                if (n->n.other)    
+                if (n->n.other)
                     n->n.other->code = NR_CURVETO;
             } else {
                 me = &(n->p);
@@ -3031,7 +3072,7 @@ static void node_scale_one (Inkscape::NodePath::Node *n, gdouble grow, int which
             other = &(n->p);
             both = true;
             n->code = NR_CURVETO;
-            if (n->n.other)    
+            if (n->n.other)
                 n->n.other->code = NR_CURVETO;
         }
     }
@@ -3082,19 +3123,19 @@ void sp_nodepath_selected_nodes_scale(Inkscape::NodePath::Path *nodepath, gdoubl
 
         Inkscape::NodePath::Node *n0 = (Inkscape::NodePath::Node *) nodepath->selected->data;
         NR::Rect box (n0->pos, n0->pos); // originally includes the first selected node
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             box.expandTo (n->pos); // contain all selected nodes
         }
 
         double scale = (box.maxExtent() + grow)/box.maxExtent();
 
-        NR::Matrix t = 
-            NR::Matrix (NR::translate(-box.midpoint())) * 
-            NR::Matrix (NR::scale(scale, scale)) * 
+        NR::Matrix t =
+            NR::Matrix (NR::translate(-box.midpoint())) *
+            NR::Matrix (NR::scale(scale, scale)) *
             NR::Matrix (NR::translate(box.midpoint()));
 
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             n->pos *= t;
             n->n.pos *= t;
@@ -3133,17 +3174,17 @@ void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis)
 
         Inkscape::NodePath::Node *n0 = (Inkscape::NodePath::Node *) nodepath->selected->data;
         NR::Rect box (n0->pos, n0->pos); // originally includes the first selected node
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             box.expandTo (n->pos); // contain all selected nodes
         }
 
-        NR::Matrix t = 
-            NR::Matrix (NR::translate(-box.midpoint())) * 
-            NR::Matrix ((axis == NR::X)? NR::scale(-1, 1) : NR::scale(1, -1)) * 
+        NR::Matrix t =
+            NR::Matrix (NR::translate(-box.midpoint())) *
+            NR::Matrix ((axis == NR::X)? NR::scale(-1, 1) : NR::scale(1, -1)) *
             NR::Matrix (NR::translate(box.midpoint()));
 
-        for (GList *l = nodepath->selected; l != NULL; l = l->next) { 
+        for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
             n->pos *= t;
             n->n.pos *= t;
@@ -3252,7 +3293,7 @@ static void sp_nodepath_subpath_open(Inkscape::NodePath::SubPath *sp,Inkscape::N
  * Returns area in triangle given by points; may be negative.
  */
 inline double
-triangle_area (NR::Point p1, NR::Point p2, NR::Point p3) 
+triangle_area (NR::Point p1, NR::Point p2, NR::Point p3)
 {
     return (p1[NR::X]*p2[NR::Y] + p1[NR::Y]*p3[NR::X] + p2[NR::X]*p3[NR::Y] - p2[NR::Y]*p3[NR::X] - p1[NR::Y]*p2[NR::X] - p1[NR::X]*p3[NR::Y]);
 }
@@ -3304,7 +3345,7 @@ sp_nodepath_node_new(Inkscape::NodePath::SubPath *sp, Inkscape::NodePath::Node *
 
     Inkscape::NodePath::Node *prev;
     if (next) {
-        g_assert(g_list_find(sp->nodes, next));
+        //g_assert(g_list_find(sp->nodes, next));
         prev = next->p.other;
     } else {
         prev = sp->last;
@@ -3323,20 +3364,15 @@ sp_nodepath_node_new(Inkscape::NodePath::SubPath *sp, Inkscape::NodePath::Node *
     n->p.other = prev;
     n->n.other = next;
 
-    n->knot = sp_knot_new(sp->nodepath->desktop);
+    n->knot = sp_knot_new(sp->nodepath->desktop, _("<b>Node</b>: drag to edit the path; with <b>Ctrl</b> to snap to horizontal/vertical; with <b>Ctrl+Alt</b> to snap to handles' directions"));
     sp_knot_set_position(n->knot, pos, 0);
-    g_object_set(G_OBJECT(n->knot),
-                 "anchor", GTK_ANCHOR_CENTER,
-                 "fill", NODE_FILL,
-                 "fill_mouseover", NODE_FILL_HI,
-                 "stroke", NODE_STROKE,
-                 "stroke_mouseover", NODE_STROKE_HI,
-                 "tip", _("<b>Node</b>: drag to edit the path; with <b>Ctrl</b> to snap to horizontal/vertical; with <b>Ctrl+Alt</b> to snap to handles' directions"),
-                 NULL);
-    if (n->type == Inkscape::NodePath::NODE_CUSP)
-        g_object_set(G_OBJECT(n->knot), "shape", SP_KNOT_SHAPE_DIAMOND, "size", 9, NULL);
-    else
-        g_object_set(G_OBJECT(n->knot), "shape", SP_KNOT_SHAPE_SQUARE, "size", 7, NULL);
+
+    n->knot->setShape ((n->type == Inkscape::NodePath::NODE_CUSP)? SP_KNOT_SHAPE_DIAMOND : SP_KNOT_SHAPE_SQUARE);
+    n->knot->setSize ((n->type == Inkscape::NodePath::NODE_CUSP)? 9 : 7);
+    n->knot->setAnchor (GTK_ANCHOR_CENTER);
+    n->knot->setFill(NODE_FILL, NODE_FILL_HI, NODE_FILL_HI);
+    n->knot->setStroke(NODE_STROKE, NODE_STROKE_HI, NODE_STROKE_HI);
+    sp_knot_update_ctrl(n->knot);
 
     g_signal_connect(G_OBJECT(n->knot), "event", G_CALLBACK(node_event), n);
     g_signal_connect(G_OBJECT(n->knot), "clicked", G_CALLBACK(node_clicked), n);
@@ -3345,52 +3381,11 @@ sp_nodepath_node_new(Inkscape::NodePath::SubPath *sp, Inkscape::NodePath::Node *
     g_signal_connect(G_OBJECT(n->knot), "request", G_CALLBACK(node_request), n);
     sp_knot_show(n->knot);
 
-    n->p.knot = sp_knot_new(sp->nodepath->desktop);
-    sp_knot_set_position(n->p.knot, ppos, 0);
-    g_object_set(G_OBJECT(n->p.knot),
-                 "shape", SP_KNOT_SHAPE_CIRCLE,
-                 "size", 7,
-                 "anchor", GTK_ANCHOR_CENTER,
-                 "fill", KNOT_FILL,
-                 "fill_mouseover", KNOT_FILL_HI,
-                 "stroke", KNOT_STROKE,
-                 "stroke_mouseover", KNOT_STROKE_HI,
-                 "tip", _("<b>Node handle</b>: drag to shape the curve; with <b>Ctrl</b> to snap angle; with <b>Alt</b> to lock length; with <b>Shift</b> to rotate both handles"),
-                 NULL);
-    g_signal_connect(G_OBJECT(n->p.knot), "clicked", G_CALLBACK(node_ctrl_clicked), n);
-    g_signal_connect(G_OBJECT(n->p.knot), "grabbed", G_CALLBACK(node_ctrl_grabbed), n);
-    g_signal_connect(G_OBJECT(n->p.knot), "ungrabbed", G_CALLBACK(node_ctrl_ungrabbed), n);
-    g_signal_connect(G_OBJECT(n->p.knot), "request", G_CALLBACK(node_ctrl_request), n);
-    g_signal_connect(G_OBJECT(n->p.knot), "moved", G_CALLBACK(node_ctrl_moved), n);
-    g_signal_connect(G_OBJECT(n->p.knot), "event", G_CALLBACK(node_ctrl_event), n);
-
-    sp_knot_hide(n->p.knot);
-    n->p.line = sp_canvas_item_new(SP_DT_CONTROLS(n->subpath->nodepath->desktop),
-                                   SP_TYPE_CTRLLINE, NULL);
-    sp_canvas_item_hide(n->p.line);
-
-    n->n.knot = sp_knot_new(sp->nodepath->desktop);
-    sp_knot_set_position(n->n.knot, npos, 0);
-    g_object_set(G_OBJECT(n->n.knot),
-                 "shape", SP_KNOT_SHAPE_CIRCLE,
-                 "size", 7,
-                 "anchor", GTK_ANCHOR_CENTER,
-                 "fill", KNOT_FILL,
-                 "fill_mouseover", KNOT_FILL_HI,
-                 "stroke", KNOT_STROKE,
-                 "stroke_mouseover", KNOT_STROKE_HI,
-                 "tip", _("<b>Node handle</b>: drag to shape the curve; with <b>Ctrl</b> to snap angle; with <b>Alt</b> to lock length; with <b>Shift</b> to rotate the opposite handle in sync"),
-                 NULL);
-    g_signal_connect(G_OBJECT(n->n.knot), "clicked", G_CALLBACK(node_ctrl_clicked), n);
-    g_signal_connect(G_OBJECT(n->n.knot), "grabbed", G_CALLBACK(node_ctrl_grabbed), n);
-    g_signal_connect(G_OBJECT(n->n.knot), "ungrabbed", G_CALLBACK(node_ctrl_ungrabbed), n);
-    g_signal_connect(G_OBJECT(n->n.knot), "request", G_CALLBACK(node_ctrl_request), n);
-    g_signal_connect(G_OBJECT(n->n.knot), "moved", G_CALLBACK(node_ctrl_moved), n);
-    g_signal_connect(G_OBJECT(n->n.knot), "event", G_CALLBACK(node_ctrl_event), n);
-    sp_knot_hide(n->n.knot);
-    n->n.line = sp_canvas_item_new(SP_DT_CONTROLS(n->subpath->nodepath->desktop),
-                                   SP_TYPE_CTRLLINE, NULL);
-    sp_canvas_item_hide(n->n.line);
+    // We only create side knots and lines on demand
+    n->p.knot = NULL;
+    n->p.line = NULL;
+    n->n.knot = NULL;
+    n->n.line = NULL;
 
     sp->nodes = g_list_prepend(sp->nodes, n);
 
@@ -3405,9 +3400,7 @@ static void sp_nodepath_node_destroy(Inkscape::NodePath::Node *node)
     g_assert(node);
     g_assert(node->subpath);
     g_assert(SP_IS_KNOT(node->knot));
-    g_assert(SP_IS_KNOT(node->p.knot));
-    g_assert(SP_IS_KNOT(node->n.knot));
-    g_assert(g_list_find(node->subpath->nodes, node));
+//    g_assert(g_list_find(node->subpath->nodes, node));
 
    Inkscape::NodePath::SubPath *sp = node->subpath;
 
@@ -3419,11 +3412,15 @@ static void sp_nodepath_node_destroy(Inkscape::NodePath::Node *node)
     node->subpath->nodes = g_list_remove(node->subpath->nodes, node);
 
     g_object_unref(G_OBJECT(node->knot));
-    g_object_unref(G_OBJECT(node->p.knot));
-    g_object_unref(G_OBJECT(node->n.knot));
+    if (node->p.knot)
+        g_object_unref(G_OBJECT(node->p.knot));
+    if (node->n.knot)
+        g_object_unref(G_OBJECT(node->n.knot));
 
-    gtk_object_destroy(GTK_OBJECT(node->p.line));
-    gtk_object_destroy(GTK_OBJECT(node->n.line));
+    if (node->p.line)
+        gtk_object_destroy(GTK_OBJECT(node->p.line));
+    if (node->n.line)
+        gtk_object_destroy(GTK_OBJECT(node->n.line));
 
     if (sp->nodes) { // there are others nodes on the subpath
         if (sp->closed) {
@@ -3513,11 +3510,11 @@ static NRPathcode sp_node_path_code_from_side(Inkscape::NodePath::Node *node,Ink
 /**
  * Call sp_nodepath_line_add_node() at t on the segment denoted by piece
  */
-Inkscape::NodePath::Node * 
+Inkscape::NodePath::Node *
 sp_nodepath_get_node_by_index(int index)
 {
     Inkscape::NodePath::Node *e = NULL;
-    
+
     Inkscape::NodePath::Path *nodepath = sp_nodepath_current();
     if (!nodepath) {
         return e;
@@ -3525,13 +3522,13 @@ sp_nodepath_get_node_by_index(int index)
 
     //find segment
     for (GList *l = nodepath->subpaths; l ; l=l->next) {
-        
+
         Inkscape::NodePath::SubPath *sp = (Inkscape::NodePath::SubPath *)l->data;
         int n = g_list_length(sp->nodes);
         if (sp->closed) {
             n++;
-        } 
-        
+        }
+
         //if the piece belongs to this subpath grab it
         //otherwise move onto the next subpath
         if (index < n) {
@@ -3548,7 +3545,7 @@ sp_nodepath_get_node_by_index(int index)
             }
         }
     }
-    
+
     return e;
 }