diff options
Diffstat (limited to 'src/display/sp-canvas.cpp')
| -rw-r--r-- | src/display/sp-canvas.cpp | 171 |
1 files changed, 97 insertions, 74 deletions
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<Geom::Point> 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<SPCanvas *>(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! |
