summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorDiederik van Lierop <mail@diedenrezi.nl>2009-02-15 20:30:42 +0000
committerdvlierop2 <dvlierop2@users.sourceforge.net>2009-02-15 20:30:42 +0000
commit32035d39b6b1138500eee1f625e40fe52c29bf26 (patch)
treeeb93df4c2799563e5eab32e06075f703e56443f5 /src/display
parentZero page size for GTK spinbutton change (diff)
downloadinkscape-32035d39b6b1138500eee1f625e40fe52c29bf26.tar.gz
inkscape-32035d39b6b1138500eee1f625e40fe52c29bf26.zip
After snapping, show a tooltip together with the snap indicator
(bzr r7296)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/snap-indicator.cpp147
-rw-r--r--src/display/snap-indicator.h6
-rw-r--r--src/display/sp-canvas.cpp51
3 files changed, 156 insertions, 48 deletions
diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp
index 98358dbab..1785da7b9 100644
--- a/src/display/snap-indicator.cpp
+++ b/src/display/snap-indicator.cpp
@@ -5,8 +5,8 @@
* Johan Engelen
* Diederik van Lierop
*
- * Copyright (C) Johan Engelen 2008 <j.b.c.engelen@utwente.nl>
- * Copyright (C) Diederik van Lierop 2008 <mail@diedenrezi.nl>
+ * Copyright (C) Johan Engelen 2009 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Diederik van Lierop 2009 <mail@diedenrezi.nl>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -18,6 +18,8 @@
#include "display/sodipodi-ctrl.h"
#include "knot.h"
#include "preferences.h"
+#include <glibmm/i18n.h>
+#include <gtk/gtk.h>
namespace Inkscape {
namespace Display {
@@ -53,48 +55,94 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const p)
bool value = prefs->getBool("/options/snapindicator/value", true);
if (value) {
- SPCanvasItem * canvasitem = NULL;
+ gchar *target_name = _("UNDEFINED");
switch (p.getTarget()) {
- /// @todo add the different kinds of snapindicator visuals
- case SNAPTARGET_NODE:
- canvasitem = sp_canvas_item_new(sp_desktop_tempgroup (_desktop),
- SP_TYPE_CTRL,
- "anchor", GTK_ANCHOR_CENTER,
- "size", 10.0,
- "stroked", TRUE,
- "stroke_color", 0xf000f0ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_DIAMOND,
- NULL );
- break;
- case SNAPTARGET_GRID:
+ case SNAPTARGET_UNDEFINED:
+ target_name = _("UNDEFINED");
+ break;
+ case SNAPTARGET_GRID:
+ target_name = _("grid line");
+ break;
case SNAPTARGET_GRID_INTERSECTION:
+ target_name = _("grid intersection");
+ break;
case SNAPTARGET_GUIDE:
+ target_name = _("guide");
+ break;
case SNAPTARGET_GUIDE_INTERSECTION:
+ target_name = _("guide intersection");
+ break;
case SNAPTARGET_GRID_GUIDE_INTERSECTION:
- case SNAPTARGET_PATH:
+ target_name = _("grid-guide intersection");
+ break;
+ case SNAPTARGET_NODE:
+ target_name = _("node");
+ break;
+ case SNAPTARGET_PATH:
+ target_name = _("path");
+ break;
case SNAPTARGET_PATH_INTERSECTION:
+ target_name = _("path intersection");
+ break;
case SNAPTARGET_BBOX_CORNER:
+ target_name = _("bounding box corner");
+ break;
case SNAPTARGET_BBOX_EDGE:
+ target_name = _("bounding box side");
+ break;
case SNAPTARGET_GRADIENT:
- case SNAPTARGET_UNDEFINED:
+ target_name = _("gradient");
+ break;
+ case SNAPTARGET_PAGE_BORDER:
+ target_name = _("page border");
+ break;
default:
- canvasitem = sp_canvas_item_new(sp_desktop_tempgroup (_desktop),
- SP_TYPE_CTRL,
- "anchor", GTK_ANCHOR_CENTER,
- "size", 10.0,
- "stroked", TRUE,
- "stroke_color", 0xf000f0ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_CROSS,
- NULL );
+ g_warning("Snap target has not yet been defined!");
break;
}
+ // std::cout << "Snapped to: " << target_name << std::endl;
- SP_CTRL(canvasitem)->moveto(p.getPoint());
- remove_snapsource(); // Don't set both the source and target indicators, as these will overlap
- _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, 1000); // TODO add preference for snap indicator timeout
- }
+ // Display the snap indicator (i.e. the cross)
+ SPCanvasItem * canvasitem = NULL;
+ if (p.getTarget() == SNAPTARGET_NODE) {
+ canvasitem = sp_canvas_item_new(sp_desktop_tempgroup (_desktop),
+ SP_TYPE_CTRL,
+ "anchor", GTK_ANCHOR_CENTER,
+ "size", 10.0,
+ "stroked", TRUE,
+ "stroke_color", 0xf000f0ff,
+ "mode", SP_KNOT_MODE_XOR,
+ "shape", SP_KNOT_SHAPE_DIAMOND,
+ NULL );
+ } else {
+ canvasitem = sp_canvas_item_new(sp_desktop_tempgroup (_desktop),
+ SP_TYPE_CTRL,
+ "anchor", GTK_ANCHOR_CENTER,
+ "size", 10.0,
+ "stroked", TRUE,
+ "stroke_color", 0xf000f0ff,
+ "mode", SP_KNOT_MODE_XOR,
+ "shape", SP_KNOT_SHAPE_CROSS,
+ NULL );
+ }
+
+ const int timeout_val = 1000; // TODO add preference for snap indicator timeout?
+
+ SP_CTRL(canvasitem)->moveto(p.getPoint());
+ remove_snapsource(); // Don't set both the source and target indicators, as these will overlap
+ _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val);
+
+ // Display the tooltip
+ GtkSettings *settings = gtk_widget_get_settings (&(_desktop->canvas->widget));
+ // If we set the timeout too short, then the tooltip might not show at all (most noticeable when a long snap delay is active)
+ g_object_set(settings, "gtk-tooltip-timeout", 200, NULL); // tooltip will be shown after x msec.
+ gtk_widget_set_tooltip_text(&(_desktop->canvas->widget), target_name);
+ // has_tooltip will be true by now because gtk_widget_set_has_tooltip() has been called implicitly
+ update_tooltip();
+ // The snap indicator will be removed automatically because it's a temporary canvas item; the tooltip
+ // however must be removed manually, so we'll create a timer to that end
+ Glib::signal_timeout().connect(sigc::mem_fun(*this, &SnapIndicator::remove_tooltip), timeout_val);
+ }
}
void
@@ -104,6 +152,8 @@ SnapIndicator::remove_snaptarget()
_desktop->remove_temporary_canvasitem(_snaptarget);
_snaptarget = NULL;
}
+
+ remove_tooltip();
}
void
@@ -141,11 +191,46 @@ SnapIndicator::remove_snapsource()
}
}
+// Shows or hides the tooltip
+void SnapIndicator::update_tooltip() const
+{
+ // When using gtk_widget_trigger_tooltip_query, the tooltip will for some reason always popup
+ // in the upper-left corner of the screen (probably at (0,0)). As a workaround we'll create
+ // a motion event instead, which will also trigger the tooltip
+ gint x, y;
+ GdkWindow *window;
+
+ GdkDisplay *display = gdk_display_get_default();
+ window = gdk_display_get_window_at_pointer(display, &x, &y);
+ if (window) {
+ GdkEvent *event = gdk_event_new(GDK_MOTION_NOTIFY);
+ event->motion.window = window;
+ event->motion.x = x;
+ event->motion.y = y;
+ event->motion.is_hint = FALSE;
+
+ gdk_window_get_origin(window, &x, &y);
+ event->motion.x_root = event->motion.x + x;
+ event->motion.y_root = event->motion.y + y;
+
+ gtk_main_do_event(event);
+ }
+}
+
+// Can be called either directly or through a timer
+bool
+SnapIndicator::remove_tooltip() const
+{
+ gtk_widget_set_has_tooltip (&(_desktop->canvas->widget), false);
+ gtk_widget_trigger_tooltip_query(&(_desktop->canvas->widget));
+ return false;
+}
} //namespace Display
} /* namespace Inkscape */
+
/*
Local Variables:
mode:c++
diff --git a/src/display/snap-indicator.h b/src/display/snap-indicator.h
index d2c6dba8e..672d2e78c 100644
--- a/src/display/snap-indicator.h
+++ b/src/display/snap-indicator.h
@@ -28,10 +28,10 @@ public:
void set_new_snaptarget(Inkscape::SnappedPoint const p);
void remove_snaptarget();
-
+
void set_new_snapsource(Geom::Point const p);
void remove_snapsource();
-
+
protected:
TemporaryItem *_snaptarget;
TemporaryItem *_snapsource;
@@ -40,6 +40,8 @@ protected:
private:
SnapIndicator(const SnapIndicator&);
SnapIndicator& operator=(const SnapIndicator&);
+ void update_tooltip() const;
+ bool remove_tooltip() const;
};
} //namespace Display
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index edd64f021..141e10611 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -938,6 +938,7 @@ static gint sp_canvas_key (GtkWidget *widget, GdkEventKey *event);
static gint sp_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event);
static gint sp_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event);
static gint sp_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event);
+static gboolean sp_canvas_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip);
static GtkWidgetClass *canvas_parent_class;
@@ -1050,6 +1051,8 @@ sp_canvas_init (SPCanvas *canvas)
canvas->watchdog_id = 0;
canvas->watchdog_event = NULL;
canvas->context_snap_delay_active = false;
+
+ g_signal_connect(&(canvas->widget), "query-tooltip", G_CALLBACK (sp_canvas_query_tooltip), NULL);
}
/**
@@ -1609,20 +1612,19 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
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 (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 );
-
+ if (canvas->context_snap_delay_active && 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;
- // 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.
@@ -1654,13 +1656,11 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
}
canvas->state = event->state;
- pick_current_item (canvas, (GdkEvent *) event);
-
- status = emit_event (canvas, (GdkEvent *) event);
-
- if (event->is_hint) {
- request_motions(widget->window, event);
- }
+ pick_current_item (canvas, (GdkEvent *) event);
+ status = emit_event (canvas, (GdkEvent *) event);
+ if (event->is_hint) {
+ request_motions(widget->window, event);
+ }
return status;
}
@@ -1670,6 +1670,7 @@ 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<SPCanvas *>(data);
if (!canvas->watchdog_event) {
+ // This might occur when this method is called directly, i.e. not through the timer
return FALSE;
}
@@ -2164,6 +2165,26 @@ sp_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
return FALSE;
}
+
+static gboolean sp_canvas_query_tooltip (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip)
+{
+ // We're not really doing anything special here, so we might just as well remove sp_canvas_query_tooltip
+ // all together (and stop listening to the query_tooltip signal. We might make a custom tooltip however
+ // someday, for example to display icons instead of just plain text. In that case we will need this call
+ // so that's why I'm leaving it here for the time being.
+
+ if (canvas_parent_class->query_tooltip) {
+ return canvas_parent_class->query_tooltip (widget, x, y, keyboard_mode, tooltip);
+ }
+
+ return false;
+}
+
+
/**
* Helper that repaints the areas in the canvas that need it.
*