Code

Finally introducing the pre-snap indicator
authorDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 30 Jan 2010 22:04:33 +0000 (23:04 +0100)
committerDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 30 Jan 2010 22:04:33 +0000 (23:04 +0100)
22 files changed:
src/arc-context.cpp
src/box3d-context.cpp
src/connector-context.cpp
src/display/snap-indicator.cpp
src/display/snap-indicator.h
src/event-context.cpp
src/event-context.h
src/gradient-context.cpp
src/knot.cpp
src/knotholder.cpp
src/knotholder.h
src/object-edit.cpp
src/pen-context.cpp
src/pencil-context.cpp
src/rect-context.cpp
src/shape-editor.cpp
src/shape-editor.h
src/snap.cpp
src/snap.h
src/spiral-context.cpp
src/star-context.cpp
src/star-context.h

index 9cb6e822285101a46d81eb2e12b1996ff5e5f297..ccaaedd14e6d6f5be8e24d37a462400c882673a2 100644 (file)
@@ -116,15 +116,15 @@ static void sp_arc_context_init(SPArcContext *arc_context)
 static void sp_arc_context_finish(SPEventContext *ec)
 {
     SPArcContext *ac = SP_ARC_CONTEXT(ec);
-       SPDesktop *desktop = ec->desktop;
+    SPDesktop *desktop = ec->desktop;
 
-       sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME);
-       sp_arc_finish(ac);
+    sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), GDK_CURRENT_TIME);
+    sp_arc_finish(ac);
     ac->sel_changed_connection.disconnect();
 
     if (((SPEventContextClass *) parent_class)->finish) {
-               ((SPEventContextClass *) parent_class)->finish(ec);
-       }
+        ((SPEventContextClass *) parent_class)->finish(ec);
+    }
 }
 
 static void sp_arc_context_dispose(GObject *object)
@@ -274,6 +274,13 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent
                 gobble_motion_events(GDK_BUTTON1_MASK);
 
                 ret = TRUE;
+            } else if (sp_event_context_knot_mouseover(ac)){
+                SnapManager &m = desktop->namedview->snap_manager;
+                m.setup(desktop);
+
+                Geom::Point const motion_w(event->motion.x, event->motion.y);
+                Geom::Point motion_dt(desktop->w2d(motion_w));
+                m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
             }
             break;
         case GDK_BUTTON_RELEASE:
@@ -283,7 +290,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent
                 sp_event_context_discard_delayed_snap_event(event_context);
                 if (!event_context->within_tolerance) {
                     // we've been dragging, finish the arc
-                               sp_arc_finish(ac);
+                       sp_arc_finish(ac);
                 } else if (event_context->item_to_select) {
                     // no dragging, select clicked item if any
                     if (event->button.state & GDK_SHIFT_MASK) {
@@ -335,14 +342,14 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent
                     }
                     break;
                 case GDK_Escape:
-                       if (dragging) {
-                               dragging = false;
-                               sp_event_context_discard_delayed_snap_event(event_context);
-                               // if drawing, cancel, otherwise pass it up for deselecting
-                                               sp_arc_cancel(ac);
-                                               ret = TRUE;
-                                       }
-                       break;
+                    if (dragging) {
+                        dragging = false;
+                        sp_event_context_discard_delayed_snap_event(event_context);
+                        // if drawing, cancel, otherwise pass it up for deselecting
+                        sp_arc_cancel(ac);
+                        ret = TRUE;
+                    }
+                    break;
                 case GDK_space:
                     if (dragging) {
                         sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
@@ -480,13 +487,13 @@ static void sp_arc_finish(SPArcContext *ac)
 
     if (ac->item != NULL) {
 
-       SPGenericEllipse *ge = SP_GENERICELLIPSE(SP_ARC(ac->item));
-               if (ge->rx.computed == 0 || ge->ry.computed == 0) {
-                       sp_arc_cancel(ac); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point
-                       return;
-               }
+        SPGenericEllipse *ge = SP_GENERICELLIPSE(SP_ARC(ac->item));
+        if (ge->rx.computed == 0 || ge->ry.computed == 0) {
+            sp_arc_cancel(ac); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point
+            return;
+        }
 
-       SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop;
+        SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop;
 
         SP_OBJECT(ac->item)->updateRepr();
 
@@ -502,14 +509,14 @@ static void sp_arc_finish(SPArcContext *ac)
 
 static void sp_arc_cancel(SPArcContext *ac)
 {
-       SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop;
+    SPDesktop *desktop = SP_EVENT_CONTEXT(ac)->desktop;
 
-       sp_desktop_selection(desktop)->clear();
-       sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0);
+    sp_desktop_selection(desktop)->clear();
+    sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0);
 
     if (ac->item != NULL) {
-       SP_OBJECT(ac->item)->deleteObject();
-       ac->item = NULL;
+        SP_OBJECT(ac->item)->deleteObject();
+        ac->item = NULL;
     }
 
     ac->within_tolerance = false;
index ad9c51f0fda674e20c289a984beb2294b4f098dd..bf9bd7b6faa49bf97c017d08b161de8f12a2a62b 100644 (file)
@@ -358,8 +358,8 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
             }
 
             if (!bc->extruded) {
-               bc->drag_ptB = from_2geom(motion_dt);
-               bc->drag_ptC = from_2geom(motion_dt);
+                bc->drag_ptB = from_2geom(motion_dt);
+                bc->drag_ptC = from_2geom(motion_dt);
 
                 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;
@@ -387,6 +387,13 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven
             sp_box3d_drag(*bc, event->motion.state);
 
             ret = TRUE;
+        } else if (sp_event_context_knot_mouseover(bc)) {
+            SnapManager &m = desktop->namedview->snap_manager;
+            m.setup(desktop);
+
+            Geom::Point const motion_w(event->motion.x, event->motion.y);
+            Geom::Point motion_dt(desktop->w2d(motion_w));
+            m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
         }
         break;
     case GDK_BUTTON_RELEASE:
index bfdef103213dfb7f8775cd97592c6ef12dbbd3ba..294e129b3f4e40bdda229aeedd30fd44d9bbb9f8 100644 (file)
@@ -976,6 +976,9 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons
                 /* This is perfectly valid */
                 break;
             default:
+                if (sp_event_context_knot_mouseover(cc)) {
+                    m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE));
+                }
                 break;
         }
     }
