Logo Search packages:      
Sourcecode: inkscape version File versions  Download package

void sp_event_context_snap_delay_handler ( SPEventContext ec,
gpointer const  dse_item,
gpointer const  dse_item2,
GdkEventMotion *  event,
DelayedSnapEvent::DelayedSnapEventOrigin  origin 
)

Analyses the current event, calculates the mouse speed, turns snapping off (temporarily) if the mouse speed is above a threshold, and stores the current event such that it can be re-triggered when needed (re-triggering is controlled by a watchdog timer)

Parameters:
ecPointer to the event context
dse_itemPointer that store a reference to a canvas or to an item
dse_item2Another pointer, storing a reference to a knot or controlpoint
eventPointer to the motion event
originIdentifier (enum) specifying where the delay (and the call to this method) were initiated

Definition at line 1174 of file event-context.cpp.

Referenced by sp_event_context_item_handler(), sp_event_context_root_handler(), and sp_knot_handler().

{
    static guint32 prev_time;
    static boost::optional<Geom::Point> prev_pos;

    if (ec->_dse_callback_in_process) {
        return;
    }

    // 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
    bool const c3 = tools_isactive(ec->desktop, TOOLS_CALLIGRAPHIC);
    // The snap delay will repeat the last motion event, which will lead to
    // erroneous points in the calligraphy context. And because we don't snap
    // in this context, we might just as well disable the snap delay all together

    if (c1 || c2 || c3) {
        // Make sure that we don't send any pending snap events to a context if we know in advance
        // that we're not going to snap any way (e.g. while scrolling with middle mouse button)
        // Any motion event might affect the state of the context, leading to unexpected behavior
        sp_event_context_discard_delayed_snap_event(ec);
    } else if (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, dse_item, dse_item2,
                        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 this way
                    ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item,
                            dse_item2, 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, dse_item, dse_item2,
                    event, origin);
        }

        prev_pos = event_pos;
        prev_time = event_t;
    }
}

Here is the caller graph for this function:


Generated by  Doxygen 1.6.0   Back to index