From f780ca188e0073ffb3ec8916c12675dd4e564f66 Mon Sep 17 00:00:00 2001 From: dvlierop2 Date: Sun, 25 Jan 2009 13:35:08 +0000 Subject: [PATCH] - The snap-delay mechanism should now be more robust. From now on, it must be turned on and off explicitely within each context. This prevents delayed snapping events from being fired after the context or context's state has changed. - Creating single dots now snaps --- src/arc-context.cpp | 13 +-- src/box3d-context.cpp | 13 +-- src/connector-context.cpp | 40 +++++---- src/desktop-events.cpp | 25 +++--- src/display/sp-canvas.cpp | 171 +++++++++++++++++++++----------------- src/display/sp-canvas.h | 5 +- src/draw-context.cpp | 4 +- src/dropper-context.cpp | 6 +- src/dyna-draw-context.cpp | 28 +++---- src/gradient-context.cpp | 34 ++++---- src/knotholder.cpp | 18 +++- src/knotholder.h | 2 + src/nodepath.cpp | 92 ++++++++++---------- src/pen-context.cpp | 41 +++++---- src/pencil-context.cpp | 84 +++++++++---------- src/pencil-context.h | 1 - src/rect-context.cpp | 13 +-- src/select-context.cpp | 12 +-- src/seltrans.cpp | 4 + src/snap.cpp | 21 ++++- src/spiral-context.cpp | 13 +-- src/star-context.cpp | 19 +++-- src/text-context.cpp | 12 ++- 23 files changed, 386 insertions(+), 285 deletions(-) diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 3c8a50192..da236ae87 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -142,7 +142,7 @@ void sp_arc_context_selection_changed(Inkscape::Selection * selection, gpointer SPEventContext *ec = SP_EVENT_CONTEXT(ac); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); ec->shape_editor->set_item(item, SH_KNOTHOLDER); } @@ -221,8 +221,9 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent if (event->button.button == 1 && !event_context->space_panning) { dragging = true; + sp_canvas_set_snap_delay_active(desktop->canvas, true); ac->center = Inkscape::setup_for_drag_start(desktop, event_context, event); - + /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); @@ -252,7 +253,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - + sp_arc_drag(ac, motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); @@ -264,6 +265,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent event_context->xp = event_context->yp = 0; if (event->button.button == 1 && !event_context->space_panning) { dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the arc sp_arc_finish(ac); @@ -327,6 +329,7 @@ static gint sp_arc_context_root_handler(SPEventContext *event_context, GdkEvent sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_arc_finish(ac); @@ -462,9 +465,9 @@ static void sp_arc_finish(SPArcContext *ac) SP_OBJECT(ac->item)->updateRepr(); sp_canvas_end_forced_full_redraws(desktop->canvas); - + sp_desktop_selection(desktop)->set(ac->item); - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, _("Create ellipse")); ac->item = NULL; diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 2d20318e3..2b76233f5 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -113,7 +113,7 @@ static void sp_box3d_context_init(Box3DContext *box3d_context) box3d_context->ctrl_dragged = false; box3d_context->extruded = false; - + box3d_context->_vpdrag = NULL; new (&box3d_context->sel_changed_connection) sigc::connection(); @@ -157,7 +157,7 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g SPEventContext *ec = SP_EVENT_CONTEXT(bc); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); ec->shape_editor->set_item(item, SH_KNOTHOLDER); if (selection->perspList().size() == 1) { @@ -167,7 +167,7 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g } /* create a default perspective in document defs if none is present - (can happen after 'vacuum defs' or when a pre-0.46 file is opened) */ + (can happen after 'vacuum defs' or when a pre-0.46 file is opened) */ static void sp_box3d_context_check_for_persp_in_defs(SPDocument *document) { SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); @@ -271,12 +271,13 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven event_context->xp = (gint) button_w[Geom::X]; event_context->yp = (gint) button_w[Geom::Y]; event_context->within_tolerance = true; - + // remember clicked item, *not* disregarding groups (since a 3D box is a group), honoring Alt event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, event->button.state & GDK_CONTROL_MASK); dragging = true; - + sp_canvas_set_snap_delay_active(desktop->canvas, true); + /* */ Geom::Point button_dt(desktop->w2d(button_w)); bc->drag_origin = from_2geom(button_dt); @@ -372,6 +373,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven event_context->xp = event_context->yp = 0; if ( event->button.button == 1 && !event_context->space_panning) { dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the box @@ -504,6 +506,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the box sp_box3d_finish(bc); diff --git a/src/connector-context.cpp b/src/connector-context.cpp index 372918b80..6fa709b18 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -291,6 +291,8 @@ sp_connector_context_setup(SPEventContext *ec) // Make sure we see all enter events for canvas items, // even if a mouse button is depressed. dt->canvas->gen_all_enter_events = true; + + sp_canvas_set_snap_delay_active(dt->canvas, true); } @@ -314,6 +316,8 @@ sp_connector_context_finish(SPEventContext *ec) // Restore the default event generating behaviour. SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(ec); desktop->canvas->gen_all_enter_events = false; + + sp_canvas_set_snap_delay_active(desktop->canvas, false); } @@ -525,7 +529,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const // Test whether we clicked on a connection point cc->sid = conn_pt_handle_test(cc, p); - + Geom::Point pt2g = to_2geom(p); if (!cc->sid) { @@ -568,12 +572,12 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const } } else if (bevent.button == 3) { if (cc->state == SP_CONNECTOR_CONTEXT_REROUTING) { - // A context menu is going to be triggered here, + // A context menu is going to be triggered here, // so end the rerouting operation. cc_connector_rerouting_finish(cc, &p); - + cc->state = SP_CONNECTOR_CONTEXT_IDLE; - + // Don't set ret to TRUE, so we drop through to the // parent handler which will open the context menu. } @@ -705,7 +709,7 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con case SP_CONNECTOR_CONTEXT_REROUTING: { cc_connector_rerouting_finish(cc, &p); - + sp_document_ensure_up_to_date(doc); cc->state = SP_CONNECTOR_CONTEXT_IDLE; return TRUE; @@ -739,14 +743,14 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval) break; case GDK_Escape: if (cc->state == SP_CONNECTOR_CONTEXT_REROUTING) { - + SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); SPDocument *doc = sp_desktop_document(desktop); cc_connector_rerouting_finish(cc, NULL); - + sp_document_undo(doc); - + cc->state = SP_CONNECTOR_CONTEXT_IDLE; desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE, _("Connector endpoint drag cancelled.")); @@ -771,7 +775,7 @@ cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p { SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); SPDocument *doc = sp_desktop_document(desktop); - + // Clear the temporary path: cc->red_curve->reset(); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(cc->red_bpath), NULL); @@ -796,7 +800,7 @@ cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p cc->clickeditem->setHidden(false); sp_conn_adjust_path(SP_PATH(cc->clickeditem)); cc->clickeditem->updateRepr(); - sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, + sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, _("Reroute connector")); cc_set_active_conn(cc, cc->clickeditem); } @@ -1005,7 +1009,7 @@ static gboolean cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) { g_assert (knot != NULL); - + g_object_ref(knot); SPConnectorContext *cc = SP_CONNECTOR_CONTEXT( @@ -1016,7 +1020,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) switch (event->type) { case GDK_ENTER_NOTIFY: sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE); - + cc->active_handle = knot; if (knot->tip) @@ -1024,24 +1028,24 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) knot->desktop->event_context->defaultMessageContext()->set( Inkscape::NORMAL_MESSAGE, knot->tip); } - + consumed = TRUE; break; case GDK_LEAVE_NOTIFY: sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE); cc->active_handle = NULL; - + if (knot->tip) { knot->desktop->event_context->defaultMessageContext()->clear(); } - + consumed = TRUE; break; default: break; } - + g_object_unref(knot); return consumed; @@ -1127,7 +1131,7 @@ static void cc_set_active_shape(SPConnectorContext *cc, SPItem *item) // Set center connection point. if ( cc->connpthandle == NULL ) { - SPKnot *knot = sp_knot_new(cc->desktop, + SPKnot *knot = sp_knot_new(cc->desktop, _("Connection point: click or drag to create a new connector")); knot->setShape(SP_KNOT_SHAPE_SQUARE); @@ -1200,7 +1204,7 @@ cc_set_active_conn(SPConnectorContext *cc, SPItem *item) // Create the handle if it doesn't exist if ( cc->endpt_handle[i] == NULL ) { - SPKnot *knot = sp_knot_new(cc->desktop, + SPKnot *knot = sp_knot_new(cc->desktop, _("Connector endpoint: drag to reroute or connect to new shapes")); knot->setShape(SP_KNOT_SHAPE_SQUARE); diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index e2c3ba40e..fbbbfee19 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -88,6 +88,7 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge case GDK_BUTTON_PRESS: if (event->button.button == 1) { dragging = true; + sp_canvas_set_snap_delay_active(desktop->canvas, true); Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win)); Geom::Point const event_dt(desktop->w2d(event_w)); @@ -142,14 +143,14 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge if (dragging) { Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win)); Geom::Point event_dt(desktop->w2d(event_w)); - + SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.guideSnap(event_dt, normal); - + sp_guideline_set_position(SP_GUIDELINE(guide), from_2geom(event_dt)); desktop->set_coordinate_status(to_2geom(event_dt)); - desktop->setPosition(to_2geom(event_dt)); + desktop->setPosition(to_2geom(event_dt)); } break; case GDK_BUTTON_RELEASE: @@ -157,12 +158,13 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge gdk_pointer_ungrab(event->button.time); Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win)); Geom::Point event_dt(desktop->w2d(event_w)); - + SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.guideSnap(event_dt, normal); - + dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); gtk_object_destroy(GTK_OBJECT(guide)); guide = NULL; if ((horiz ? wy : wx) >= 0) { @@ -172,7 +174,7 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge sp_repr_set_point(repr, "position", from_2geom(event_dt)); SP_OBJECT_REPR(desktop->namedview)->appendChild(repr); Inkscape::GC::release(repr); - sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, + sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, _("Create guide")); } desktop->set_coordinate_status(from_2geom(event_dt)); @@ -209,6 +211,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) case GDK_2BUTTON_PRESS: if (event->button.button == 1) { dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); sp_canvas_item_ungrab(item, event->button.time); Inkscape::UI::Dialogs::GuidelinePropertiesDialog::showDialog(guide, desktop); ret = TRUE; @@ -224,6 +227,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) break; } dragging = true; + sp_canvas_set_snap_delay_active(desktop->canvas, true); sp_canvas_item_grab(item, ( GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | @@ -238,13 +242,13 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(to_2geom(desktop->w2d(from_2geom(motion_w)))); - - // This is for snapping while dragging existing guidelines. New guidelines, + + // This is for snapping while dragging existing guidelines. New guidelines, // which are dragged off the ruler, are being snapped in sp_dt_ruler_event SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.guideSnap(motion_dt, to_2geom(guide->normal_to_line)); - + sp_guide_moveto(*guide, from_2geom(motion_dt), false); moved = true; desktop->set_coordinate_status(from_2geom(motion_dt)); @@ -280,6 +284,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) desktop->setPosition (from_2geom(event_dt)); } dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); sp_canvas_item_ungrab(item, event->button.time); ret=TRUE; } @@ -406,7 +411,7 @@ void snoop_extended(GdkEvent* event, SPDesktop *desktop) // device shows up. it->second = tools_active(desktop); } - + it = toolToUse.find(name); if (it != toolToUse.end() ) { tools_switch(desktop, it->second); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index e5ef2c80d..edd64f021 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -946,8 +946,8 @@ static void sp_canvas_dirty_rect(SPCanvas* canvas, int nl, int nt, int nr, int n static void sp_canvas_mark_rect(SPCanvas* canvas, int nl, int nt, int nr, int nb, uint8_t val); static int do_update (SPCanvas *canvas); -static gboolean sp_canvas_snap_watchdog_callback(gpointer data); -static void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event); +static gboolean sp_canvas_snap_watchdog_callback(gpointer data); +static void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event); static void sp_canvas_snap_watchdog_kill(SPCanvas *canvas); /** @@ -1049,6 +1049,7 @@ sp_canvas_init (SPCanvas *canvas) canvas->watchdog_id = 0; canvas->watchdog_event = NULL; + canvas->context_snap_delay_active = false; } /** @@ -1234,7 +1235,7 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) } widget->allocation = *allocation; - + if (GTK_WIDGET_REALIZED (widget)) { gdk_window_move_resize (widget->window, widget->allocation.x, widget->allocation.y, @@ -1531,12 +1532,12 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - if (dt) { + if (dt) { // Snapping will be on hold if we're moving the mouse at high speeds. When starting - // drawing a new shape we really should snap though. + // drawing a new shape we really should snap though. dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); } - + /* Pick the current item as if the button were not pressed, and * then process the event. */ @@ -1547,8 +1548,8 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) break; case GDK_BUTTON_RELEASE: - sp_canvas_snap_watchdog_callback(canvas); // If we have any pending snapping action, then invoke it now - + sp_canvas_snap_watchdog_callback(canvas); // If we have any pending snapping action, then invoke it now + /* Process the event as if the button were pressed, then repick * after the button has been released */ @@ -1558,7 +1559,7 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); event->state ^= mask; - + break; default: @@ -1594,7 +1595,7 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) { static guint32 prev_time; static boost::optional prev_pos; - + int status; SPCanvas *canvas = SP_CANVAS (widget); @@ -1605,61 +1606,53 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) if (canvas->pixmap_gc == NULL) // canvas being deleted return FALSE; - + SPDesktop *dt = SP_ACTIVE_DESKTOP; - + // Snap when speed drops below e.g. 0.02 px/msec, or when no motion events have occured for some period. // i.e. snap when we're at stand still. A speed threshold enforces snapping for tablets, which might never // be fully at stand still and might keep spitting out motion events. - if (dt) { - bool const c1 = event->type == GDK_MOTION_NOTIFY; - bool const c21 = event->state & GDK_BUTTON1_MASK; // Snapping only occurs when dragging with the left mouse button down - bool const c22 = event->state & GDK_BUTTON2_MASK; // We shouldn't hold back any events when other mouse buttons have been - bool const c23 = event->state & GDK_BUTTON3_MASK; // pressed, e.g. when scrolling with the middle mouse button; if we do then - // Inkscape will get stuck in an unresponsive state - bool const c3 = dt->namedview->snap_manager.snapprefs.getSnapEnabledGlobally(); - if (c1 && c21 && (!c22) && (!c23) && c3) { - Geom::Point event_pos(event->x, event->y); - guint32 event_t = gdk_event_get_time ( (GdkEvent *) event ); - - dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold - - if (prev_pos) { - Geom::Coord dist = Geom::L2(event_pos - *prev_pos); - guint32 delta_t = event_t - prev_time; - gdouble speed = delta_t > 0 ? dist/delta_t : 1000; - // std::cout << "speed = " << speed << " px/msec " << "| time passed = " << delta_t << " msec" << std::endl; - if (speed > 0.02) { // Jitter threshold, might be needed for tablets - // We're moving fast, so postpone any snapping until the next GDK_MOTION_NOTIFY event. We - // will keep on postponing the snapping as long as the speed is high. - // We must snap at some point in time though, so set a watchdog timer at some time from - // now, just in case there's no future motion event that drops under the speed limit (when - // stoppping abruptly) - sp_canvas_snap_watchdog_kill(canvas); - sp_canvas_snap_watchdog_set(canvas, event); // watchdog is reset, i.e. pushed forward in time - // If the watchdog expires before a new motion event is received, we will snap (as explained - // above). This means however that when the timer is too short, we will always snap and that the - // speed threshold is ineffective. In the extreme case the delay is set to zero, and snapping will - // be immediate, as it used to be in the old days ;-). - } else { // Speed is very low, so we're virtually at stand still - // But if we're really standing still, then we should snap now. We could use some low-pass filtering, - // otherwise snapping occurs for each jitter movement. For this filtering we'll leave the watchdog to expire, - // snap, and set a new watchdog again. - if (canvas->watchdog_id == 0) { // no watchdog has been set - // it might have already expired, so we'll set a new one; the snapping frequency will be limited by this - sp_canvas_snap_watchdog_set(canvas, event); - } // else: watchdog has been set before and we'll wait for it to expire - } - } else { - // This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog - sp_canvas_snap_watchdog_set(canvas, event); + if (canvas->context_snap_delay_active && dt && dt->namedview->snap_manager.snapprefs.getSnapEnabledGlobally()) { + Geom::Point event_pos(event->x, event->y); + guint32 event_t = gdk_event_get_time ( (GdkEvent *) event ); + + dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold + + if (prev_pos) { + Geom::Coord dist = Geom::L2(event_pos - *prev_pos); + guint32 delta_t = event_t - prev_time; + gdouble speed = delta_t > 0 ? dist/delta_t : 1000; + // std::cout << "speed = " << speed << " px/msec " << "| time passed = " << delta_t << " msec" << std::endl; + if (speed > 0.02) { // Jitter threshold, might be needed for tablets + // We're moving fast, so postpone any snapping until the next GDK_MOTION_NOTIFY event. We + // will keep on postponing the snapping as long as the speed is high. + // We must snap at some point in time though, so set a watchdog timer at some time from + // now, just in case there's no future motion event that drops under the speed limit (when + // stopping abruptly) + sp_canvas_snap_watchdog_kill(canvas); + sp_canvas_snap_watchdog_set(canvas, event); // watchdog is reset, i.e. pushed forward in time + // If the watchdog expires before a new motion event is received, we will snap (as explained + // above). This means however that when the timer is too short, we will always snap and that the + // speed threshold is ineffective. In the extreme case the delay is set to zero, and snapping will + // be immediate, as it used to be in the old days ;-). + } else { // Speed is very low, so we're virtually at stand still + // But if we're really standing still, then we should snap now. We could use some low-pass filtering, + // otherwise snapping occurs for each jitter movement. For this filtering we'll leave the watchdog to expire, + // snap, and set a new watchdog again. + if (canvas->watchdog_id == 0) { // no watchdog has been set + // it might have already expired, so we'll set a new one; the snapping frequency will be limited by this + sp_canvas_snap_watchdog_set(canvas, event); + } // else: watchdog has been set before and we'll wait for it to expire } - - prev_pos = event_pos; - prev_time = event_t; - } + } else { + // This is the first GDK_MOTION_NOTIFY event, so postpone snapping and set the watchdog + sp_canvas_snap_watchdog_set(canvas, event); + } + + prev_pos = event_pos; + prev_time = event_t; } - + canvas->state = event->state; pick_current_item (canvas, (GdkEvent *) event); @@ -1672,50 +1665,80 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) return status; } -gboolean sp_canvas_snap_watchdog_callback(gpointer data) +gboolean sp_canvas_snap_watchdog_callback(gpointer data) { - // Snap NOW! For this the "postponed" flag will be reset and an the last motion event will be repeated + // Snap NOW! For this the "postponed" flag will be reset and an the last motion event will be repeated SPCanvas *canvas = reinterpret_cast(data); if (!canvas->watchdog_event) { return FALSE; - } - + } + SPDesktop *dt = SP_ACTIVE_DESKTOP; if (dt) { dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); } - + emit_event(canvas, canvas->watchdog_event); gdk_event_free(canvas->watchdog_event); canvas->watchdog_event = NULL; canvas->watchdog_id = 0; - + return FALSE; } -void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event) +void sp_canvas_snap_watchdog_set(SPCanvas *canvas, GdkEventMotion *event) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double value = prefs->getDoubleLimited("/options/snapdelay/value", 0, 0, 1000); g_assert(canvas->watchdog_id == 0); canvas->watchdog_id = g_timeout_add(value, &sp_canvas_snap_watchdog_callback, canvas); g_assert(canvas->watchdog_event == NULL); - canvas->watchdog_event = gdk_event_copy( (GdkEvent *) event); + canvas->watchdog_event = gdk_event_copy( (GdkEvent *) event); } -void sp_canvas_snap_watchdog_kill(SPCanvas *canvas) +void sp_canvas_snap_watchdog_kill(SPCanvas *canvas) { - if (canvas->watchdog_id) { + if (canvas->watchdog_id) { g_source_remove(canvas->watchdog_id); // Kill the watchdog canvas->watchdog_id = 0; } - + if (canvas->watchdog_event) { gdk_event_free(canvas->watchdog_event); canvas->watchdog_event = NULL; } } - + +void sp_canvas_set_snap_delay_active(SPCanvas *canvas, bool snapping) +{ + // Only when canvas->context_snap_delay_active has been set, Inkscape will know that snapping is active + // and will delay any snapping events (but only when asked to through the preferences) + + // When snapping is being delayed, then that will also mean that at some point the last event + // might be re-triggered. This should only occur when Inkscape is still in the same tool or context, + // and even more specifically, the tool should even be in the same state. If for example snapping is being delayed while + // creating a rectangle, then the rect-context will be active and it will be in the "dragging" state + // (see the static boolean variable "dragging" in the sp_rect_context_root_handler). The procedure is + // as follows: call sp_canvas_set_snap_delay_active(*, TRUE) when entering the "dragging" state, which will delay + // snapping from that moment on, and call sp_canvas_set_snap_delay_active(*, FALSE) when leaving the "dragging" + // state. This last call will also make sure that any pending snap events will be canceled. + + if (!canvas) { + g_warning("sp_canvas_set_snap_delay_active() has been called without providing a canvas!"); + return; + } + + if (canvas->context_snap_delay_active == snapping) { + g_warning("Snapping was already allowed or disallowed! This is a bug, please report it."); + } + + canvas->context_snap_delay_active = snapping; + + if (snapping == false) { + sp_canvas_snap_watchdog_kill(canvas); // kill any pending snapping events + } +} + static void sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1, int draw_x1, int draw_y1, int draw_x2, int draw_y2, int sw) { @@ -1731,7 +1754,7 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1, // Mark the region clean sp_canvas_mark_rect(canvas, x0, y0, x1, y1, 0); - buf.buf_rowstride = sw * 4; + buf.buf_rowstride = sw * 4; buf.rect.x0 = x0; buf.rect.y0 = y0; buf.rect.x1 = x1; @@ -2020,7 +2043,7 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) } else { // paths only, so 1M works faster // 1M is the cached buffer and we need 4 channels - setup.max_pixels = 262144; + setup.max_pixels = 262144; } // Start the clock @@ -2282,7 +2305,7 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, int ix = (int) round(cx); // ix and iy are the new canvas coordinates (integer screen pixels) int iy = (int) round(cy); // cx might be negative, so (int)(cx + 0.5) will not do! - int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the + int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the int dy = iy - canvas->y0; // canvas w.r.t its previous position canvas->dx0 = cx; // here the 'd' stands for double, not delta! diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 2c416b8a7..cb63374e1 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -193,9 +193,10 @@ struct SPCanvas { Geom::Rect getViewbox() const; NR::IRect getViewboxIntegers() const; - + guint watchdog_id; GdkEvent *watchdog_event; + bool context_snap_delay_active; }; GtkWidget *sp_canvas_new_aa(); @@ -217,6 +218,8 @@ void sp_canvas_world_to_window(SPCanvas const *canvas, double worldx, double wor Geom::Point sp_canvas_window_to_world(SPCanvas const *canvas, Geom::Point const win); Geom::Point sp_canvas_world_to_window(SPCanvas const *canvas, Geom::Point const world); +void sp_canvas_set_snap_delay_active(SPCanvas *canvas, bool snapping); + #endif // SEEN_SP_CANVAS_H /* diff --git a/src/draw-context.cpp b/src/draw-context.cpp index 98fee29bf..5e3ff82dc 100644 --- a/src/draw-context.cpp +++ b/src/draw-context.cpp @@ -697,7 +697,7 @@ spdc_flush_white(SPDrawContext *dc, SPCurve *gc) item->updateRepr(); } - sp_document_done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL, + sp_document_done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL, _("Draw path")); // When quickly drawing several subpaths with Shift, the next subpath may be finished and @@ -834,7 +834,7 @@ void spdc_create_single_dot(SPEventContext *ec, Geom::Point const &pt, char cons /* put the circle where the mouse click occurred and set the diameter to the current stroke width, multiplied by the amount specified in the preferences */ Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - + Geom::Matrix const i2d (sp_item_i2d_affine (item)); Geom::Point pp = pt * i2d; double rad = 0.5 * prefs->getDouble(tool_path + "/dot-size", 3.0); diff --git a/src/dropper-context.cpp b/src/dropper-context.cpp index 1f6842a5c..985e3ac51 100644 --- a/src/dropper-context.cpp +++ b/src/dropper-context.cpp @@ -144,11 +144,11 @@ guint32 sp_dropper_context_get_color(SPEventContext *ec) { SPDropperContext *dc = SP_DROPPER_CONTEXT(ec); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - + int pick = prefs->getInt("/tools/dropper/pick", SP_DROPPER_PICK_VISIBLE); bool setalpha = prefs->getBool("/tools/dropper/setalpha", true); - + return SP_RGBA32_F_COMPOSE(dc->R, dc->G, dc->B, (pick == SP_DROPPER_PICK_ACTUAL && setalpha) ? dc->alpha : 1.0); } @@ -324,7 +324,7 @@ static gint sp_dropper_context_root_handler(SPEventContext *event_context, GdkEv if (!(sp_desktop_selection(desktop)->isEmpty())) { - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_DROPPER, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_DROPPER, _("Set picked color")); } diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index 8cab1690b..75aef13ef 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -335,7 +335,7 @@ sp_dyna_draw_apply(SPDynaDrawContext *dc, Geom::Point p) // If force is below the absolute threshold DYNA_EPSILON, // or we haven't yet reached DYNA_VEL_START (i.e. at the beginning of stroke) // _and_ the force is below the (higher) DYNA_EPSILON_START threshold, - // discard this move. + // discard this move. // This prevents flips, blobs, and jerks caused by microscopic tremor of the tablet pen, // especially bothersome at the start of the stroke where we don't yet have the inertia to // smooth them out. @@ -433,7 +433,7 @@ sp_dyna_draw_brush(SPDynaDrawContext *dc) // get the real brush point, not the same as pointer (affected by hatch tracking and/or mass // drag) Geom::Point brush = sp_dyna_draw_get_vpoint(dc, dc->cur); - Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); + Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); double trace_thick = 1; if (dc->trace_bg) { @@ -617,7 +617,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } else { dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Select a guide path to track with Ctrl")); } - } + } if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) { dc->dragging = TRUE; @@ -712,7 +712,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } else { // looks like we're starting to lose speed, // so _gradually_ let go attraction to prevent jerks - target = (dc->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL; + target = (dc->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL; } if (!IS_NAN(dot) && dot < -0.5) {// flip target = -target; @@ -735,7 +735,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } } else { - // this is the first motion event, set the dist + // this is the first motion event, set the dist dc->hatch_spacing = hatch_dist; } @@ -773,8 +773,8 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } // Draw the hatching circle if necessary - if (event->motion.state & GDK_CONTROL_MASK) { - if (dc->hatch_spacing == 0 && hatch_dist != 0) { + if (event->motion.state & GDK_CONTROL_MASK) { + if (dc->hatch_spacing == 0 && hatch_dist != 0) { // Haven't set spacing yet: gray, center free, update radius live Geom::Point c = desktop->w2d(motion_w); Geom::Matrix const sm (Geom::Scale(hatch_dist, hatch_dist) * Geom::Translate(c)); @@ -859,7 +859,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, dc->hatch_livarot_path = NULL; dc->just_started_drawing = false; - if (dc->hatch_spacing != 0 && !dc->keep_selected) { + if (dc->hatch_spacing != 0 && !dc->keep_selected) { // we do not select the newly drawn path, so increase spacing by step if (dc->hatch_spacing_step == 0) { dc->hatch_spacing_step = dc->hatch_spacing; @@ -1026,7 +1026,7 @@ set_to_accumulated(SPDynaDrawContext *dc, bool unionize) } else { if (dc->keep_selected) { sp_desktop_selection(desktop)->set(dc->repr); - } + } } } else { @@ -1036,14 +1036,14 @@ set_to_accumulated(SPDynaDrawContext *dc, bool unionize) dc->repr = NULL; } - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_CALLIGRAPHIC, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_CALLIGRAPHIC, _("Draw calligraphic stroke")); } static void add_cap(SPCurve *curve, Geom::Point const &from, - Geom::Point const &to, + Geom::Point const &to, double rounding) { if (Geom::L2( to - from ) > DYNA_EPSILON) { @@ -1062,7 +1062,7 @@ accumulate_calligraphic(SPDynaDrawContext *dc) dc->cal1->is_empty() || dc->cal2->is_empty() || (dc->cal1->get_segment_count() <= 0) || - dc->cal1->first_path()->closed() + dc->cal1->first_path()->closed() ) { dc->cal1->reset(); dc->cal2->reset(); @@ -1072,7 +1072,7 @@ accumulate_calligraphic(SPDynaDrawContext *dc) SPCurve *rev_cal2 = dc->cal2->create_reverse(); if ( (rev_cal2->get_segment_count() <= 0) || - rev_cal2->first_path()->closed() + rev_cal2->first_path()->closed() ) { rev_cal2->unref(); dc->cal1->reset(); @@ -1089,7 +1089,7 @@ accumulate_calligraphic(SPDynaDrawContext *dc) !dc_cal1_firstseg || !rev_cal2_firstseg || !dc_cal1_lastseg || - !rev_cal2_lastseg + !rev_cal2_lastseg ) { rev_cal2->unref(); dc->cal1->reset(); diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index b4f52a7c9..e9b46a2c2 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -114,6 +114,8 @@ static void sp_gradient_context_dispose(GObject *object) SPGradientContext *rc = SP_GRADIENT_CONTEXT(object); SPEventContext *ec = SP_EVENT_CONTEXT(object); + sp_canvas_set_snap_delay_active(ec->desktop->canvas, false); + ec->enableGrDrag(false); if (rc->_message_context) { @@ -140,7 +142,7 @@ const gchar *gr_handle_descr [] = { N_("Radial gradient mid stop") }; -static void +static void gradient_selection_changed (Inkscape::Selection *, gpointer data) { SPGradientContext *rc = (SPGradientContext *) data; @@ -216,6 +218,8 @@ static void sp_gradient_context_setup(SPEventContext *ec) rc->selcon = new sigc::connection (selection->connectChanged( sigc::bind (sigc::ptr_fun(&gradient_selection_changed), rc))); rc->subselcon = new sigc::connection (ec->desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(&gradient_subselection_changed), rc))); gradient_selection_changed(selection, rc); + + sp_canvas_set_snap_delay_active(ec->desktop->canvas, true); } void @@ -271,7 +275,7 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi // remember the coord of the dragger to reselect it later coords.push_back(dragger->point); // for all draggables of dragger - for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { + for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { GrDraggable *d = (GrDraggable *) j->data; // find the gradient @@ -279,9 +283,9 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false); // these draggable types cannot have a next draggabe to insert a stop between them - if (d->point_type == POINT_LG_END || - d->point_type == POINT_RG_FOCUS || - d->point_type == POINT_RG_R1 || + if (d->point_type == POINT_LG_END || + d->point_type == POINT_RG_FOCUS || + d->point_type == POINT_RG_R1 || d->point_type == POINT_RG_R2) { continue; } @@ -299,7 +303,7 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi // if there's a next stop, if (next_stop) { GrDragger *dnext = NULL; - // find its dragger + // find its dragger // (complex because it may have different types, and because in radial, // more than one dragger may correspond to a stop, so we must distinguish) if (type == POINT_LG_BEGIN || type == POINT_LG_MID) { @@ -311,14 +315,14 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi if (type == POINT_RG_CENTER || type == POINT_RG_MID1) { if (next_stop == last_stop) dnext = drag->getDraggerFor (item, POINT_RG_R1, p_i+1, fs); - else + else dnext = drag->getDraggerFor (item, POINT_RG_MID1, p_i+1, fs); - } - if ((type == POINT_RG_MID2) || + } + if ((type == POINT_RG_MID2) || (type == POINT_RG_CENTER && dnext && !dnext->isSelected())) { if (next_stop == last_stop) dnext = drag->getDraggerFor (item, POINT_RG_R2, p_i+1, fs); - else + else dnext = drag->getDraggerFor (item, POINT_RG_MID2, p_i+1, fs); } } @@ -354,7 +358,7 @@ sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc) if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) { // if a single stop is selected, add between that stop and the next one GrDragger *dragger = (GrDragger *) drag->selected->data; - for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { + for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { GrDraggable *d = (GrDraggable *) j->data; SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false); @@ -428,10 +432,10 @@ sp_gradient_simplify(SPGradientContext *rc, double tolerance) guint32 const c0 = sp_stop_get_rgba32(stop0); guint32 const c2 = sp_stop_get_rgba32(stop2); guint32 const c1r = sp_stop_get_rgba32(stop1); - guint32 c1 = average_color (c0, c2, + guint32 c1 = average_color (c0, c2, (stop1->offset - stop0->offset) / (stop2->offset - stop0->offset)); - double diff = + double diff = sqr(SP_RGBA32_R_F(c1) - SP_RGBA32_R_F(c1r)) + sqr(SP_RGBA32_G_F(c1) - SP_RGBA32_G_F(c1r)) + sqr(SP_RGBA32_B_F(c1) - SP_RGBA32_B_F(c1r)) + @@ -630,7 +634,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) } else { dragging = false; - // unless clicked with Ctrl (to enable Ctrl+doubleclick). + // unless clicked with Ctrl (to enable Ctrl+doubleclick). if (event->button.state & GDK_CONTROL_MASK) { ret = TRUE; break; @@ -667,7 +671,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) event_context->item_to_select = NULL; ret = TRUE; } - Inkscape::Rubberband::get(desktop)->stop(); + Inkscape::Rubberband::get(desktop)->stop(); } break; case GDK_KEY_PRESS: diff --git a/src/knotholder.cpp b/src/knotholder.cpp index 0cb9fc423..eaf5658f8 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -30,6 +30,8 @@ #include "sp-pattern.h" #include "style.h" #include "live_effects/lpeobject.h" +#include "desktop.h" +#include "display/sp-canvas.h" #include "xml/repr.h" // for debugging only @@ -53,6 +55,8 @@ KnotHolder::KnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFun this->repr = repr; this->local_change = FALSE; + + this->dragging = false; } KnotHolder::~KnotHolder() { @@ -89,7 +93,7 @@ KnotHolder::update_knots() void KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) { - KnotHolder *knot_holder = this; + KnotHolder *knot_holder = this; for(std::list::iterator i = knot_holder->entity.begin(); i != knot_holder->entity.end(); ++i) { KnotHolderEntity *e = *i; @@ -133,7 +137,12 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) void KnotHolder::knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state) { - // this was a local change and the knotholder does not need to be recreated: + if (this->dragging == false) { + this->dragging = true; + sp_canvas_set_snap_delay_active(desktop->canvas, true); + } + + // this was a local change and the knotholder does not need to be recreated: this->local_change = TRUE; for(std::list::iterator i = this->entity.begin(); i != this->entity.end(); ++i) { @@ -155,7 +164,10 @@ KnotHolder::knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state) void KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/) { - if (this->released) { + this->dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); + + if (this->released) { this->released(this->item); } else { SPObject *object = (SPObject *) this->item; diff --git a/src/knotholder.h b/src/knotholder.h index 310adab61..fa1abd071 100644 --- a/src/knotholder.h +++ b/src/knotholder.h @@ -60,6 +60,8 @@ protected: SPKnotHolderReleasedFunc released; gboolean local_change; ///< if true, no need to recreate knotholder if repr was changed. + + bool dragging; }; /** diff --git a/src/nodepath.cpp b/src/nodepath.cpp index add070d1f..cc38acbe5 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -306,7 +306,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(object)); if (lpe && lpe->isVisible() && lpe->showOrigPath()) { np->show_helperpath = true; - } + } } np->straight_path = false; if (IS_LIVEPATHEFFECT(object) && item) { @@ -314,7 +314,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, } else { np->item = SP_ITEM(object); } - + np->drag_origin_mouse = Geom::Point(NR_HUGE, NR_HUGE); // we need to update item's transform from the repr here, @@ -1064,7 +1064,7 @@ static void sp_nodepath_set_line_type(Inkscape::NodePath::Node *end, NRPathcode start->type = Inkscape::NodePath::NODE_SMOOTH; if (end->type == Inkscape::NodePath::NODE_AUTO) end->type = Inkscape::NodePath::NODE_SMOOTH; - + start->n.pos = start->pos; end->p.pos = end->pos; @@ -1152,10 +1152,10 @@ sp_node_side_is_line (Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeSi other_to_me = &othernode->n; } else if (&node->n == side) { other_to_me = &othernode->p; - } + } if (!other_to_me) return false; - bool is_line = + bool is_line = (Geom::L2(othernode->pos - other_to_me->pos) < 1e-6 && Geom::L2(node->pos - side->pos) < 1e-6); return is_line; @@ -1164,7 +1164,7 @@ sp_node_side_is_line (Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeSi /** * Same as sp_nodepath_set_node_type(), but also converts, if necessary, adjacent segments from * lines to curves. If adjacent to one line segment, pulls out or rotates opposite handle to align - * with that segment, procucing half-smooth node. If already half-smooth, pull out the second handle too. + * with that segment, procucing half-smooth node. If already half-smooth, pull out the second handle too. * If already cusp and set to cusp, retracts handles. */ void sp_nodepath_convert_node_type(Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeType type) @@ -1178,9 +1178,9 @@ void sp_nodepath_convert_node_type(Inkscape::NodePath::Node *node, Inkscape::Nod if (type == Inkscape::NodePath::NODE_SYMM || type == Inkscape::NodePath::NODE_SMOOTH) { -/* +/* Here's the algorithm of converting node to smooth (Shift+S or toolbar button), in pseudocode: - + if (two_handles) { // do nothing, adjust_handles called via set_node_type will line them up } else if (one_handle) { @@ -1337,19 +1337,19 @@ void sp_node_moveto(Inkscape::NodePath::Node *node, Geom::Point p) * Call sp_node_moveto() for node selection and handle possible snapping. */ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, Geom::Coord dx, Geom::Coord dy, - bool const snap, bool constrained = false, + bool const snap, bool constrained = false, Inkscape::Snapper::ConstraintLine const &constraint = Geom::Point()) { Geom::Point delta(dx, dy); Geom::Point best_pt = delta; Inkscape::SnappedPoint best; - - if (snap) { + + if (snap) { /* When dragging a (selected) node, it should only snap to other nodes (i.e. unselected nodes), and - * not to itself. The snapper however can not tell which nodes are selected and which are not, so we + * not to itself. The snapper however can not tell which nodes are selected and which are not, so we * must provide that information. */ - - // Build a list of the unselected nodes to which the snapper should snap + + // Build a list of the unselected nodes to which the snapper should snap std::vector unselected_nodes; for (GList *spl = nodepath->subpaths; spl != NULL; spl = spl->next) { Inkscape::NodePath::SubPath *subpath = (Inkscape::NodePath::SubPath *) spl->data; @@ -1357,20 +1357,20 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, Inkscape::NodePath::Node *node = (Inkscape::NodePath::Node *) nl->data; if (!node->selected) { unselected_nodes.push_back(to_2geom(node->pos)); - } + } } - } - + } + SnapManager &m = nodepath->desktop->namedview->snap_manager; - - // When only the node closest to the mouse pointer is to be snapped + + // When only the node closest to the mouse pointer is to be snapped // then we will not even try to snap to other points and discard those immediately Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool closest_only = prefs->getBool("/options/snapclosestonly/value", false); - + bool closest_only = prefs->getBool("/options/snapclosestonly/value", false); + Inkscape::NodePath::Node *closest_node = NULL; Geom::Coord closest_dist = NR_HUGE; - + if (closest_only) { for (GList *l = nodepath->selected; l != NULL; l = l->next) { Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; @@ -1379,25 +1379,25 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, closest_node = n; closest_dist = dist; } - } + } } - + // Iterate through all selected nodes m.setup(nodepath->desktop, false, SP_PATH(nodepath->item), &unselected_nodes); for (GList *l = nodepath->selected; l != NULL; l = l->next) { Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; if (!closest_only || n == closest_node) { //try to snap either all selected nodes or only the closest one - Inkscape::SnappedPoint s; + Inkscape::SnappedPoint s; if (constrained) { Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint; dedicated_constraint.setPoint(n->pos); s = m.constrainedSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta), dedicated_constraint); } else { s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, to_2geom(n->pos + delta)); - } - + } + if (s.getSnapped()) { - s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin)); + s.setPointerDistance(Geom::L2(nodepath->drag_origin_mouse - n->origin)); if (!s.isOtherSnapBetter(best, true)) { best = s; best_pt = from_2geom(s.getPoint()) - n->pos; @@ -1405,11 +1405,11 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, } } } - + if (best.getSnapped()) { nodepath->desktop->snapindicator->set_new_snaptarget(best); } else { - nodepath->desktop->snapindicator->remove_snaptarget(); + nodepath->desktop->snapindicator->remove_snaptarget(); } } @@ -2296,13 +2296,13 @@ static void do_node_selected_join(Inkscape::NodePath::Path *nodepath, Inkscape:: } if (b == sb->first) { - // copy all nodes from b to a, forward + // copy all nodes from b to a, forward sp_nodepath_node_new(sa, NULL,Inkscape::NodePath::NODE_CUSP, code, &p, &c, &sb->first->n.pos); for (n = sb->first->n.other; n != NULL; n = n->n.other) { sp_nodepath_node_new(sa, NULL, (Inkscape::NodePath::NodeType)n->type, (NRPathcode)n->code, &n->p.pos, &n->pos, &n->n.pos); } } else if (b == sb->last) { - // copy all nodes from b to a, backward + // copy all nodes from b to a, backward sp_nodepath_node_new(sa, NULL,Inkscape::NodePath::NODE_CUSP, code, &p, &c, &sb->last->p.pos); for (n = sb->last->p.other; n != NULL; n = n->p.other) { sp_nodepath_node_new(sa, NULL, (Inkscape::NodePath::NodeType)n->type, (NRPathcode)n->n.other->code, &n->n.pos, &n->pos, &n->p.pos); @@ -3333,7 +3333,7 @@ static void sp_node_adjust_handle(Inkscape::NodePath::Node *node, gint which_adj } if (node->type == Inkscape::NodePath::NODE_SYMM) { - // symmetrize + // symmetrize me->pos = 2 * node->pos - other->pos; return; } else { @@ -3403,16 +3403,16 @@ static void sp_node_adjust_handles_auto(Inkscape::NodePath::Node *node) Geom::Point leg_prev = to_2geom(node->p.other->pos - node->pos); Geom::Point leg_next = to_2geom(node->n.other->pos - node->pos); - + double norm_leg_prev = Geom::L2(leg_prev); double norm_leg_next = Geom::L2(leg_next); - + Geom::Point delta; if (norm_leg_next > 0.0) { delta = (norm_leg_prev / norm_leg_next) * leg_next - leg_prev; delta.normalize(); } - + node->p.pos = node->pos - norm_leg_prev / 3 * delta; node->n.pos = node->pos + norm_leg_next / 3 * delta; } @@ -3584,9 +3584,10 @@ static void node_grabbed(SPKnot *knot, guint state, gpointer data) } n->is_dragging = true; + sp_canvas_set_snap_delay_active(n->subpath->nodepath->desktop->canvas, true); // Reconstruct and store the location of the mouse pointer at the time when we started dragging (needed for snapping) - n->subpath->nodepath->drag_origin_mouse = knot->grabbed_rel_pos + knot->drag_origin; - + n->subpath->nodepath->drag_origin_mouse = knot->grabbed_rel_pos + knot->drag_origin; + sp_canvas_force_full_redraw_after_interruptions(n->subpath->nodepath->desktop->canvas, 5); sp_nodepath_remember_origins (n->subpath->nodepath); @@ -3601,6 +3602,7 @@ static void node_ungrabbed(SPKnot */*knot*/, guint /*state*/, gpointer data) n->dragging_out = NULL; n->is_dragging = false; + sp_canvas_set_snap_delay_active(n->subpath->nodepath->desktop->canvas, false); n->subpath->nodepath->drag_origin_mouse = Geom::Point(NR_HUGE, NR_HUGE); sp_canvas_end_forced_full_redraws(n->subpath->nodepath->desktop->canvas); @@ -3798,16 +3800,16 @@ node_request(SPKnot */*knot*/, Geom::Point const &p, guint state, gpointer data) // move the node to the closest point sp_nodepath_selected_nodes_move(n->subpath->nodepath, n->origin[Geom::X] + c[Geom::X] - n->pos[Geom::X], - n->origin[Geom::Y] + c[Geom::Y] - n->pos[Geom::Y], + n->origin[Geom::Y] + c[Geom::Y] - n->pos[Geom::Y], true); } else { // constraining to hor/vert if (fabs(p[Geom::X] - n->origin[Geom::X]) > fabs(p[Geom::Y] - n->origin[Geom::Y])) { // snap to hor sp_nodepath_selected_nodes_move(n->subpath->nodepath, - p[Geom::X] - n->pos[Geom::X], + p[Geom::X] - n->pos[Geom::X], n->origin[Geom::Y] - n->pos[Geom::Y], - true, + true, true, Inkscape::Snapper::ConstraintLine(component_vectors[Geom::X])); } else { // snap to vert sp_nodepath_selected_nodes_move(n->subpath->nodepath, @@ -3935,10 +3937,10 @@ static gboolean node_handle_request(SPKnot *knot, Geom::Point &p, guint state, g SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, n->subpath->nodepath->item); Inkscape::SnappedPoint s; - + if ((state & GDK_SHIFT_MASK) != 0) { // We will not try to snap when the shift-key is pressed - // so remove the old snap indicator and don't wait for it to time-out + // so remove the old snap indicator and don't wait for it to time-out desktop->snapindicator->remove_snaptarget(); } @@ -3968,7 +3970,7 @@ static gboolean node_handle_request(SPKnot *knot, Geom::Point &p, guint state, g s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); } } - + s.getPoint(p); sp_node_adjust_handle(n, -which); @@ -4613,7 +4615,7 @@ sp_nodepath_node_new(Inkscape::NodePath::SubPath *sp, Inkscape::NodePath::Node * n->pos = *pos; n->p.pos = *ppos; n->n.pos = *npos; - + n->dragging_out = NULL; Inkscape::NodePath::Node *prev; diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 1762d668c..804c736be 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -148,7 +148,7 @@ sp_pen_context_init(SPPenContext *pc) pc->c1 = NULL; pc->cl0 = NULL; pc->cl1 = NULL; - + pc->events_disabled = 0; pc->num_clicks = 0; @@ -209,6 +209,8 @@ sp_pen_context_setup(SPEventContext *ec) pc = SP_PEN_CONTEXT(ec); + sp_canvas_set_snap_delay_active(pc->desktop->canvas, true); + if (((SPEventContextClass *) pen_parent_class)->setup) { ((SPEventContextClass *) pen_parent_class)->setup(ec); } @@ -241,7 +243,7 @@ sp_pen_context_setup(SPEventContext *ec) } static void -pen_cancel (SPPenContext *const pc) +pen_cancel (SPPenContext *const pc) { pc->num_clicks = 0; pc->state = SP_PEN_CONTEXT_STOP; @@ -264,6 +266,8 @@ sp_pen_context_finish(SPEventContext *ec) { SPPenContext *pc = SP_PEN_CONTEXT(ec); + sp_canvas_set_snap_delay_active(pc->desktop->canvas, false); + if (pc->npoints != 0) { pen_cancel (pc); } @@ -332,7 +336,7 @@ spdc_endpoint_snap_handle(SPPenContext const *const pc, Geom::Point &p, guint co } } -static gint +static gint sp_pen_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event) { SPPenContext *const pc = SP_PEN_CONTEXT(ec); @@ -417,7 +421,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const SPDrawContext * const dc = SP_DRAW_CONTEXT(pc); SPDesktop * const desktop = SP_EVENT_CONTEXT_DESKTOP(dc); Geom::Point const event_w(bevent.x, bevent.y); - Geom::Point const event_dt(desktop->w2d(event_w)); + Geom::Point event_dt(desktop->w2d(event_w)); SPEventContext *event_context = SP_EVENT_CONTEXT(pc); gint ret = FALSE; @@ -453,7 +457,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const case SP_PEN_CONTEXT_CLOSE: break; case SP_PEN_CONTEXT_STOP: - /* This is allowed, if we just cancelled curve */ + /* This is allowed, if we just canceled curve */ pc->state = SP_PEN_CONTEXT_POINT; break; default: @@ -463,13 +467,20 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const case SP_PEN_CONTEXT_MODE_DRAG: switch (pc->state) { case SP_PEN_CONTEXT_STOP: - /* This is allowed, if we just cancelled curve */ + /* This is allowed, if we just canceled curve */ case SP_PEN_CONTEXT_POINT: if (pc->npoints == 0) { + Geom::Point p; if (bevent.state & GDK_CONTROL_MASK) { - spdc_create_single_dot(event_context, event_dt, "/tools/freehand/pen", bevent.state); - ret = TRUE; + p = event_dt; + if (!(bevent.state & GDK_SHIFT_MASK)) { + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); + } + spdc_create_single_dot(event_context, p, "/tools/freehand/pen", bevent.state); + ret = TRUE; break; } @@ -478,7 +489,6 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const /* Set start anchor */ pc->sa = anchor; - Geom::Point p; if (anchor && !sp_pen_context_has_waiting_LPE(pc)) { /* Adjust point to anchor if needed; if we have a waiting LPE, we need a fresh path to be created so don't continue an existing one */ @@ -591,7 +601,7 @@ pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion const &mevent) // allow scrolling return FALSE; } - + if (pc->events_disabled) { // skip motion events if pen events are disabled return FALSE; @@ -765,7 +775,7 @@ pen_handle_button_release(SPPenContext *const pc, GdkEventButton const &revent) ret = TRUE; break; case SP_PEN_CONTEXT_STOP: - /* This is allowed, if we just cancelled curve */ + /* This is allowed, if we just canceled curve */ pc->state = SP_PEN_CONTEXT_POINT; ret = TRUE; break; @@ -964,7 +974,8 @@ pen_lastpoint_toline (SPPenContext *const pc) static gint pen_handle_key_press(SPPenContext *const pc, GdkEvent *event) { - gint ret = FALSE; + + gint ret = FALSE; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); // in px @@ -1201,7 +1212,7 @@ spdc_pen_set_initial_point(SPPenContext *const pc, Geom::Point const p) * Show the status message for the current line/curve segment. * This type of message always shows angle/distance as the last * two parameters ("angle %3.2f°, distance %s"). - */ + */ static void spdc_pen_set_angle_distance_status_message(SPPenContext *const pc, Geom::Point const p, int pc_point_to_compare, gchar const *message) { @@ -1343,7 +1354,7 @@ spdc_pen_finish(SPPenContext *const pc, gboolean const closed) pc->num_clicks = 0; pen_disable_events(pc); - + SPDesktop *const desktop = pc->desktop; pc->_message_context->clear(); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Drawing finished")); @@ -1379,7 +1390,7 @@ pen_disable_events(SPPenContext *const pc) { static void pen_enable_events(SPPenContext *const pc) { g_return_if_fail(pc->events_disabled != 0); - + pc->events_disabled--; } diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index d089146b8..a8c3112ac 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -252,9 +252,17 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve break; default: /* Set first point of sequence */ + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + sp_canvas_set_snap_delay_active(desktop->canvas, true); + if (bevent.state & GDK_CONTROL_MASK) { - spdc_create_single_dot(event_context, p, "/tools/freehand/pencil", bevent.state); - ret = true; + if (!(bevent.state & GDK_SHIFT_MASK)) { + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); + } + spdc_create_single_dot(event_context, p, "/tools/freehand/pencil", bevent.state); + sp_canvas_set_snap_delay_active(desktop->canvas, false); + ret = true; break; } if (anchor) { @@ -263,23 +271,15 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve } else { if (!(bevent.state & GDK_SHIFT_MASK)) { - - // This is the first click of a new curve; deselect item so that + // This is the first click of a new curve; deselect item so that // this curve is not combined with it (unless it is drawn from its // anchor, which is handled by the sibling branch above) selection->clear(); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Creating new path")); - SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop); - Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); - if (s.getSnapped()) { - s.getPoint(p); - pc->prev_snap_was_succesful = true; - } else { - pc->prev_snap_was_succesful = false; - } + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); } else if (selection->singleItem() && SP_IS_PATH(selection->singleItem())) { desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Appending to selected path")); + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); } } pc->sa = anchor; @@ -296,14 +296,15 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve static gint pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mevent) { - if ((mevent.state & GDK_CONTROL_MASK) && (mevent.state & GDK_BUTTON1_MASK)) { + SPDesktop *const dt = pc->desktop; + + if ((mevent.state & GDK_CONTROL_MASK) && (mevent.state & GDK_BUTTON1_MASK)) { // mouse was accidentally moved during Ctrl+click; // ignore the motion and create a single point pc->is_drawing = false; return TRUE; } gint ret = FALSE; - SPDesktop *const dt = pc->desktop; SPEventContext *event_context = SP_EVENT_CONTEXT(pc); if (event_context->space_panning || mevent.state & GDK_BUTTON2_MASK || mevent.state & GDK_BUTTON3_MASK) { @@ -355,7 +356,11 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev default: /* We may be idle or already freehand */ if ( mevent.state & GDK_BUTTON1_MASK && pc->is_drawing ) { - pc->state = SP_PENCIL_CONTEXT_FREEHAND; + if (pc->state == SP_PENCIL_CONTEXT_IDLE) { + sp_canvas_set_snap_delay_active(dt->canvas, false); + } + pc->state = SP_PENCIL_CONTEXT_FREEHAND; + if ( !pc->sa && !pc->green_anchor ) { /* Create green anchor */ pc->green_anchor = sp_draw_anchor_new(pc, pc->green_curve, TRUE, pc->p[0]); @@ -364,27 +369,13 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev * fixme: I am not sure whether we want to snap to anchors * in middle of freehand (Lauris) */ - SnapManager &m = dt->namedview->snap_manager; - if (anchor) { p = anchor->dp; - } else if ((mevent.state & GDK_SHIFT_MASK) == 0) { - m.setup(dt); - Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, p); - if (s.getSnapped()) { - s.getPoint(p); - pc->prev_snap_was_succesful = true; - } else { - pc->prev_snap_was_succesful = false; - } } + if ( pc->npoints != 0) { // buttonpress may have happened before we entered draw context! - if (!(pc->prev_snap_was_succesful && m.snapprefs.getSnapPostponedGlobally())) { - // When snapping is enabled but temporarily on hold because the mouse is moving - // fast, then we don't want to add nodes off-grid - spdc_add_freehand_point(pc, p, mevent.state); - ret = TRUE; - } + spdc_add_freehand_point(pc, p, mevent.state); + ret = TRUE; } if (anchor && !pc->anchor_statusbar) { @@ -436,6 +427,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re if (!(revent.state & GDK_CONTROL_MASK)) { // Ctrl+click creates a single point so only set context in ADDLINE mode when Ctrl isn't pressed pc->state = SP_PENCIL_CONTEXT_ADDLINE; + //sp_canvas_set_snap_delay_active(dt->canvas, true); } ret = TRUE; break; @@ -450,6 +442,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re spdc_set_endpoint(pc, p); spdc_finish_endpoint(pc); pc->state = SP_PENCIL_CONTEXT_IDLE; + sp_canvas_set_snap_delay_active(dt->canvas, false); ret = TRUE; break; case SP_PENCIL_CONTEXT_FREEHAND: @@ -463,6 +456,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re } pc->state = SP_PENCIL_CONTEXT_SKETCH; + //sp_canvas_set_snap_delay_active(dt->canvas, true); } else { /* Finish segment now */ /// \todo fixme: Clean up what follows (Lauris) @@ -482,6 +476,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor); } pc->state = SP_PENCIL_CONTEXT_IDLE; + // sp_canvas_set_snap_delay_active(dt->canvas, false); // reset sketch mode too pc->sketch_n = 0; } @@ -504,7 +499,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re } static void -pencil_cancel (SPPencilContext *const pc) +pencil_cancel (SPPencilContext *const pc) { if (pc->grab) { /* Release grab now */ @@ -513,8 +508,8 @@ pencil_cancel (SPPencilContext *const pc) } pc->is_drawing = false; - pc->state = SP_PENCIL_CONTEXT_IDLE; + sp_canvas_set_snap_delay_active(pc->desktop->canvas, false); pc->red_curve->reset(); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), NULL); @@ -605,6 +600,7 @@ pencil_handle_key_release(SPPencilContext *const pc, guint const keyval, guint c pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor); } pc->state = SP_PENCIL_CONTEXT_IDLE; + sp_canvas_set_snap_delay_active(pc->desktop->canvas, false); pc->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand sketch")); ret = TRUE; } @@ -715,11 +711,13 @@ static void interpolate(SPPencilContext *pc) { - g_assert( pc->ps.size() > 1 ); + if ( pc->ps.size() <= 1 ) { + return; + } Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4; - double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * + double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * tol) * exp(0.2*tol - 2); g_assert(is_zero(pc->req_tangent) @@ -733,7 +731,7 @@ interpolate(SPPencilContext *pc) Geom::Point * b = g_new(Geom::Point, 4*n_points); Geom::Point * points = g_new(Geom::Point, 4*n_points); - for (unsigned int i = 0; i < pc->ps.size(); i++) { + for (unsigned int i = 0; i < pc->ps.size(); i++) { points[i] = pc->ps[i]; } @@ -747,7 +745,7 @@ interpolate(SPPencilContext *pc) { /* Fit and draw and reset state */ pc->green_curve->moveto(b[0]); - for (int c = 0; c < n_segs; c++) { + for (int c = 0; c < n_segs; c++) { pc->green_curve->curveto(b[4*c+1], b[4*c+2], b[4*c+3]); } sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), pc->green_curve); @@ -781,7 +779,7 @@ sketch_interpolate(SPPencilContext *pc) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4; - double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * + double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * tol) * exp(0.2*tol - 2); bool average_all_sketches = prefs->getBool("/tools/freehand/pencil/average_all_sketches", true); @@ -796,7 +794,7 @@ sketch_interpolate(SPPencilContext *pc) Geom::Point * b = g_new(Geom::Point, 4*n_points); Geom::Point * points = g_new(Geom::Point, 4*n_points); - for (unsigned i = 0; i < pc->ps.size(); i++) { + for (unsigned i = 0; i < pc->ps.size(); i++) { points[i] = pc->ps[i]; } @@ -809,7 +807,7 @@ sketch_interpolate(SPPencilContext *pc) if ( n_segs > 0) { Geom::Path fit(b[0]); - for (int c = 0; c < n_segs; c++) { + for (int c = 0; c < n_segs; c++) { fit.appendNew(b[4*c+1], b[4*c+2], b[4*c+3]); } Geom::Piecewise > fit_pwd2 = fit.toPwSb(); @@ -866,7 +864,7 @@ fit_and_split(SPPencilContext *pc) || is_unit_vector(pc->req_tangent)); Geom::Point const tHatEnd(0, 0); int const n_segs = Geom::bezier_fit_cubic_full(b, NULL, pc->p, pc->npoints, - pc->req_tangent, tHatEnd, + pc->req_tangent, tHatEnd, tolerance_sq, 1); if ( n_segs > 0 && unsigned(pc->npoints) < G_N_ELEMENTS(pc->p) ) diff --git a/src/pencil-context.h b/src/pencil-context.h index c3b34b647..cbcf2b98e 100644 --- a/src/pencil-context.h +++ b/src/pencil-context.h @@ -31,7 +31,6 @@ struct SPPencilContext : public SPDrawContext { Geom::Point req_tangent; bool is_drawing; - bool prev_snap_was_succesful; std::vector ps; diff --git a/src/rect-context.cpp b/src/rect-context.cpp index 65292851b..c63e1dc2a 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -151,7 +151,7 @@ void sp_rect_context_selection_changed(Inkscape::Selection *selection, gpointer SPEventContext *ec = SP_EVENT_CONTEXT(rc); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); ec->shape_editor->set_item(item, SH_KNOTHOLDER); } @@ -257,17 +257,18 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE); dragging = true; + sp_canvas_set_snap_delay_active(desktop->canvas, true); /* Position center */ Geom::Point button_dt(desktop->w2d(button_w)); rc->center = from_2geom(button_dt); - + /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, button_dt); rc->center = from_2geom(button_dt); - + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -275,7 +276,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK ), NULL, event->button.time); - + ret = TRUE; } break; @@ -295,7 +296,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - + sp_rect_drag(*rc, motion_dt, event->motion.state); // this will also handle the snapping gobble_motion_events(GDK_BUTTON1_MASK); ret = TRUE; @@ -305,6 +306,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent event_context->xp = event_context->yp = 0; if (event->button.button == 1 && !event_context->space_panning) { dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the rect @@ -379,6 +381,7 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_rect_finish(rc); diff --git a/src/select-context.cpp b/src/select-context.cpp index 1daf6b0e5..c7b305dd2 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -326,7 +326,7 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE sc->moved = FALSE; sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5); - + // remember the clicked item in sc->item: if (sc->item) { sp_object_unref(sc->item, NULL); @@ -511,10 +511,10 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) item_in_group = desktop->item_at_point(Geom::Point(event->button.x, event->button.y), TRUE); group_at_point = desktop->group_at_point(Geom::Point(event->button.x, event->button.y)); - // group-at-point is meant to be topmost item if it's a group, + // group-at-point is meant to be topmost item if it's a group, // not topmost group of all items at point - if (group_at_point != item_in_group && - !(group_at_point && item_at_point && + if (group_at_point != item_in_group && + !(group_at_point && item_at_point && group_at_point->isAncestorOf(item_at_point))) group_at_point = NULL; @@ -673,7 +673,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) sp_canvas_item_ungrab(sc->grabbed, event->button.time); sc->grabbed = NULL; } - + desktop->updateNow(); } if (event->button.button == 1) { @@ -902,7 +902,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } ret = TRUE; } - break; + break; case GDK_g: case GDK_G: if (MOD__SHIFT_ONLY) { diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 0fd15593c..b1917edfd 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -366,6 +366,8 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } } + sp_canvas_set_snap_delay_active(_desktop->canvas, true); + // The lines below are useful for debugging any snapping issues, as they'll spit out all points that are considered for snapping /*std::cout << "Number of snap points: " << _snap_points.size() << std::endl; @@ -432,6 +434,8 @@ void Inkscape::SelTrans::ungrab() _grabbed = false; _show_handles = true; + sp_canvas_set_snap_delay_active(_desktop->canvas, false); + Inkscape::Selection *selection = sp_desktop_selection(_desktop); _updateVolatileState(); diff --git a/src/snap.cpp b/src/snap.cpp index 24cfefe0b..11ba077e4 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -13,7 +13,7 @@ * * Copyright (C) 2006-2007 Johan Engelen * Copyrigth (C) 2004 Nathan Hurst - * Copyright (C) 1999-2008 Authors + * Copyright (C) 1999-2009 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -162,7 +162,12 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp bool first_point, Geom::OptRect const &bbox_to_snap) const { - if (!someSnapperMightSnap()) { + if (_desktop->canvas->context_snap_delay_active == false) { + g_warning("context_snap_delay_active has not been set to true by the current context. Please report this!"); + // When the context goes into dragging-mode, then Inkscape should call this: sp_canvas_set_snap_delay_active(desktop->canvas, true); + } + + if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } @@ -286,7 +291,12 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P bool first_point, Geom::OptRect const &bbox_to_snap) const { - if (!someSnapperMightSnap()) { + if (_desktop->canvas->context_snap_delay_active == false) { + g_warning("context_snap_delay_active has not been set to true by the current context. Please report this!"); + // When the context goes into dragging-mode, then Inkscape should call this: sp_canvas_set_snap_delay_active(desktop->canvas, true); + } + + if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } @@ -317,6 +327,11 @@ void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) con { // This method is used to snap a guide to nodes, while dragging the guide around + if (_desktop->canvas->context_snap_delay_active == false) { + g_warning("context_snap_delay_active has not been set to true by the current context. Please report this!"); + // When the context goes into dragging-mode, then Inkscape should call this: sp_canvas_set_snap_delay_active(desktop->canvas, true); + } + if ( !(object.GuidesMightSnap() && snapprefs.getSnapEnabledGlobally()) || snapprefs.getSnapPostponedGlobally() ) { return; } diff --git a/src/spiral-context.cpp b/src/spiral-context.cpp index ce9ea1e03..35d5144a7 100644 --- a/src/spiral-context.cpp +++ b/src/spiral-context.cpp @@ -149,7 +149,7 @@ sp_spiral_context_selection_changed(Inkscape::Selection *selection, gpointer dat SPEventContext *ec = SP_EVENT_CONTEXT(sc); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); ec->shape_editor->set_item(item, SH_KNOTHOLDER); } @@ -221,6 +221,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (event->button.button == 1 && !event_context->space_panning) { dragging = TRUE; + sp_canvas_set_snap_delay_active(desktop->canvas, true); sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); SnapManager &m = desktop->namedview->snap_manager; @@ -254,7 +255,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(event_context->desktop->w2d(motion_w)); - + SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, sc->item); m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, motion_dt); @@ -269,6 +270,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) event_context->xp = event_context->yp = 0; if (event->button.button == 1 && !event_context->space_panning) { dragging = FALSE; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the spiral sp_spiral_finish(sc); @@ -328,6 +330,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_spiral_finish(sc); @@ -404,8 +407,8 @@ sp_spiral_drag(SPSpiralContext *sc, Geom::Point p, guint state) m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g); Geom::Point const p0 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, sc->center)); - Geom::Point const p1 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, from_2geom(pt2g))); - + Geom::Point const p1 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, from_2geom(pt2g))); + SPSpiral *spiral = SP_SPIRAL(sc->item); Geom::Point const delta = p1 - p0; @@ -447,7 +450,7 @@ sp_spiral_finish(SPSpiralContext *sc) sp_canvas_end_forced_full_redraws(desktop->canvas); sp_desktop_selection(desktop)->set(sc->item); - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, _("Create spiral")); sc->item = NULL; diff --git a/src/star-context.cpp b/src/star-context.cpp index 9dc2db296..da79d4719 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -156,7 +156,7 @@ sp_star_context_selection_changed (Inkscape::Selection * selection, gpointer dat SPEventContext *ec = SP_EVENT_CONTEXT (sc); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); ec->shape_editor->set_item(item, SH_KNOTHOLDER); } @@ -202,7 +202,7 @@ sp_star_context_set (SPEventContext *ec, Inkscape::Preferences::Entry *val) { SPStarContext *sc = SP_STAR_CONTEXT (ec); Glib::ustring path = val->getEntryName(); - + if (path == "magnitude") { sc->magnitude = CLAMP (val->getInt(5), 3, 1024); } else if (path == "proportion") { @@ -235,9 +235,10 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent if (event->button.button == 1 && !event_context->space_panning) { dragging = TRUE; + sp_canvas_set_snap_delay_active(desktop->canvas, true); sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); - + /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true); @@ -269,7 +270,7 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); - + sp_star_drag (sc, motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); @@ -281,6 +282,7 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent event_context->xp = event_context->yp = 0; if (event->button.button == 1 && !event_context->space_panning) { dragging = FALSE; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the star sp_star_finish (sc); @@ -340,6 +342,7 @@ static gint sp_star_context_root_handler(SPEventContext *event_context, GdkEvent sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); dragging = false; + sp_canvas_set_snap_delay_active(desktop->canvas, false); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_star_finish(sc); @@ -413,11 +416,11 @@ static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, sc->item); Geom::Point pt2g = to_2geom(p); - m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g); - + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g); + Geom::Point const p0 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, sc->center)); Geom::Point const p1 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, from_2geom(pt2g))); - + SPStar *star = SP_STAR(sc->item); double const sides = (gdouble) sc->magnitude; @@ -460,7 +463,7 @@ sp_star_finish (SPStarContext * sc) sp_canvas_end_forced_full_redraws(desktop->canvas); sp_desktop_selection(desktop)->set(sc->item); - sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, _("Create star")); sc->item = NULL; diff --git a/src/text-context.cpp b/src/text-context.cpp index ad9211cba..6e4b637b8 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -353,6 +353,7 @@ sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); tc->dragging = 1; + sp_canvas_set_snap_delay_active(desktop->canvas, true); } ret = TRUE; } @@ -369,6 +370,7 @@ sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); tc->dragging = 2; + sp_canvas_set_snap_delay_active(desktop->canvas, true); ret = TRUE; } } @@ -380,12 +382,14 @@ sp_text_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEve sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); tc->dragging = 3; + sp_canvas_set_snap_delay_active(desktop->canvas, true); ret = TRUE; } break; case GDK_BUTTON_RELEASE: if (event->button.button == 1 && tc->dragging && !event_context->space_panning) { tc->dragging = 0; + sp_canvas_set_snap_delay_active(desktop->canvas, false); ret = TRUE; } break; @@ -1011,7 +1015,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons sp_document_maybe_done(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, _("Kern to the left")); } else { - if (MOD__CTRL) + if (MOD__CTRL) tc->text_sel_end.cursorLeftWithControl(); else tc->text_sel_end.cursorLeft(); @@ -1314,7 +1318,7 @@ sp_text_paste_inline(SPEventContext *ec) Glib::RefPtr refClipboard = Gtk::Clipboard::get(); Glib::ustring const clip_text = refClipboard->wait_for_text(); - + if (!clip_text.empty()) { // Fix for 244940 // The XML standard defines the following as valid characters @@ -1342,7 +1346,7 @@ sp_text_paste_inline(SPEventContext *ec) itr = text.erase(itr); } } - + if (!tc->text) { // create text if none (i.e. if nascent_object) sp_text_context_setup_text(tc); tc->nascent_object = 0; // we don't need it anymore, having created a real @@ -1430,7 +1434,7 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, SPTextContext SPEventContext *ec = SP_EVENT_CONTEXT(tc); ec->shape_editor->unset_item(SH_KNOTHOLDER); - SPItem *item = selection->singleItem(); + SPItem *item = selection->singleItem(); if (item && SP_IS_FLOWTEXT (item) && SP_FLOWTEXT(item)->has_internal_frame()) { ec->shape_editor->set_item(item, SH_KNOTHOLDER); } -- 2.30.2