index dd80524f1614eafe20f1ab43e2e42723f87dc758..b135dd9fe7640c1cf051df06411562ae0076afbd 100644 (file)
@@ -43,7 +43,7 @@ SnapIndicator::~SnapIndicator()
 }
 
 void
-SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p)
+SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap)
 {
     remove_snaptarget(); //only display one snaptarget at a time
 
@@ -220,7 +220,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p)
                                             "anchor", GTK_ANCHOR_CENTER,
                                             "size", 10.0,
                                             "stroked", TRUE,
-                                            "stroke_color", 0xff0000ff,
+                                            "stroke_color", pre_snap ? 0x7f7f7fff : 0xff0000ff,
                                             "mode", SP_KNOT_MODE_XOR,
                                             "shape", SP_KNOT_SHAPE_DIAMOND,
                                             NULL );
@@ -230,7 +230,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p)
                                             "anchor", GTK_ANCHOR_CENTER,
                                             "size", 10.0,
                                             "stroked", TRUE,
-                                            "stroke_color", 0xff0000ff,
+                                            "stroke_color", pre_snap ? 0x7f7f7fff : 0xff0000ff,
                                             "mode", SP_KNOT_MODE_XOR,
                                             "shape", SP_KNOT_SHAPE_CROSS,
                                             NULL );
@@ -241,15 +241,20 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p)
         SP_CTRL(canvasitem)->moveto(p.getPoint());
         _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val);
 
+        // Display the tooltip, which reveals the type of snap source and the type of snap target
         gchar *tooltip_str = g_strconcat(source_name, _(" to "), target_name, NULL);
         Geom::Point tooltip_pos = p.getPoint() + _desktop->w2d(Geom::Point(15, -15));
 
         SPCanvasItem *canvas_tooltip = sp_canvastext_new(sp_desktop_tempgroup(_desktop), _desktop, tooltip_pos, tooltip_str);
+        if (pre_snap) {
+            SP_CANVASTEXT(canvas_tooltip)->rgba = 0x7f7f7fff;
+        }
         g_free(tooltip_str);
 
         sp_canvastext_set_anchor((SPCanvasText* )canvas_tooltip, -1, 1);
         _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val);
 
+        // Display the bounding box, if we snapped to one
         Geom::OptRect const bbox = p.getTargetBBox();
         if (bbox) {
             SPCanvasItem* box = sp_canvas_item_new(sp_desktop_tempgroup (_desktop),
@@ -257,7 +262,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p)
                                                      NULL);
 
             SP_CTRLRECT(box)->setRectangle(*bbox);
