X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fevent-context.cpp;h=828ce3d5b1d02ab950dc31ab76eb789603ca24d3;hb=42382dfb4164b919ffcdf03766da9f8be4e43b42;hp=100e6b1430123126dfbf94c6466a90c4776feb58;hpb=f200d31b8a03050faa7243929bbd5698db488399;p=inkscape.git diff --git a/src/event-context.cpp b/src/event-context.cpp index 100e6b143..828ce3d5b 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -1,5 +1,3 @@ -#define __SP_EVENT_CONTEXT_C__ - /** \file * Main event handling, and related helper functions. * @@ -7,8 +5,9 @@ * Lauris Kaplinski * Frank Felfe * bulia byak + * Jon A. Cruz * - * Copyright (C) 1999-2005 authors + * Copyright (C) 1999-2010 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information @@ -43,6 +42,9 @@ #include "shortcuts.h" #include "desktop.h" #include "desktop-handles.h" +#include "desktop-events.h" +#include "desktop-style.h" +#include "widgets/desktop-widget.h" #include "sp-namedview.h" #include "selection.h" #include "file.h" @@ -58,6 +60,9 @@ #include "selcue.h" #include "lpe-tool-context.h" #include "ui/tool/control-point.h" +#include "shape-editor.h" +#include "sp-guide.h" +#include "color.h" static void sp_event_context_class_init(SPEventContextClass *klass); static void sp_event_context_init(SPEventContext *event_context); @@ -136,6 +141,8 @@ static void sp_event_context_init(SPEventContext *event_context) { event_context->space_panning = false; event_context->shape_editor = NULL; event_context->_delayed_snap_event = NULL; + event_context->_dse_callback_in_process = false; + event_context->tool_url = NULL; } /** @@ -178,17 +185,38 @@ void sp_event_context_update_cursor(SPEventContext *ec) { if (w->window) { /* fixme: */ if (ec->cursor_shape) { - GdkBitmap *bitmap = NULL; - GdkBitmap *mask = NULL; - sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, ec->cursor_shape); - if ((bitmap != NULL) && (mask != NULL)) { - if (ec->cursor) - gdk_cursor_unref(ec->cursor); - ec->cursor = gdk_cursor_new_from_pixmap(bitmap, mask, - &w->style->black, &w->style->white, ec->hot_x, - ec->hot_y); - g_object_unref(bitmap); - g_object_unref(mask); + GdkDisplay *display = gdk_display_get_default(); + if (ec->tool_url && gdk_display_supports_cursor_alpha(display) && gdk_display_supports_cursor_color(display)) { + bool fillHasColor=false, strokeHasColor=false; + guint32 fillColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, true, &fillHasColor); + guint32 strokeColor = sp_desktop_get_color_tool(ec->desktop, ec->tool_url, false, &strokeHasColor); + double fillOpacity = fillHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, true) : 0; + double strokeOpacity = strokeHasColor ? sp_desktop_get_opacity_tool(ec->desktop, ec->tool_url, false) : 0; + GdkPixbuf *pixbuf = sp_cursor_pixbuf_from_xpm( + ec->cursor_shape, + w->style->black, w->style->white, + SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(fillColor),SP_RGBA32_G_U(fillColor),SP_RGBA32_B_U(fillColor),SP_COLOR_F_TO_U(fillOpacity)), + SP_RGBA32_U_COMPOSE(SP_RGBA32_R_U(strokeColor),SP_RGBA32_G_U(strokeColor),SP_RGBA32_B_U(strokeColor),SP_COLOR_F_TO_U(strokeOpacity)) + ); + if (pixbuf != NULL) { + if (ec->cursor) + gdk_cursor_unref(ec->cursor); + ec->cursor = gdk_cursor_new_from_pixbuf(display, pixbuf, ec->hot_x, ec->hot_y); + g_object_unref(pixbuf); + } + } else { + GdkBitmap *bitmap = NULL; + GdkBitmap *mask = NULL; + sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, ec->cursor_shape); + if ((bitmap != NULL) && (mask != NULL)) { + if (ec->cursor) + gdk_cursor_unref(ec->cursor); + ec->cursor = gdk_cursor_new_from_pixmap(bitmap, mask, + &w->style->black, &w->style->white, ec->hot_x, + ec->hot_y); + g_object_unref(bitmap); + g_object_unref(mask); + } } } gdk_window_set_cursor(w->window, ec->cursor); @@ -743,6 +771,19 @@ gint sp_event_context_private_item_handler(SPEventContext *ec, SPItem *item, return ret; } +/** + * @brief: Returns true if we're hovering above a knot (needed because we don't want to pre-snap in that case) + */ + +bool sp_event_context_knot_mouseover(SPEventContext *ec) +{ + if (ec->shape_editor) { + return ec->shape_editor->knot_mouseover(); + } + + return false; +} + /** * @brief An observer that relays pref changes to the derived classes */ @@ -888,7 +929,8 @@ void sp_event_context_deactivate(SPEventContext *ec) { * Calls virtual root_handler(), the main event handling function. */ gint sp_event_context_root_handler(SPEventContext * event_context, - GdkEvent * event) { + GdkEvent * event) +{ switch (event->type) { case GDK_MOTION_NOTIFY: sp_event_context_snap_delay_handler(event_context, NULL, NULL, @@ -917,13 +959,13 @@ gint sp_event_context_root_handler(SPEventContext * event_context, return sp_event_context_virtual_root_handler(event_context, event); } -gint sp_event_context_virtual_root_handler(SPEventContext * event_context, - GdkEvent * event) { - gint - ret = - ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler( - event_context, event); - set_event_location(event_context->desktop, event); +gint sp_event_context_virtual_root_handler(SPEventContext * event_context, GdkEvent * event) { + gint ret = false; + if (event_context) { // If no event-context is available then do nothing, otherwise Inkscape would crash + // (see the comment in SPDesktop::set_event_context, and bug LP #622350) + ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->root_handler(event_context, event); + set_event_location(event_context->desktop, event); + } return ret; } @@ -934,25 +976,21 @@ gint sp_event_context_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event) { switch (event->type) { case GDK_MOTION_NOTIFY: - sp_event_context_snap_delay_handler(event_context, item, NULL, - (GdkEventMotion *) event, - DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER); + sp_event_context_snap_delay_handler(event_context, (gpointer) item, NULL, (GdkEventMotion *) event, DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER); break; case GDK_BUTTON_RELEASE: if (event_context->_delayed_snap_event) { // If we have any pending snapping action, then invoke it now - sp_event_context_snap_watchdog_callback( - event_context->_delayed_snap_event); + sp_event_context_snap_watchdog_callback(event_context->_delayed_snap_event); } 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; - */ + 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; } @@ -960,17 +998,16 @@ gint sp_event_context_item_handler(SPEventContext * event_context, return sp_event_context_virtual_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_virtual_root_handler(event_context, event); - } else { - set_event_location(event_context->desktop, event); +gint sp_event_context_virtual_item_handler(SPEventContext * event_context, SPItem * item, GdkEvent * event) { + gint ret = false; + if (event_context) { // If no event-context is available then do nothing, otherwise Inkscape would crash + // (see the comment in SPDesktop::set_event_context, and bug LP #622350) + ret = ((SPEventContextClass *) G_OBJECT_GET_CLASS(event_context))->item_handler(event_context, item, event); + if (!ret) { + ret = sp_event_context_virtual_root_handler(event_context, event); + } else { + set_event_location(event_context->desktop, event); + } } return ret; @@ -1065,20 +1102,21 @@ guint get_group0_keyval(GdkEventKey *event) { * If state includes alt key mask, cyclically selects under; honors * into_groups. */ -SPItem * -sp_event_context_find_item(SPDesktop *desktop, Geom::Point const &p, - bool select_under, bool into_groups) { - SPItem *item; +SPItem *sp_event_context_find_item(SPDesktop *desktop, Geom::Point const &p, + bool select_under, bool into_groups) +{ + SPItem *item = 0; if (select_under) { - SPItem *selected_at_point = desktop->item_from_list_at_point_bottom( + SPItem *selected_at_point = desktop->getItemFromListAtPointBottom( desktop->selection->itemList(), p); - item = desktop->item_at_point(p, into_groups, selected_at_point); + item = desktop->getItemAtPoint(p, into_groups, selected_at_point); if (item == NULL) { // we may have reached bottom, flip over to the top - item = desktop->item_at_point(p, into_groups, NULL); + item = desktop->getItemAtPoint(p, into_groups, NULL); } - } else - item = desktop->item_at_point(p, into_groups, NULL); + } else { + item = desktop->getItemAtPoint(p, into_groups, NULL); + } return item; } @@ -1093,7 +1131,7 @@ sp_event_context_over_item(SPDesktop *desktop, SPItem *item, Geom::Point const &p) { GSList *temp = NULL; temp = g_slist_prepend(temp, item); - SPItem *item_at_point = desktop->item_from_list_at_point_bottom(temp, p); + SPItem *item_at_point = desktop->getItemFromListAtPointBottom(temp, p); g_slist_free(temp); return item_at_point; @@ -1146,12 +1184,28 @@ void event_context_print_event_info(GdkEvent *event, bool print_return) { } } +/** + * \brief 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) + * + * \param ec Pointer to the event context + * \param dse_item Pointer that store a reference to a canvas or to an item + * \param dse_item2 Another pointer, storing a reference to a knot or controlpoint + * \param event Pointer to the motion event + * \param origin Identifier (enum) specifying where the delay (and the call to this method) were initiated + */ void sp_event_context_snap_delay_handler(SPEventContext *ec, - SPItem* const item, SPKnot* const knot, GdkEventMotion *event, - DelayedSnapEvent::DelayedSnapEventOrigin origin) { + gpointer const dse_item, gpointer const dse_item2, GdkEventMotion *event, + DelayedSnapEvent::DelayedSnapEventOrigin origin) +{ static guint32 prev_time; static boost::optional 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 @@ -1171,8 +1225,7 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, // 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 + 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); @@ -1189,7 +1242,7 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, // 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, + 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 @@ -1201,14 +1254,14 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, // 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, item, - knot, event, origin); + 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, item, knot, + ec->_delayed_snap_event = new DelayedSnapEvent(ec, dse_item, dse_item2, event, origin); } @@ -1217,6 +1270,10 @@ void sp_event_context_snap_delay_handler(SPEventContext *ec, } } +/** + * \brief When the snap delay watchdog timer barks, this method will be called and will re-inject the last motion + * event in an appropriate place, with snapping being turned on again + */ 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); @@ -1231,24 +1288,27 @@ gboolean sp_event_context_snap_watchdog_callback(gpointer data) { if (ec == NULL || ec->desktop == NULL) { return false; } + ec->_dse_callback_in_process = true; SPDesktop *dt = ec->desktop; dt->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); + // Depending on where the delayed snap event originated from, we will inject it back at it's origin + // The switch below takes care of that and prepares the relevant parameters switch (dse->getOrigin()) { case DelayedSnapEvent::EVENTCONTEXT_ROOT_HANDLER: sp_event_context_virtual_root_handler(ec, dse->getEvent()); break; case DelayedSnapEvent::EVENTCONTEXT_ITEM_HANDLER: { SPItem* item = NULL; - item = dse->getItem(); + item = SP_ITEM(dse->getItem()); if (item && SP_IS_ITEM(item)) { sp_event_context_virtual_item_handler(ec, item, dse->getEvent()); } } break; case DelayedSnapEvent::KNOT_HANDLER: { - SPKnot* knot = dse->getKnot(); + SPKnot* knot = SP_KNOT(dse->getItem2()); if (knot && SP_IS_KNOT(knot)) { sp_knot_handler_request_position(dse->getEvent(), knot); } @@ -1256,10 +1316,35 @@ gboolean sp_event_context_snap_watchdog_callback(gpointer data) { break; case DelayedSnapEvent::CONTROL_POINT_HANDLER: { using Inkscape::UI::ControlPoint; - ControlPoint *point = reinterpret_cast (dse->getKnot()); + ControlPoint *point = reinterpret_cast (dse->getItem2()); point->_eventHandler(dse->getEvent()); } break; + case DelayedSnapEvent::GUIDE_HANDLER: { + gpointer item = dse->getItem(); + gpointer item2 = dse->getItem2(); + if (item && item2) { + g_assert(SP_IS_CANVAS_ITEM(item)); + g_assert(SP_IS_GUIDE(item2)); + sp_dt_guide_event(SP_CANVAS_ITEM(item), dse->getEvent(), item2); + } + } + break; + case DelayedSnapEvent::GUIDE_HRULER: + case DelayedSnapEvent::GUIDE_VRULER: { + gpointer item = dse->getItem(); + gpointer item2 = dse->getItem2(); + if (item && item2) { + g_assert(GTK_IS_WIDGET(item)); + g_assert(SP_IS_DESKTOP_WIDGET(item2)); + if (dse->getOrigin() == DelayedSnapEvent::GUIDE_HRULER) { + sp_dt_hruler_event(GTK_WIDGET(item), dse->getEvent(), SP_DESKTOP_WIDGET(item2)); + } else { + sp_dt_vruler_event(GTK_WIDGET(item), dse->getEvent(), SP_DESKTOP_WIDGET(item2)); + } + } + } + break; default: g_warning("Origin of snap-delay event has not been defined!;"); break; @@ -1268,12 +1353,15 @@ gboolean sp_event_context_snap_watchdog_callback(gpointer data) { ec->_delayed_snap_event = NULL; delete dse; + ec->_dse_callback_in_process = false; + return FALSE; //Kills the timer and stops it from executing this callback over and over again. } void sp_event_context_discard_delayed_snap_event(SPEventContext *ec) { delete ec->_delayed_snap_event; ec->_delayed_snap_event = NULL; + ec->desktop->namedview->snap_manager.snapprefs.setSnapPostponedGlobally(false); } /* @@ -1285,4 +1373,4 @@ void sp_event_context_discard_delayed_snap_event(SPEventContext *ec) { fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :