From: dvlierop2 Date: Sun, 29 Mar 2009 19:12:03 +0000 (+0000) Subject: - Move snap delay mechanism to the event context (used to be in SPCanvas) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=6a15201cbb894ffa10891d94c4b42acc91214f03;p=inkscape.git - Move snap delay mechanism to the event context (used to be in SPCanvas) - Rename lots of variables and methods to make them easier to understand - Add snapping to the connector tool --- diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 115b5534c..e33985c22 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -41,6 +41,7 @@ #include "context-fns.h" #include "verbs.h" #include "shape-editor.h" +#include "event-context.h" #include "arc-context.h" @@ -221,7 +222,7 @@ 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); + sp_event_context_snap_window_open(event_context); ac->center = Inkscape::setup_for_drag_start(desktop, event_context, event); /* Snap center */ @@ -265,7 +266,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the arc sp_arc_finish(ac); @@ -329,7 +330,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_arc_finish(ac); diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index e8cee44b0..5fb85d793 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -276,7 +276,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven 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); + sp_event_context_snap_window_open(event_context); /* */ Geom::Point button_dt(desktop->w2d(button_w)); @@ -373,7 +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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the box @@ -506,7 +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); + sp_event_context_snap_window_closed(event_context); 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 e364336c4..c8754972a 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -290,8 +290,6 @@ 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); } @@ -301,6 +299,7 @@ sp_connector_context_finish(SPEventContext *ec) SPConnectorContext *cc = SP_CONNECTOR_CONTEXT(ec); spcc_connector_finish(cc); + cc->state = SP_CONNECTOR_CONTEXT_IDLE; if (((SPEventContextClass *) parent_class)->finish) { ((SPEventContextClass *) parent_class)->finish(ec); @@ -315,8 +314,6 @@ 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); } @@ -412,6 +409,7 @@ sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, G { spcc_reset_colors(cc); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); } if (cc->state != SP_CONNECTOR_CONTEXT_IDLE) { // Doing simething else like rerouting. @@ -427,6 +425,7 @@ sp_connector_context_item_handler(SPEventContext *event_context, SPItem *item, G cc->selection->set(item_ungrouped); } ret = TRUE; + } break; case GDK_ENTER_NOTIFY: @@ -463,7 +462,7 @@ sp_connector_context_root_handler(SPEventContext *ec, GdkEvent *event) break; case GDK_MOTION_NOTIFY: - ret = connector_handle_motion_notify(cc, event->motion); + ret = connector_handle_motion_notify(cc, event->motion); break; case GDK_BUTTON_RELEASE: @@ -512,6 +511,10 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const connector_within_tolerance = true; Geom::Point const event_dt = cc->desktop->w2d(event_w); + + SnapManager &m = cc->desktop->namedview->snap_manager; + m.setup(cc->desktop); + switch (cc->state) { case SP_CONNECTOR_CONTEXT_STOP: /* This is allowed, if we just cancelled curve */ @@ -529,16 +532,14 @@ 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); + sp_event_context_snap_window_open(event_context); if (!cc->sid) { // This is the first point, so just snap it to the grid // as there's no other points to go off. - SnapManager &m = cc->desktop->namedview->snap_manager; - m.setup(cc->desktop); - m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g, Inkscape::SNAPSOURCE_HANDLE); + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); } - spcc_connector_set_initial_point(cc, from_2geom(pt2g)); + spcc_connector_set_initial_point(cc, p); } cc->state = SP_CONNECTOR_CONTEXT_DRAGGING; @@ -548,6 +549,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const case SP_CONNECTOR_CONTEXT_DRAGGING: { // This is the second click of a connector creation. + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); spcc_connector_set_subsequent_point(cc, p); spcc_connector_finish_segment(cc, p); @@ -558,6 +560,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const } cc_set_active_conn(cc, cc->newconn); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); ret = TRUE; break; } @@ -576,12 +579,15 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const cc_connector_rerouting_finish(cc, &p); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); // Don't set ret to TRUE, so we drop through to the // parent handler which will open the context menu. } else if (cc->npoints != 0) { spcc_connector_finish(cc); + cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); ret = TRUE; } } @@ -619,13 +625,16 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons /* Find desktop coordinates */ Geom::Point p = dt->w2d(event_w); + SnapManager &m = dt->namedview->snap_manager; + m.setup(dt); + switch (cc->state) { case SP_CONNECTOR_CONTEXT_DRAGGING: { // This is movement during a connector creation. - - if ( cc->npoints > 0 ) { - cc->selection->clear(); + if ( cc->npoints > 0 ) { + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); + cc->selection->clear(); spcc_connector_set_subsequent_point(cc, p); ret = TRUE; } @@ -635,6 +644,8 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons { g_assert( SP_IS_PATH(cc->clickeditem)); + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); + // Update the hidden path Geom::Matrix i2d = sp_item_i2d_affine(cc->clickeditem); Geom::Matrix d2i = i2d.inverse(); @@ -676,9 +687,12 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con SPEventContext *event_context = SP_EVENT_CONTEXT(cc); if ( revent.button == 1 && !event_context->space_panning ) { - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); + SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); SPDocument *doc = sp_desktop_document(desktop); + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop); + Geom::Point const event_w(revent.x, revent.y); /* Find desktop coordinates */ @@ -688,7 +702,9 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con //case SP_CONNECTOR_CONTEXT_POINT: case SP_CONNECTOR_CONTEXT_DRAGGING: { - if (connector_within_tolerance) + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); + + if (connector_within_tolerance) { spcc_connector_finish_segment(cc, p); return TRUE; @@ -703,14 +719,17 @@ connector_handle_button_release(SPConnectorContext *const cc, GdkEventButton con } cc_set_active_conn(cc, cc->newconn); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); break; } case SP_CONNECTOR_CONTEXT_REROUTING: { - cc_connector_rerouting_finish(cc, &p); + m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, p, Inkscape::SNAPSOURCE_HANDLE); + cc_connector_rerouting_finish(cc, &p); sp_document_ensure_up_to_date(doc); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(event_context); return TRUE; break; } @@ -737,6 +756,8 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval) case GDK_KP_Enter: if (cc->npoints != 0) { spcc_connector_finish(cc); + cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc)); ret = TRUE; } break; @@ -751,6 +772,7 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval) sp_document_undo(doc); cc->state = SP_CONNECTOR_CONTEXT_IDLE; + sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc)); desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE, _("Connector endpoint drag cancelled.")); ret = TRUE; @@ -758,6 +780,7 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval) else if (cc->npoints != 0) { // if drawing, cancel, otherwise pass it up for deselecting cc->state = SP_CONNECTOR_CONTEXT_STOP; + sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(cc)); spcc_reset_colors(cc); ret = TRUE; } @@ -1000,7 +1023,6 @@ spcc_connector_finish(SPConnectorContext *const cc) delete cc->newConnRef; cc->newConnRef = NULL; } - cc->state = SP_CONNECTOR_CONTEXT_IDLE; } @@ -1067,6 +1089,7 @@ endpt_handler(SPKnot */*knot*/, GdkEvent *event, SPConnectorContext *cc) cc->clickedhandle = cc->active_handle; cc_clear_active_conn(cc); cc->state = SP_CONNECTOR_CONTEXT_REROUTING; + sp_event_context_snap_window_open(SP_EVENT_CONTEXT(cc)); // Disconnect from attached shape unsigned ind = (cc->active_handle == cc->endpt_handle[0]) ? 0 : 1; diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index f77f3de35..2a87d84a1 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -72,7 +72,7 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge static bool dragging = false; static SPCanvasItem *guide = NULL; static Geom::Point normal; - static bool snap_delay_temporarily_active = false; + static bool snap_window_temporarily_open = false; int wx, wy; SPDesktop *desktop = dtw->desktop; @@ -89,17 +89,17 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge if (event->button.button == 1) { dragging = true; - // FIXME: The snap delay mechanism won't work here, because it has been implemented for the canvas. Dragging - // guides off the ruler will send event to the ruler and not to the canvas, which bypasses sp_canvas_motion + // FIXME: The snap delay mechanism won't work here, because it has been implemented for the event context. Dragging + // guides off the ruler will send event to the ruler and not to the context, which bypasses sp_event_context_snap_delay_handler // The snap manager will not notice the difference, so it'll check if the snap delay has been activated (This check - // is only needed for catching coding errors, i.e. to warn if the snap delay has not been implemented properly + // is only needed for catching coding errors, i.e. to warn if the snap window has not been implemented properly // in some context) - if (desktop->canvas->context_snap_delay_active == false) { - // A dt_ruler_event might be emitted when dragging a guide of the rulers while drawing a Bezier curve + if (desktop->event_context->_snap_window_open == false) { + // A dt_ruler_event might be emitted when dragging a guide off the rulers while drawing a Bezier curve // In such a situation, we're already in that specific context and the snap delay is already active. We should // not set the snap delay to active again, because that will trigger a similar warning to the one above - sp_canvas_set_snap_delay_active(desktop->canvas, true); - snap_delay_temporarily_active = true; + sp_event_context_snap_window_open(desktop->event_context); + snap_window_temporarily_open = true; } Geom::Point const event_w(sp_canvas_window_to_world(dtw->canvas, event_win)); @@ -183,9 +183,9 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge dragging = false; // See the comments in GDK_BUTTON_PRESS - if (snap_delay_temporarily_active) { - sp_canvas_set_snap_delay_active(desktop->canvas, false); - snap_delay_temporarily_active = false; + if (snap_window_temporarily_open) { + sp_event_context_snap_window_closed(desktop->event_context); + snap_window_temporarily_open = false; } gtk_object_destroy(GTK_OBJECT(guide)); @@ -251,7 +251,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) case GDK_2BUTTON_PRESS: if (event->button.button == 1) { drag_type = SP_DRAG_NONE; - sp_canvas_set_snap_delay_active(desktop->canvas, false); + sp_event_context_snap_window_closed(desktop->event_context); sp_canvas_item_ungrab(item, event->button.time); Inkscape::UI::Dialogs::GuidelinePropertiesDialog::showDialog(guide, desktop); ret = TRUE; @@ -267,7 +267,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) break; } - sp_canvas_set_snap_delay_active(desktop->canvas, true); + sp_event_context_snap_window_closed(desktop->event_context); double tol = 40.0; Geom::Point const event_w(event->button.x, event->button.y); Geom::Point const event_dt(desktop->w2d(event_w)); @@ -398,7 +398,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) desktop->setPosition (from_2geom(event_dt)); } drag_type = SP_DRAG_NONE; - sp_canvas_set_snap_delay_active(desktop->canvas, false); + sp_event_context_snap_window_closed(desktop->event_context); sp_canvas_item_ungrab(item, event->button.time); ret=TRUE; } diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 0f9e883ed..e0d885d36 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -946,10 +946,6 @@ 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 void sp_canvas_snap_watchdog_kill(SPCanvas *canvas); - /** * Registers the SPCanvas class if necessary, and returns the type ID * associated to it. @@ -1046,10 +1042,6 @@ sp_canvas_init (SPCanvas *canvas) #endif // ENABLE_LCMS canvas->is_scrolling = false; - - canvas->watchdog_id = 0; - canvas->watchdog_event = NULL; - canvas->context_snap_delay_active = false; } /** @@ -1288,7 +1280,7 @@ emit_event (SPCanvas *canvas, GdkEvent *event) if (!(mask & canvas->grabbed_event_mask)) return FALSE; } - /* Convert to world coordinates -- we have two cases because of diferent + /* Convert to world coordinates -- we have two cases because of different * offsets of the fields in the event structures. */ @@ -1497,7 +1489,6 @@ static gint sp_canvas_button (GtkWidget *widget, GdkEventButton *event) { SPCanvas *canvas = SP_CANVAS (widget); - SPDesktop *dt = SP_ACTIVE_DESKTOP; int retval = FALSE; @@ -1532,12 +1523,6 @@ sp_canvas_button (GtkWidget *widget, GdkEventButton *event) case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - 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. - dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); - } - /* Pick the current item as if the button were not pressed, and * then process the event. */ @@ -1548,9 +1533,7 @@ 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 - - /* Process the event as if the button were pressed, then repick + /* Process the event as if the button were pressed, then repick * after the button has been released */ canvas->state = event->state; @@ -1593,9 +1576,6 @@ static inline void request_motions(GdkWindow *w, GdkEventMotion *event) { static int sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) { - static guint32 prev_time; - static boost::optional prev_pos; - int status; SPCanvas *canvas = SP_CANVAS (widget); @@ -1607,56 +1587,6 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) if (canvas->pixmap_gc == NULL) // canvas being deleted return FALSE; - SPDesktop *dt = SP_ACTIVE_DESKTOP; - - // Snapping occurs when dragging with the left mouse button down, or when hovering e.g. in the pen tool with left mouse button up - bool const c1 = event->state & GDK_BUTTON2_MASK; // We shouldn't hold back any events when other mouse buttons have been - bool const c2 = 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 - - if (canvas->context_snap_delay_active && !c1 && !c2 && dt && dt->namedview->snap_manager.snapprefs.getSnapEnabledGlobally()) { - // Snap when speed drops below e.g. 0.02 px/msec, or when no motion events have occurred 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. - dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold - - Geom::Point event_pos(event->x, event->y); - guint32 event_t = gdk_event_get_time ( (GdkEvent *) event ); - - 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; - 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 - } - } 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); status = emit_event (canvas, (GdkEvent *) event); @@ -1667,82 +1597,6 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) return status; } -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 - SPCanvas *canvas = reinterpret_cast(data); - if (!canvas->watchdog_event) { - // This might occur when this method is called directly, i.e. not through the timer - return FALSE; - } - - SPDesktop *dt = SP_ACTIVE_DESKTOP; - if (dt) { - dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); - } - - ((GdkEventMotion *)canvas->watchdog_event)->time = GDK_CURRENT_TIME; - 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) -{ - 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); -} - -void sp_canvas_snap_watchdog_kill(SPCanvas *canvas) -{ - 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) { diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index cb63374e1..35e3fb5de 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -193,10 +193,6 @@ 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(); @@ -218,8 +214,6 @@ 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/event-context.cpp b/src/event-context.cpp index 7039c3b13..5b845388b 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -43,6 +43,7 @@ #include "shortcuts.h" #include "desktop.h" #include "desktop-handles.h" +#include "sp-namedview.h" #include "selection.h" #include "file.h" #include "interface.h" @@ -142,6 +143,7 @@ sp_event_context_init(SPEventContext *event_context) event_context->_grdrag = NULL; event_context->space_panning = false; event_context->shape_editor = NULL; + event_context->_delayed_snap_event = NULL; } /** @@ -228,7 +230,7 @@ gint gobble_key_events(guint keyval, gint mask) && event_next->key.keyval == keyval && (!mask || (event_next->key.state & mask))) { if (event_next->type == GDK_KEY_PRESS) - i ++; + i ++; // kill it gdk_event_free(event_next); // get next @@ -464,7 +466,7 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context, Inkscape::Rubberband::get(desktop)->move(motion_dt); } else { Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); - } + } if (zoom_rb == 2) gobble_motion_events(GDK_BUTTON2_MASK); } @@ -491,7 +493,7 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context, // in slow complex drawings, some of the motion events are lost; // to make up for this, we scroll it once again to the button-up event coordinates - // (i.e. canvas will always get scrolled all the way to the mouse release point, + // (i.e. canvas will always get scrolled all the way to the mouse release point, // even if few intermediate steps were visible) Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const moved_w( motion_w - button_w ); @@ -514,8 +516,8 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context, // in the editing window). So we resteal them back and run our regular shortcut // invoker on them. unsigned int shortcut; - case GDK_Tab: - case GDK_ISO_Left_Tab: + case GDK_Tab: + case GDK_ISO_Left_Tab: case GDK_F1: shortcut = get_group0_keyval(&event->key); if (event->key.state & GDK_SHIFT_MASK) @@ -637,7 +639,7 @@ static gint sp_event_context_private_root_handler(SPEventContext *event_context, desktop->updateNow(); } ret= TRUE; - } + } break; case GDK_Q: case GDK_q: @@ -747,7 +749,7 @@ public: Inkscape::Preferences::Observer(path), _ec(ec) {} virtual void notify(Inkscape::Preferences::Entry const &val) - { + { if (((SPEventContextClass *) G_OBJECT_GET_CLASS(_ec))->set) { ((SPEventContextClass *) G_OBJECT_GET_CLASS(_ec))->set(_ec, const_cast(&val)); @@ -773,10 +775,10 @@ sp_event_context_new(GType type, SPDesktop *desktop, gchar const *pref_path, uns ec->_message_context = new Inkscape::MessageContext(desktop->messageStack()); ec->key = key; ec->pref_observer = NULL; - + if (pref_path) { ec->pref_observer = new ToolPrefObserver(pref_path, ec); - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->addObserver(*(ec->pref_observer)); } @@ -865,6 +867,12 @@ sp_event_context_activate(SPEventContext *ec) g_return_if_fail(ec != NULL); g_return_if_fail(SP_IS_EVENT_CONTEXT(ec)); + // Make sure no delayed snapping events are carried over after switching contexts + // (this is only an additional safety measure against sloppy coding, because each + // context should take care of this by itself. It might be hard to get each and every + // context perfect though) + sp_event_context_snap_window_closed(ec, false); + if (((SPEventContextClass *) G_OBJECT_GET_CLASS(ec))->activate) ((SPEventContextClass *) G_OBJECT_GET_CLASS(ec))->activate(ec); } @@ -888,13 +896,36 @@ sp_event_context_deactivate(SPEventContext *ec) gint sp_event_context_root_handler(SPEventContext * event_context, GdkEvent * event) { - gint ret; + //std::cout << "sp_event_context_root_handler" << std::endl; + switch (event->type) { + case GDK_MOTION_NOTIFY: + sp_event_context_snap_delay_handler(event_context, NULL, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER); + break; + case GDK_BUTTON_RELEASE: + sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event); // If we have any pending snapping action, then invoke it now + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + // 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. + event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); + break; + default: + break; + } - ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler(event_context, event); + return sp_event_context_virtual_root_handler(event_context, event); +} - set_event_location(event_context->desktop, event); +gint +sp_event_context_virtual_root_handler(SPEventContext * event_context, GdkEvent * event) +{ + //std::cout << "sp_event_context_virtual_root_handler -> postponed: " << event_context->desktop->namedview->snap_manager.snapprefs.getSnapPostponedGlobally() << std::endl; - return ret; + gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler(event_context, event); + set_event_location(event_context->desktop, event); + return ret; } /** @@ -903,17 +934,41 @@ sp_event_context_root_handler(SPEventContext * event_context, GdkEvent * event) gint sp_event_context_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event) { - gint ret; + //std::cout << "sp_event_context_item_handler" << std::endl; + switch (event->type) { + case GDK_MOTION_NOTIFY: + sp_event_context_snap_delay_handler(event_context, item, NULL, (GdkEventMotion *)event, DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER); + break; + case GDK_BUTTON_RELEASE: + sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event); // If we have any pending snapping action, then invoke it now + break; + /*case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + // 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. + event_context->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); + break; + */ + default: + break; + } + + return sp_event_context_virtual_item_handler(event_context, item, event); +} - ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->item_handler(event_context, item, event); +gint +sp_event_context_virtual_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event) +{ + gint ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->item_handler(event_context, item, event); - if (! ret) { - ret = sp_event_context_root_handler(event_context, event); - } else { - set_event_location(event_context->desktop, event); - } + if (! ret) { + ret = sp_event_context_virtual_root_handler(event_context, event); + } else { + set_event_location(event_context->desktop, event); + } - return ret; + return ret; } /** @@ -927,7 +982,7 @@ static void set_event_location(SPDesktop *desktop, GdkEvent *event) Geom::Point const button_w(event->button.x, event->button.y); Geom::Point const button_dt(desktop->w2d(button_w)); - desktop-> setPosition (button_dt); + desktop->setPosition(button_dt); desktop->set_coordinate_status(button_dt); } @@ -1105,6 +1160,155 @@ event_context_print_event_info(GdkEvent *event, bool print_return) { } } +void sp_event_context_snap_delay_handler(SPEventContext *ec, SPItem* const item, SPKnot* const knot, GdkEventMotion *event, DelayedSnapEvent::DelayedSnapEventOrigin origin) +{ + static guint32 prev_time; + static boost::optional prev_pos; + + // Snapping occurs when dragging with the left mouse button down, or when hovering e.g. in the pen tool with left mouse button up + bool const c1 = event->state & GDK_BUTTON2_MASK; // We shouldn't hold back any events when other mouse buttons have been + bool const c2 = 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 + + if (ec->_snap_window_open && !c1 && !c2 && ec->desktop && ec->desktop->namedview->snap_manager.snapprefs.getSnapEnabledGlobally()) { + // Snap when speed drops below e.g. 0.02 px/msec, or when no motion events have occurred 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. + ec->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(true); // put snapping on hold + + Geom::Point event_pos(event->x, event->y); + guint32 event_t = gdk_event_get_time ( (GdkEvent *) event ); + + 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 << "Mouse speed = " << speed << " px/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) + delete ec->_delayed_snap_event; + ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin); // 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 (ec->_delayed_snap_event == NULL) { // 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 + ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin); + } // 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 + g_assert(ec->_delayed_snap_event == NULL); + ec->_delayed_snap_event = new DelayedSnapEvent(ec, item, knot, event, origin); + } + + prev_pos = event_pos; + prev_time = event_t; + } +} + +gboolean sp_event_context_snap_watchdog_callback(gpointer data) +{ + // Snap NOW! For this the "postponed" flag will be reset and the last motion event will be repeated + DelayedSnapEvent *dse = reinterpret_cast(data); + + if (dse == NULL) { + // This might occur when this method is called directly, i.e. not through the timer + // E.g. on GDK_BUTTON_RELEASE in sp_event_context_root_handler() + return FALSE; + } + + SPEventContext *ec = dse->getEventContext(); + if (ec == NULL || ec->desktop == NULL) { + return false; + } + + SPDesktop *dt = ec->desktop; + dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); + + switch (dse->getOrigin()) { + case DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER: + sp_event_context_virtual_root_handler(ec, dse->getEvent()); + break; + case DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER: + g_assert(dse->getItem() != NULL); + sp_event_context_virtual_item_handler(ec, dse->getItem(), dse->getEvent()); + break; + case DelayedSnapEvent::KNOT_HANDLER: + g_assert(dse->getKnot() != NULL); + sp_knot_handler_request_position(dse->getEvent(), dse->getKnot()); + break; + default: + g_warning("Origin of snap-delay event has not been defined!;"); + break; + } + + ec->_delayed_snap_event = NULL; + delete dse; + + return FALSE; //Kills the timer and stops it from executing this callback over and over again. +} + +void sp_event_context_snap_window_open(SPEventContext *ec, bool show_debug_warnings) +{ + // Only when ec->_snap_window_open 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_event_context_snap_window_open(*, TRUE) when entering the "dragging" state, which will delay + // snapping from that moment on, and call sp_event_context_snap_window_open(*, FALSE) when leaving the "dragging" + // state. This last call will also make sure that any pending snap events will be canceled. + + //std::cout << "sp_event_context_snap_window_open" << std::endl; + if (!ec) { + if (show_debug_warnings) { + g_warning("sp_event_context_snap_window_open() has been called without providing an event context!"); + } + return; + } + + if (ec->_snap_window_open == true && show_debug_warnings) { + g_warning("Snap window was already open! This is a bug, please report it."); + } + + ec->_snap_window_open = true; +} + +void sp_event_context_snap_window_closed(SPEventContext *ec, bool show_debug_warnings) +{ + //std::cout << "sp_event_context_snap_window_closed" << std::endl; + if (!ec) { + if (show_debug_warnings) { + g_warning("sp_event_context_snap_window_closed() has been called without providing an event context!"); + } + return; + } + + if (ec->_snap_window_open == false && show_debug_warnings) { + g_warning("Snap window was already closed! This is a bug, please report it."); + } + + ec->_snap_window_open = false; + + delete ec->_delayed_snap_event; + ec->_delayed_snap_event = NULL; +} + + + /* Local Variables: mode:c++ diff --git a/src/event-context.h b/src/event-context.h index df4aa6eab..638ac56f7 100644 --- a/src/event-context.h +++ b/src/event-context.h @@ -20,6 +20,7 @@ #include #include #include +#include "knot.h" #include "2geom/forward.h" #include "preferences.h" @@ -28,6 +29,7 @@ struct GrDrag; struct SPDesktop; struct SPItem; class ShapeEditor; +struct SPEventContext; namespace Inkscape { class MessageContext; @@ -37,6 +39,52 @@ namespace Inkscape { } } +gboolean sp_event_context_snap_watchdog_callback(gpointer data); +void sp_event_context_snap_window_open(SPEventContext *ec, bool show_debug_warnings = true); +void sp_event_context_snap_window_closed(SPEventContext *ec, bool show_debug_warnings = true); + +class DelayedSnapEvent +{ +public: + enum DelayedSnapEventOrigin { + UNDEFINED_HANDLER = 0, + EVENTCONTEXT_ROOT_HANDLER, + EVENTCONTEXT_ITEM_HANDLER, + KNOT_HANDLER + }; + + DelayedSnapEvent(SPEventContext *event_context, SPItem* const item, SPKnot* knot, GdkEventMotion const *event, DelayedSnapEvent::DelayedSnapEventOrigin const origin) + : _timer_id(0), _event(NULL), _item(item), _knot(knot), _origin(origin), _event_context(event_context) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double value = prefs->getDoubleLimited("/options/snapdelay/value", 0, 0, 1000); + _timer_id = g_timeout_add(value, &sp_event_context_snap_watchdog_callback, this); + _event = gdk_event_copy((GdkEvent*) event); + ((GdkEventMotion *)_event)->time = GDK_CURRENT_TIME; + } + + ~DelayedSnapEvent() { + if (_timer_id > 0) g_source_remove(_timer_id); // Kill the watchdog + if (_event != NULL) gdk_event_free(_event); // Remove the copy of the original event + } + + SPEventContext* getEventContext() {return _event_context;} + DelayedSnapEventOrigin getOrigin() {return _origin;} + GdkEvent* getEvent() {return _event;} + SPItem* getItem() {return _item;} + SPKnot* getKnot() {return _knot;} + +private: + guint _timer_id; + GdkEvent* _event; + SPItem* _item; + SPKnot* _knot; + DelayedSnapEventOrigin _origin; + SPEventContext* _event_context; +}; + +void sp_event_context_snap_delay_handler(SPEventContext *ec, SPItem* const item, SPKnot* const knot, GdkEventMotion *event, DelayedSnapEvent::DelayedSnapEventOrigin origin); + /** * Base class for Event processors. */ @@ -57,7 +105,7 @@ struct SPEventContext : public GObject { gint tolerance; bool within_tolerance; ///< are we still within tolerance of origin - SPItem *item_to_select; ///< the item where mouse_press occurred, to + SPItem *item_to_select; ///< the item where mouse_press occurred, to ///< be selected if this is a click not drag Inkscape::MessageContext *defaultMessageContext() { @@ -74,6 +122,9 @@ struct SPEventContext : public GObject { ShapeEditor* shape_editor; bool space_panning; + + bool _snap_window_open; + DelayedSnapEvent *_delayed_snap_event; }; /** @@ -101,7 +152,9 @@ void sp_event_context_activate(SPEventContext *ec); void sp_event_context_deactivate(SPEventContext *ec); gint sp_event_context_root_handler(SPEventContext *ec, GdkEvent *event); +gint sp_event_context_virtual_root_handler(SPEventContext *ec, GdkEvent *event); gint sp_event_context_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event); +gint sp_event_context_virtual_item_handler(SPEventContext *ec, SPItem *item, GdkEvent *event); void sp_event_root_menu_popup(SPDesktop *desktop, SPItem *item, GdkEvent *event); diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index 16df41f7a..03c3c947c 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -114,8 +114,6 @@ 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) { @@ -219,7 +217,7 @@ static void sp_gradient_context_setup(SPEventContext *ec) 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); + sp_event_context_snap_window_open(ec); } void diff --git a/src/knot.cpp b/src/knot.cpp index fab622bbd..ae8a7f7c5 100644 --- a/src/knot.cpp +++ b/src/knot.cpp @@ -29,7 +29,6 @@ #include "message-context.h" #include "event-context.h" - #define KNOT_EVENT_MASK (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | \ GDK_POINTER_MOTION_MASK | \ GDK_POINTER_MOTION_HINT_MASK | \ @@ -318,8 +317,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot 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); - if (knot->desktop->canvas->context_snap_delay_active == false) { - sp_canvas_set_snap_delay_active(knot->desktop->canvas, true); + if (knot->desktop->event_context->_snap_window_open == false) { + sp_event_context_snap_window_open(knot->desktop->event_context); snap_delay_temporarily_active = true; } consumed = TRUE; @@ -327,7 +326,15 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot break; case GDK_BUTTON_RELEASE: if (event->button.button == 1 && !knot->desktop->event_context->space_panning) { - knot->pressure = 0; + if (snap_delay_temporarily_active) { + if (knot->desktop->event_context->_snap_window_open == true) { + sp_event_context_snap_window_closed(knot->desktop->event_context); + } + snap_delay_temporarily_active = false; + } + sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event); + + knot->pressure = 0; if (transform_escaped) { transform_escaped = false; consumed = TRUE; @@ -353,13 +360,6 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot grabbed = FALSE; moved = FALSE; consumed = TRUE; - - if (snap_delay_temporarily_active) { - if (knot->desktop->canvas->context_snap_delay_active == true) { - sp_canvas_set_snap_delay_active(knot->desktop->canvas, false); - } - snap_delay_temporarily_active = false; - } } } break; @@ -391,14 +391,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot SP_KNOT_DRAGGING, TRUE); } - 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); + sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, DelayedSnapEvent::KNOT_HANDLER); + sp_knot_handler_request_position(event, knot); moved = TRUE; } break; @@ -428,35 +422,35 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot break; 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; - if (snap_delay_temporarily_active) { - sp_canvas_set_snap_delay_active(knot->desktop->canvas, false); - snap_delay_temporarily_active = false; + 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; + if (snap_delay_temporarily_active) { + sp_event_context_snap_window_closed(knot->desktop->event_context); + snap_delay_temporarily_active = false; + } + break; + default: + consumed = FALSE; + break; } - break; - default: - consumed = FALSE; - break; - } - break; + break; default: break; } @@ -466,6 +460,18 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot return consumed; } +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); +} + /** * Return new knot object. */ diff --git a/src/knot.h b/src/knot.h index 07c2640c3..351c7f7be 100644 --- a/src/knot.h +++ b/src/knot.h @@ -33,7 +33,7 @@ class SPKnotClass; /** * Desktop-bound visual control object. - * + * * A knot is a draggable object, with callbacks to change something by * dragging it, visuably represented by a canvas item (mostly square). */ @@ -174,6 +174,7 @@ void sp_knot_set_position(SPKnot *knot, Geom::Point const &p, guint state); /** Moves knot without any signal. */ void sp_knot_moveto(SPKnot *knot, Geom::Point const &p); +void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot); Geom::Point sp_knot_position(SPKnot const *knot); diff --git a/src/knotholder.cpp b/src/knotholder.cpp index 60c1f8084..773b9249c 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -139,7 +139,7 @@ KnotHolder::knot_moved_handler(SPKnot *knot, Geom::Point const &p, guint state) { if (this->dragging == false) { this->dragging = true; - //sp_canvas_set_snap_delay_active(desktop->canvas, true); + //sp_event_context_snap_window_open(desktop->canvas); } // this was a local change and the knotholder does not need to be recreated: @@ -165,7 +165,7 @@ void KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/) { this->dragging = false; - //sp_canvas_set_snap_delay_active(desktop->canvas, false); + //sp_event_context_snap_window_closed(desktop->canvas); if (this->released) { this->released(this->item); diff --git a/src/node-context.cpp b/src/node-context.cpp index f40d1b7fc..44dbabcb0 100644 --- a/src/node-context.cpp +++ b/src/node-context.cpp @@ -294,7 +294,7 @@ sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (!(event->button.state & GDK_SHIFT_MASK)) { if (!nc->drag) { if (se->has_nodepath() && selection->single() /* && item_over */) { - sp_canvas_set_snap_delay_active(desktop->canvas, true); + sp_event_context_snap_window_open(event_context); // save drag origin bool over_stroke = se->is_over_stroke(Geom::Point(event->button.x, event->button.y), true); //only dragging curves @@ -425,13 +425,13 @@ sp_node_context_root_handler(SPEventContext *event_context, GdkEvent *event) } desktop->updateNow(); } - sp_canvas_set_snap_delay_active(desktop->canvas, false); + sp_event_context_snap_window_closed(event_context); break; case GDK_2BUTTON_PRESS: //add a node se->add_node_near_point(); nc->added_node = true; - sp_canvas_set_snap_delay_active(desktop->canvas, false); + sp_event_context_snap_window_closed(event_context); break; default: break; diff --git a/src/nodepath.cpp b/src/nodepath.cpp index ed356e5c4..b92a3bf85 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -3590,7 +3590,7 @@ 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); + //sp_event_context_snap_window_open(n->subpath->nodepath->desktop->canvas); // 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; @@ -3608,7 +3608,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); + //sp_event_context_snap_window_closed(n->subpath->nodepath->desktop->canvas); n->subpath->nodepath->drag_origin_mouse = Geom::Point(NR_HUGE, NR_HUGE); sp_canvas_end_forced_full_redraws(n->subpath->nodepath->desktop->canvas); diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 7ffabcefd..beece2b31 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -208,8 +208,6 @@ 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); } @@ -265,7 +263,7 @@ sp_pen_context_finish(SPEventContext *ec) { SPPenContext *pc = SP_PEN_CONTEXT(ec); - sp_canvas_set_snap_delay_active(pc->desktop->canvas, false); + sp_event_context_snap_window_closed(ec, false); //TODO: Detailed implementation of the snap window; now it's simply always open if (pc->npoints != 0) { pen_cancel (pc); @@ -369,6 +367,8 @@ sp_pen_context_root_handler(SPEventContext *ec, GdkEvent *event) { SPPenContext *const pc = SP_PEN_CONTEXT(ec); + sp_event_context_snap_window_open(ec, false); //TODO: Detailed implementation of the snap window; now it's simply always open + gint ret = FALSE; switch (event->type) { diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index fc2088a17..4b87e86b5 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -255,7 +255,7 @@ pencil_handle_button_press(SPPencilContext *const pc, GdkEventButton const &beve /* Set first point of sequence */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); - sp_canvas_set_snap_delay_active(desktop->canvas, true); + sp_event_context_snap_window_open(event_context); if (anchor) { p = anchor->dp; @@ -349,7 +349,7 @@ pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mev /* We may be idle or already freehand */ if ( mevent.state & GDK_BUTTON1_MASK && pc->is_drawing ) { if (pc->state == SP_PENCIL_CONTEXT_IDLE) { - sp_canvas_set_snap_delay_active(dt->canvas, false); + sp_event_context_snap_window_closed(event_context); } pc->state = SP_PENCIL_CONTEXT_FREEHAND; @@ -417,7 +417,7 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re /* Releasing button in idle mode means single click */ /* We have already set up start point/anchor in button_press */ pc->state = SP_PENCIL_CONTEXT_ADDLINE; - //sp_canvas_set_snap_delay_active(dt->canvas, true); + //sp_event_context_snap_window_open(dt->canvas); ret = TRUE; break; case SP_PENCIL_CONTEXT_ADDLINE: @@ -431,7 +431,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); + sp_event_context_snap_window_closed(event_context); ret = TRUE; break; case SP_PENCIL_CONTEXT_FREEHAND: @@ -445,7 +445,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); + //sp_event_context_snap_window_open(dt->canvas); } else { /* Finish segment now */ /// \todo fixme: Clean up what follows (Lauris) @@ -465,7 +465,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); + // sp_event_context_snap_window_closed(dt->canvas); // reset sketch mode too pc->sketch_n = 0; } @@ -498,7 +498,7 @@ 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); + sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(pc)); pc->red_curve->reset(); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), NULL); @@ -589,7 +589,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); + sp_event_context_snap_window_closed(SP_EVENT_CONTEXT(pc)); pc->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand sketch")); ret = TRUE; } diff --git a/src/rect-context.cpp b/src/rect-context.cpp index 3650e05b1..9c1c704dd 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -257,7 +257,7 @@ 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); + sp_event_context_snap_window_open(event_context); /* Position center */ Geom::Point button_dt(desktop->w2d(button_w)); @@ -306,7 +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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the rect @@ -381,7 +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); + sp_event_context_snap_window_closed(event_context); 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 b2a05dca2..e30ef53d2 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -212,6 +212,7 @@ sp_select_context_abort(SPEventContext *event_context) seltrans->ungrab(); sc->moved = FALSE; sc->dragging = FALSE; + sp_event_context_snap_window_closed(event_context); drag_escaped = 1; if (sc->item) { @@ -323,6 +324,7 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE // pass the event to root handler which will perform rubberband, shift-click, ctrl-click, ctrl-drag } else { sc->dragging = TRUE; + sp_event_context_snap_window_open(event_context); sc->moved = FALSE; sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5); @@ -427,6 +429,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) desktop->setCurrentLayer(reinterpret_cast(clicked_item)); sp_desktop_selection(desktop)->clear(); sc->dragging = false; + sp_event_context_snap_window_closed(event_context); sp_canvas_end_forced_full_redraws(desktop->canvas); } else { // switch tool @@ -497,6 +500,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) // if it's not click and ctrl or alt was pressed (the latter with some selection // but not with shift) we want to drag rather than rubberband sc->dragging = TRUE; + sp_event_context_snap_window_open(event_context); sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5); } @@ -547,7 +551,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) ret = TRUE; } else { sc->dragging = FALSE; - + sp_event_context_snap_window_closed(event_context); sp_canvas_end_forced_full_redraws(desktop->canvas); } } else { @@ -596,7 +600,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } } sc->dragging = FALSE; - + sp_event_context_snap_window_closed(event_context); sp_canvas_end_forced_full_redraws(desktop->canvas); if (sc->item) { diff --git a/src/seltrans.cpp b/src/seltrans.cpp index f3ad2849c..e6c53acfe 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -368,7 +368,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } } - sp_canvas_set_snap_delay_active(_desktop->canvas, true); + //sp_event_context_snap_window_open(_desktop->event_context); if ((x != -1) && (y != -1)) { sp_canvas_item_show(_norm); @@ -422,7 +422,7 @@ void Inkscape::SelTrans::ungrab() _grabbed = false; _show_handles = true; - sp_canvas_set_snap_delay_active(_desktop->canvas, false); + //sp_event_context_snap_window_closed(_desktop->event_context); _desktop->snapindicator->remove_snapsource(); diff --git a/src/snap.cpp b/src/snap.cpp index 2b9a45a1d..19455ba73 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -32,6 +32,7 @@ #include "desktop.h" #include "sp-guide.h" #include "preferences.h" +#include "event-context.h" using std::vector; /** @@ -160,12 +161,14 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointTyp bool first_point, Geom::OptRect const &bbox_to_snap) const { - 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 (_desktop->event_context->_snap_window_open == false) { + g_warning("context_snap_window_open 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_event_context_snap_window_open(event_context); + } + + //std::cout << "SnapManager::freeSnap -> postponed: " << snapprefs.getSnapPostponedGlobally() << std::endl; - if (!someSnapperMightSnap()) { + if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } @@ -293,12 +296,12 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P bool first_point, Geom::OptRect const &bbox_to_snap) const { - 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 (_desktop->event_context->_snap_window_open == false) { + g_warning("context_snap_window_open 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_event_context_snap_window_open(event_context); + } - if (!someSnapperMightSnap()) { + if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, source_type, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false); } @@ -331,10 +334,10 @@ void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) con { // This method is used to snap a guide to nodes or to other guides, while dragging the guide around. Will not snap to grids! - 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 (_desktop->event_context->_snap_window_open == false) { + g_warning("context_snap_window_open 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_event_context_snap_window_open(event_context); + } if (!snapprefs.getSnapEnabledGlobally() || snapprefs.getSnapPostponedGlobally()) { return; diff --git a/src/spiral-context.cpp b/src/spiral-context.cpp index e91f550dc..67ee82b35 100644 --- a/src/spiral-context.cpp +++ b/src/spiral-context.cpp @@ -220,7 +220,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); + sp_event_context_snap_window_open(event_context); sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); SnapManager &m = desktop->namedview->snap_manager; @@ -269,7 +269,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the spiral sp_spiral_finish(sc); @@ -329,7 +329,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_spiral_finish(sc); diff --git a/src/star-context.cpp b/src/star-context.cpp index b2c56cc7f..5361219aa 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -234,7 +234,7 @@ 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); + sp_event_context_snap_window_open(event_context); sc->center = Inkscape::setup_for_drag_start(desktop, event_context, event); @@ -281,7 +281,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the star sp_star_finish (sc); @@ -341,7 +341,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); + sp_event_context_snap_window_closed(event_context); if (!event_context->within_tolerance) { // we've been dragging, finish the rect sp_star_finish(sc); diff --git a/src/text-context.cpp b/src/text-context.cpp index d743d45c2..a5af08385 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -352,7 +352,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); + sp_event_context_snap_window_open(event_context); } ret = TRUE; } @@ -369,7 +369,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); + sp_event_context_snap_window_open(event_context); ret = TRUE; } } @@ -381,14 +381,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); + sp_event_context_snap_window_open(event_context); 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); + sp_event_context_snap_window_closed(event_context); ret = TRUE; } break; @@ -1392,7 +1392,7 @@ sp_text_get_selected_text(SPEventContext const *ec) SPCSSAttr * sp_text_get_style_at_cursor(SPEventContext const *ec) -{ +{ if (!SP_IS_TEXT_CONTEXT(ec)) return NULL; SPTextContext const *tc = SP_TEXT_CONTEXT(ec);