-            SP_CTRLRECT(box)->setColor(0xff0000ff, 0, 0);
+            SP_CTRLRECT(box)->setColor(pre_snap ? 0x7f7f7fff : 0xff0000ff, 0, 0);
             SP_CTRLRECT(box)->setDashed(true);
             sp_canvas_item_move_to_z(box, 0);
             _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val);
index feb118baabdf2bc9bea0855cbba69c984a903308..259af8ae6d9c73547d3d4f94214c373245700c57 100644 (file)
@@ -26,7 +26,7 @@ public:
     SnapIndicator(SPDesktop *desktop);
     virtual ~SnapIndicator();
 
-    void set_new_snaptarget(Inkscape::SnappedPoint const &p);
+    void set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap = false);
     void remove_snaptarget();
 
     void set_new_snapsource(Inkscape::SnapCandidatePoint const &p);
index 5592741d9a525cd48d0258c76c0c4e523a660040..1e47b9d9da4be0790ec4094543c7138eca6f8a2a 100644 (file)
@@ -58,6 +58,7 @@
 #include "selcue.h"
 #include "lpe-tool-context.h"
 #include "ui/tool/control-point.h"
+#include "shape-editor.h"
 
 static void sp_event_context_class_init(SPEventContextClass *klass);
 static void sp_event_context_init(SPEventContext *event_context);
@@ -743,6 +744,15 @@ gint sp_event_context_private_item_handler(SPEventContext *ec, SPItem *item,
     return ret;
 }
 
+bool sp_event_context_knot_mouseover(SPEventContext *ec)
+{
+    if (ec->shape_editor) {
+        return !(ec->shape_editor->knot_mouseover());
+    }
+
+    return false;
+}
+
 /**
  * @brief An observer that relays pref changes to the derived classes
  */
index 97abee0d5a24a1d4298aed411e87543b7799c5ba..be06f0a3411eb490b57113849fe2d974fdf7986e 100644 (file)
@@ -171,6 +171,7 @@ SPItem *sp_event_context_find_item (SPDesktop *desktop, Geom::Point const &p, bo
 SPItem *sp_event_context_over_item (SPDesktop *desktop, SPItem *item, Geom::Point const &p);
 
 ShapeEditor *sp_event_context_get_shape_editor (SPEventContext *ec);
+bool sp_event_context_knot_mouseover(SPEventContext *ec);
 
 void ec_shape_event_attr_changed(Inkscape::XML::Node *shape_repr,
                                      gchar const *name, gchar const *old_value, gchar const *new_value,
index a1fcf582b8c3f46ab6b814c3cbc760c8f20eb086..b73d258fdddfb31d1216cdd3a8b6eae2aa45891c 100644 (file)
@@ -593,6 +593,15 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event)
 
             ret = TRUE;
         } else {
+            if (sp_event_context_knot_mouseover(event_context)) {
+                SnapManager &m = desktop->namedview->snap_manager;
+                m.setup(desktop);
+
+                Geom::Point const motion_w(event->motion.x, event->motion.y);
+                Geom::Point const motion_dt = event_context->desktop->w2d(motion_w);
+                m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
+            }
+
             bool over_line = false;
             if (drag->lines) {
                 for (GSList *l = drag->lines; l != NULL; l = l->next) {
index b17e41b243bf9b640365be12de1f755cd5f9b7f4..cc26653e5f7d996af169d7556412be1a80090c11 100644 (file)
@@ -284,7 +284,7 @@ void sp_knot_start_dragging(SPKnot *knot, Geom::Point const &p, gint x, gint y,
  */
 static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot)
 {
-       g_assert(knot != NULL);
+    g_assert(knot != NULL);
     g_assert(SP_IS_KNOT(knot));
 
     /* Run client universal event handler, if present */
@@ -302,7 +302,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
     tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
 
     switch (event->type) {
-       case GDK_2BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
             if (event->button.button == 1) {
                 g_signal_emit(knot, knot_signals[DOUBLECLICKED], 0, event->button.state);
 
@@ -311,23 +311,23 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
                 consumed = TRUE;
             }
             break;
-       case GDK_BUTTON_PRESS:
+    case GDK_BUTTON_PRESS:
             if (event->button.button == 1 && !knot->desktop->event_context->space_panning) {
                 Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y));
                 sp_knot_start_dragging(knot, p, (gint) event->button.x, (gint) event->button.y, event->button.time);
-                               consumed = TRUE;
+                consumed = TRUE;
             }
             break;
-       case GDK_BUTTON_RELEASE:
-                       if (event->button.button == 1 && !knot->desktop->event_context->space_panning) {
-                               // If we have any pending snap event, then invoke it now
-                               if (knot->desktop->event_context->_delayed_snap_event) {
-                                       sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event);
-                               }
+    case GDK_BUTTON_RELEASE:
+            if (event->button.button == 1 && !knot->desktop->event_context->space_panning) {
+                // If we have any pending snap event, then invoke it now
+                if (knot->desktop->event_context->_delayed_snap_event) {
+                    sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event);
+                }
 
-                               sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
+                sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
 
-               knot->pressure = 0;
+                knot->pressure = 0;
                 if (transform_escaped) {
                     transform_escaped = false;
                     consumed = TRUE;
@@ -356,7 +356,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
                 }
             }
             break;
-       case GDK_MOTION_NOTIFY:
+    case GDK_MOTION_NOTIFY:
             if (grabbed && !knot->desktop->event_context->space_panning) {
                 consumed = TRUE;
 
@@ -389,7 +389,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
                 moved = TRUE;
             }
             break;
-       case GDK_ENTER_NOTIFY:
+    case GDK_ENTER_NOTIFY:
             sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE);
             sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
 
@@ -401,7 +401,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
             moved = FALSE;
             consumed = TRUE;
             break;
-       case GDK_LEAVE_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
             sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE);
             sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
 
