summaryrefslogtreecommitdiffstats
path: root/src/display/sp-canvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/sp-canvas.cpp')
-rw-r--r--src/display/sp-canvas.cpp171
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!