@@ -413,35 +413,35 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
             moved = FALSE;
             consumed = TRUE;
             break;
-       case GDK_KEY_PRESS: // keybindings for knot
+    case GDK_KEY_PRESS: // keybindings for knot
             switch (get_group0_keyval(&event->key)) {
-                               case GDK_Escape:
-                                                       sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
-                                                       if (!nograb) {
-                                                               sp_canvas_item_ungrab(knot->item, event->button.time);
-                                                       }
-                                                       if (moved) {
-                                                               sp_knot_set_flag(knot,
-                                                                                                SP_KNOT_DRAGGING,
-                                                                                                FALSE);
-                                                               g_signal_emit(knot,
-                                                                                         knot_signals[UNGRABBED], 0,
-                                                                                         event->button.state);
-                                                               sp_document_undo(sp_desktop_document(knot->desktop));
-                                                               knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled."));
-                                                               transform_escaped = true;
-                                                               consumed = TRUE;
-                                                       }
-                                                       grabbed = FALSE;
-                                                       moved = FALSE;
-                                                       sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
-                                                       break;
-                               default:
-                                                       consumed = FALSE;
-                                                       break;
-                                       }
-                                       break;
-       default:
+                case GDK_Escape:
+                            sp_knot_set_flag(knot, SP_KNOT_GRABBED, FALSE);
+                            if (!nograb) {
+                                sp_canvas_item_ungrab(knot->item, event->button.time);
+                            }
+                            if (moved) {
+                                sp_knot_set_flag(knot,
+                                                 SP_KNOT_DRAGGING,
+                                                 FALSE);
+                                g_signal_emit(knot,
+                                              knot_signals[UNGRABBED], 0,
+                                              event->button.state);
+                                sp_document_undo(sp_desktop_document(knot->desktop));
+                                knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled."));
+                                transform_escaped = true;
+                                consumed = TRUE;
+                            }
+                            grabbed = FALSE;
+                            moved = FALSE;
+                            sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
+                            break;
+                default:
+                            consumed = FALSE;
+                            break;
+                    }
+                    break;
+    default:
             break;
     }
 
@@ -452,14 +452,14 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
 
 void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot)
 {
-       Geom::Point const motion_w(event->motion.x, event->motion.y);
-       Geom::Point const motion_dt = knot->desktop->w2d(motion_w);
-       Geom::Point p = motion_dt - knot->grabbed_rel_pos;
-       sp_knot_request_position (knot, p, event->motion.state);
-       knot->desktop->scroll_to_point (motion_dt);
-       knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different!
-       if (event->motion.state & GDK_BUTTON1_MASK)
-               gobble_motion_events(GDK_BUTTON1_MASK);
+    Geom::Point const motion_w(event->motion.x, event->motion.y);
+    Geom::Point const motion_dt = knot->desktop->w2d(motion_w);
+    Geom::Point p = motion_dt - knot->grabbed_rel_pos;
+    sp_knot_request_position (knot, p, event->motion.state);
+    knot->desktop->scroll_to_point (motion_dt);
+    knot->desktop->set_coordinate_status(knot->pos); // display the coordinate of knot, not cursor - they may be different!
+    if (event->motion.state & GDK_BUTTON1_MASK)
+        gobble_motion_events(GDK_BUTTON1_MASK);
 }
 
 /**
@@ -620,20 +620,20 @@ void sp_knot_set_flag(SPKnot *knot, guint flag, bool set)
     }
 
     switch (flag) {
-       case SP_KNOT_VISIBLE:
+    case SP_KNOT_VISIBLE:
             if (set) {
                 sp_canvas_item_show(knot->item);
             } else {
                 sp_canvas_item_hide(knot->item);
             }
             break;
-       case SP_KNOT_MOUSEOVER:
-       case SP_KNOT_DRAGGING:
+    case SP_KNOT_MOUSEOVER:
+    case SP_KNOT_DRAGGING:
             sp_knot_set_ctrl_state(knot);
             break;
-       case SP_KNOT_GRABBED:
+    case SP_KNOT_GRABBED:
             break;
-       default:
+    default:
             g_assert_not_reached();
             break;
     }
index 45cb140c019883787c478e928668a85c73511fd7..314ad807c5a1de383472327124a322bff06cfd6a 100644 (file)
@@ -91,6 +91,21 @@ KnotHolder::update_knots()
     }
 }
 
+/**
+ * \brief Returns true if at least one of the KnotHolderEntities has the mouse hovering above it
+ */
+bool KnotHolder::knot_mouseover()
+{
+    for(std::list<KnotHolderEntity *>::iterator i = entity.begin(); i != entity.end(); ++i) {
+        SPKnot *knot = (*i)->knot;
+        if (knot && (knot->flags & SP_KNOT_MOUSEOVER)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void
 KnotHolder::knot_clicked_handler(SPKnot *knot, guint state)
 {
index fa1abd071efd4e226efdfcc5fb470f803b8c3184..0b37d211c52079b2358621fd9a964f02b8cc5b30 100644 (file)
@@ -49,6 +49,8 @@ public:
 
     const SPItem *getItem() { return item; }
 
+    bool knot_mouseover();
+
     friend class ShapeEditor;
 
 protected:
index 6b83413e481c184a2a0745f7d8381e2a1a4fadcf..1d81aa7f5a86ef2854d5b9771d52c117de8969a0 100644 (file)
@@ -194,7 +194,7 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(0, 1)));
 
     if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry,
-                                   // resulting in a perfect circle (and not an ellipse)
+                                    // resulting in a perfect circle (and not an ellipse)
         gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
         rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp);
         rect->ry._set = rect->rx._set = true;
@@ -277,19 +277,19 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or
         Geom::Point p_handle(rect->x.computed + rect->width.computed, rect->y.computed + rect->height.computed);
 
         if (fabs(minx) > fabs(miny)) {
-               // snap to horizontal or diagonal
+            // snap to horizontal or diagonal
             if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                               rect->height.computed = MAX(h_orig + minx / ratio, 0);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->height.computed = MAX(h_orig + minx / ratio, 0);
             } else {
                 // closer to the horizontal, change only width, height is h_orig
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                               rect->height.computed = MAX(h_orig, 0);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->height.computed = MAX(h_orig, 0);
             }
             rect->width.computed = MAX(w_orig + minx, 0);
 
@@ -297,16 +297,16 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or
             // snap to vertical or diagonal
             if (miny != 0 && fabs(minx/miny) > 0.5 * ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                       rect->width.computed = MAX(w_orig + miny * ratio, 0);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->width.computed = MAX(w_orig + miny * ratio, 0);
             } else {
                 // closer to the vertical, change only height, width is w_orig
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                               rect->width.computed = MAX(w_orig, 0);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->width.computed = MAX(w_orig, 0);
             }
             rect->height.computed = MAX(h_orig + miny, 0);
 
@@ -316,8 +316,8 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or
 
     } else {
         // move freely
-       s = snap_knot_position(p);
-       rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0);
+        s = snap_knot_position(p);
+        rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0);
         rect->height.computed = MAX(s[Geom::Y] - rect->y.computed, 0);
         rect->width._set = rect->height._set = true;
     }
@@ -367,54 +367,54 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin
         gdouble ratio = (w_orig / h_orig);
 
         if (fabs(minx) > fabs(miny)) {
-               // snap to horizontal or diagonal
+            // snap to horizontal or diagonal
             if (minx != 0 && fabs(miny/minx) > 0.5 * 1/ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-               rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y);
                 rect->height.computed = MAX(h_orig - minx / ratio, 0);
             } else {
                 // closer to the horizontal, change only width, height is h_orig
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-               rect->y.computed = MIN(origin[Geom::Y], opposite_y);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-1, 0)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->y.computed = MIN(origin[Geom::Y], opposite_y);
                 rect->height.computed = MAX(h_orig, 0);
             }
             rect->x.computed = MIN(s[Geom::X], opposite_x);
             rect->width.computed = MAX(w_orig - minx, 0);
         } else {
             // snap to vertical or diagonal
-               if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) {
+            if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) {
                 // closer to the diagonal and in same-sign quarters, change both using ratio
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                               rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(-ratio, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x);
                 rect->width.computed = MAX(w_orig - miny * ratio, 0);
             } else {
                 // closer to the vertical, change only height, width is w_orig
-               s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1)));
-                               minx = s[Geom::X] - origin[Geom::X];
-                               miny = s[Geom::Y] - origin[Geom::Y];
-                               rect->x.computed = MIN(origin[Geom::X], opposite_x);
+                s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(p_handle, Geom::Point(0, -1)));
+                minx = s[Geom::X] - origin[Geom::X];
+                miny = s[Geom::Y] - origin[Geom::Y];
+                rect->x.computed = MIN(origin[Geom::X], opposite_x);
                 rect->width.computed = MAX(w_orig, 0);
             }
             rect->y.computed = MIN(s[Geom::Y], opposite_y);
-                       rect->height.computed = MAX(h_orig - miny, 0);
+            rect->height.computed = MAX(h_orig - miny, 0);
         }
 
         rect->width._set = rect->height._set = rect->x._set = rect->y._set = true;
 
     } else {
         // move freely
-       s = snap_knot_position(p);
-       minx = s[Geom::X] - origin[Geom::X];
-               miny = s[Geom::Y] - origin[Geom::Y];
+        s = snap_knot_position(p);
+        minx = s[Geom::X] - origin[Geom::X];
+        miny = s[Geom::Y] - origin[Geom::Y];
 
-       rect->x.computed = MIN(s[Geom::X], opposite_x);
+        rect->x.computed = MIN(s[Geom::X], opposite_x);
         rect->width.computed = MAX(w_orig - minx, 0);
         rect->y.computed = MIN(s[Geom::Y], opposite_y);
         rect->height.computed = MAX(h_orig - miny, 0);
index b71bc2e54eecc5e1313beef76085050d7e8d5366..9cf4d5420ef10ad905cce0210c6206beb3183224 100644 (file)
@@ -469,7 +469,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const
                         if (pc->npoints == 0) {
 
                             Geom::Point p;
-                          if ((bevent.state & GDK_CONTROL_MASK) && (pc->polylines_only || pc->polylines_paraxial)) {
+                            if ((bevent.state & GDK_CONTROL_MASK) && (pc->polylines_only || pc->polylines_paraxial)) {
                                 p = event_dt;
                                 if (!(bevent.state & GDK_SHIFT_MASK)) {
                                     SnapManager &m = desktop->namedview->snap_manager;
@@ -479,7 +479,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const
                               spdc_create_single_dot(event_context, p, "/tools/freehand/pen", bevent.state);
                               ret = TRUE;
                               break;
-                          }
+                            }
 
                             // TODO: Perhaps it would be nicer to rearrange the following case
                             // distinction so that the case of a waiting LPE is treated separately
@@ -632,6 +632,10 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent)
                         spdc_endpoint_snap(pc, p, mevent.state);
                         spdc_pen_set_subsequent_point(pc, p, true);
                         ret = TRUE;
+                    } else if (sp_event_context_knot_mouseover(pc)) {
+                        SnapManager &m = dt->namedview->snap_manager;
+                        m.setup(dt);
+                        m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE));
                     }
                     break;
                 case SP_PEN_CONTEXT_CONTROL:
@@ -677,6 +681,11 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent)
                             pc->_message_context->clear();
                             pc->anchor_statusbar = false;
                         }
+                        if (sp_event_context_knot_mouseover(pc)) {
+                            SnapManager &m = dt->namedview->snap_manager;
+                            m.setup(dt);
+                            m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE));
+                        }
                     }
                     break;
                 case SP_PEN_CONTEXT_CONTROL:
@@ -698,6 +707,11 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent)
                     /* This is perfectly valid */
                     break;
                 default:
+                    if (sp_event_context_knot_mouseover(pc)) {
+                        SnapManager &m = dt->namedview->snap_manager;
+                        m.setup(dt);
+                        m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE));
+                    }
                     break;
             }
             break;
index acdd4d6e5d14759fc1321028e12a055b2c8ab3c5..5aa9efbd91f7add0250a9bc6c6bf9e95d86201a0 100644 (file)
@@ -295,7 +295,7 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve
 static gint
 pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mevent)
 {
-       SPDesktop *const dt = pc->desktop;
+    SPDesktop *const dt = pc->desktop;
 
     if ((mevent.state & GDK_CONTROL_MASK) && (mevent.state & GDK_BUTTON1_MASK)) {
         // mouse was accidentally moved during Ctrl+click;
@@ -395,6 +395,11 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev
                     pc->_message_context->clear();
                     pc->anchor_statusbar = false;
                 }
+                if (sp_event_context_knot_mouseover(pc)) {
+                    SnapManager &m = dt->namedview->snap_manager;
+                    m.setup(dt);
+                    m.preSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE));
+                }
             }
             break;
     }
index dcc1f0aa1309a4049da77e3cbfc1f078d6b7a9c3..9eab188ddea51a9a1ee0f87327be2bdb4ab8d600 100644 (file)
@@ -317,6 +317,13 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent
             sp_rect_drag(*rc, motion_dt, event->motion.state); // this will also handle the snapping
             gobble_motion_events(GDK_BUTTON1_MASK);
             ret = TRUE;
+        } else if (sp_event_context_knot_mouseover(rc)) {
+            SnapManager &m = desktop->namedview->snap_manager;
+            m.setup(desktop);
+
+            Geom::Point const motion_w(event->motion.x, event->motion.y);
+            Geom::Point motion_dt(desktop->w2d(motion_w));
+            m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
         }
         break;
     case GDK_BUTTON_RELEASE:
index 7002c972356accbcd98339de0555e4fd78a99f13..e3b6d65c284e66b8a5b300743eb863cf868297fc 100644 (file)
@@ -226,6 +226,16 @@ bool ShapeEditor::has_selection() {
     return false; //  so far, knotholder cannot have selection
 }
 
+/**
+ * \brief Returns true if this ShapeEditor has a knot above which the mouse currently hovers
+ */
+bool ShapeEditor::knot_mouseover()
+{
+    if (this->knotholder) {
+        return knotholder->knot_mouseover();
+    }
+}
+
 /*
   Local Variables:
   mode:c++
index 2374d6ac645bd5d28a3c08f78d014b594130d012..f400244b326ac40b8ad73512af8181007c7caa27 100644 (file)
@@ -62,6 +62,8 @@ public:
     // this one is only public because it's called from non-C++ repr changed callback
     void shapeeditor_event_attr_changed(gchar const *name);
 
+    bool knot_mouseover();
+
 private:
     bool has_knotholder ();
     void reset_item (SubType type, bool keep_knotholder = true);
index 4727c7b3e2f78cbfad54bf5caa5faba671c2a63d..9ee575e22e789731df282b06058af3884179e8ad 100644 (file)
@@ -214,6 +214,22 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const
     return findBestSnap(p, sc, false);
 }
 
+void SnapManager::preSnap(Inkscape::SnapCandidatePoint const &p)
+{
+    // setup() must have been called before calling this method!
+
+    if (_snapindicator) {
+        _snapindicator = false; // prevent other methods from drawing a snap indicator; we want to control this here
+        Inkscape::SnappedPoint s = freeSnap(p);
+        if (s.getSnapped()) {
+            _desktop->snapindicator->set_new_snaptarget(s, true);
+        } else {
+            _desktop->snapindicator->remove_snaptarget();
+        }
+        _snapindicator = true; // restore the original value
+    }
+}
+
 /**
  * \brief Snap to the closest multiple of a grid pitch
  *
index 24a60eaf0ce152c6b85dfcbd87cc083d7171de26..613550376aca3d485f3f33536631358494aa2d51 100644 (file)
@@ -105,6 +105,8 @@ public:
     Inkscape::SnappedPoint freeSnap(Inkscape::SnapCandidatePoint const &p,
                                     Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
 
+    void preSnap(Inkscape::SnapCandidatePoint const &p);
+
     Geom::Point multipleOfGridPitch(Geom::Point const &t) const;
 
     // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
index d751fae6dbc75781f3e0917b820300916e3a1533..f8a4bddfb8c4f0b81f2ab322e363f6a95b15482a 100644 (file)
@@ -277,6 +277,13 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event)
                 gobble_motion_events(GDK_BUTTON1_MASK);
 
                 ret = TRUE;
+            } else if (sp_event_context_knot_mouseover(sc)) {
+                SnapManager &m = desktop->namedview->snap_manager;
+                m.setup(desktop);
+
+                Geom::Point const motion_w(event->motion.x, event->motion.y);
+                Geom::Point motion_dt(desktop->w2d(motion_w));
+                m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
             }
             break;
         case GDK_BUTTON_RELEASE:
index f67ca434d26c60311ebcd0b59e24f9d299831c43..693d5188860d9c07eaeb10619dcbf41a80dbbd93 100644 (file)
@@ -291,6 +291,13 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent
             gobble_motion_events(GDK_BUTTON1_MASK);
 
             ret = TRUE;
+        } else if (sp_event_context_knot_mouseover(event_context)) {
+            SnapManager &m = desktop->namedview->snap_manager;
+            m.setup(desktop);
+
+            Geom::Point const motion_w(event->motion.x, event->motion.y);
+            Geom::Point motion_dt(desktop->w2d(motion_w));
+            m.preSnap(Inkscape::SnapCandidatePoint(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE));
         }
         break;
     case GDK_BUTTON_RELEASE:
@@ -472,13 +479,13 @@ sp_star_finish (SPStarContext * sc)
     sc->_message_context->clear();
 
     if (sc->item != NULL) {
-       SPStar *star = SP_STAR(sc->item);
-       if (star->r[1] == 0) {
-               sp_star_cancel(sc); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point
-               return;
-       }
+        SPStar *star = SP_STAR(sc->item);
+        if (star->r[1] == 0) {
+            sp_star_cancel(sc); // Don't allow the creating of zero sized arc, for example when the start and and point snap to the snap grid point
+            return;
+        }
 
-       SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop;
+        SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop;
         SPObject *object = SP_OBJECT(sc->item);
 
         sp_shape_set_shape(SP_SHAPE(sc->item));
@@ -497,14 +504,14 @@ sp_star_finish (SPStarContext * sc)
 
 static void sp_star_cancel(SPStarContext *sc)
 {
-       SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop;
+    SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop;
 
-       sp_desktop_selection(desktop)->clear();
-       sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0);
+    sp_desktop_selection(desktop)->clear();
+    sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0);
 
     if (sc->item != NULL) {
-       SP_OBJECT(sc->item)->deleteObject();
-       sc->item = NULL;
+        SP_OBJECT(sc->item)->deleteObject();
+        sc->item = NULL;
     }
 
     sc->within_tolerance = false;
index 6db29ec4212abd32558644fd3b9524fcc4fca0e8..024bf8d74940499d69b478a3cdb14fab48504b1e 100644 (file)
@@ -28,27 +28,27 @@ class SPStarContext;
 class SPStarContextClass;
 
 struct SPStarContext : public SPEventContext {
-       SPItem *item;
-       Geom::Point center;
-
-       /* Number of corners */
-       gint magnitude;
-       /* Outer/inner radius ratio */
-       gdouble proportion;
-       /* flat sides or not? */
-       bool isflatsided;
-       /* rounded corners ratio */
-       gdouble rounded;
-       // randomization
-       gdouble randomized;
+    SPItem *item;
+    Geom::Point center;
+
+    /* Number of corners */
+    gint magnitude;
+    /* Outer/inner radius ratio */
+    gdouble proportion;
+    /* flat sides or not? */
+    bool isflatsided;
+    /* rounded corners ratio */
+    gdouble rounded;
+    // randomization
+    gdouble randomized;
 
     sigc::connection sel_changed_connection;
 
-       Inkscape::MessageContext *_message_context;
+    Inkscape::MessageContext *_message_context;
 };
 
 struct SPStarContextClass {
-       SPEventContextClass parent_class;
+    SPEventContextClass parent_class;
 };
 
 GtkType sp_star_context_get_type (void);