Commit d155be62 authored by Michael Natterer's avatar Michael Natterer 😴

libgimpwidgets: fix ruler motion event tracking on offscreen overlays

Add a list of "track widgets" to GimpRuler and connect to their
motion-notify-event. Correctly translate the motion event's x/y to the
ruler's coordinate system when updating the marker.
parent e27b5f6d
...@@ -516,9 +516,7 @@ gimp_display_shell_constructed (GObject *object) ...@@ -516,9 +516,7 @@ gimp_display_shell_constructed (GObject *object)
gtk_widget_set_events (GTK_WIDGET (shell->hrule), gtk_widget_set_events (GTK_WIDGET (shell->hrule),
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect_swapped (shell->canvas, "motion-notify-event", gimp_ruler_add_track_widget (GIMP_RULER (shell->hrule), shell->canvas);
G_CALLBACK (GTK_WIDGET_GET_CLASS (shell->hrule)->motion_notify_event),
shell->hrule);
g_signal_connect (shell->hrule, "button-press-event", g_signal_connect (shell->hrule, "button-press-event",
G_CALLBACK (gimp_display_shell_hruler_button_press), G_CALLBACK (gimp_display_shell_hruler_button_press),
shell); shell);
...@@ -530,9 +528,7 @@ gimp_display_shell_constructed (GObject *object) ...@@ -530,9 +528,7 @@ gimp_display_shell_constructed (GObject *object)
gtk_widget_set_events (GTK_WIDGET (shell->vrule), gtk_widget_set_events (GTK_WIDGET (shell->vrule),
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect_swapped (shell->canvas, "motion-notify-event", gimp_ruler_add_track_widget (GIMP_RULER (shell->vrule), shell->canvas);
G_CALLBACK (GTK_WIDGET_GET_CLASS (shell->vrule)->motion_notify_event),
shell->vrule);
g_signal_connect (shell->vrule, "button-press-event", g_signal_connect (shell->vrule, "button-press-event",
G_CALLBACK (gimp_display_shell_vruler_button_press), G_CALLBACK (gimp_display_shell_vruler_button_press),
shell); shell);
......
...@@ -73,8 +73,13 @@ typedef struct ...@@ -73,8 +73,13 @@ typedef struct
gint xsrc; gint xsrc;
gint ysrc; gint ysrc;
GList *track_widgets;
} GimpRulerPrivate; } GimpRulerPrivate;
#define GIMP_RULER_GET_PRIVATE(ruler) \
G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_RULER, GimpRulerPrivate)
static const struct static const struct
{ {
...@@ -87,6 +92,7 @@ static const struct ...@@ -87,6 +92,7 @@ static const struct
}; };
static void gimp_ruler_dispose (GObject *object);
static void gimp_ruler_set_property (GObject *object, static void gimp_ruler_set_property (GObject *object,
guint prop_id, guint prop_id,
const GValue *value, const GValue *value,
...@@ -119,8 +125,7 @@ static PangoLayout * gimp_ruler_get_layout (GtkWidget *widget, ...@@ -119,8 +125,7 @@ static PangoLayout * gimp_ruler_get_layout (GtkWidget *widget,
G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET) G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET)
#define GIMP_RULER_GET_PRIVATE(ruler) \ #define parent_class gimp_ruler_parent_class
G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_RULER, GimpRulerPrivate)
static void static void
...@@ -129,6 +134,7 @@ gimp_ruler_class_init (GimpRulerClass *klass) ...@@ -129,6 +134,7 @@ gimp_ruler_class_init (GimpRulerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = gimp_ruler_dispose;
object_class->set_property = gimp_ruler_set_property; object_class->set_property = gimp_ruler_set_property;
object_class->get_property = gimp_ruler_get_property; object_class->get_property = gimp_ruler_get_property;
...@@ -224,6 +230,18 @@ gimp_ruler_init (GimpRuler *ruler) ...@@ -224,6 +230,18 @@ gimp_ruler_init (GimpRuler *ruler)
priv->font_scale = DEFAULT_RULER_FONT_SCALE; priv->font_scale = DEFAULT_RULER_FONT_SCALE;
} }
static void
gimp_ruler_dispose (GObject *object)
{
GimpRuler *ruler = GIMP_RULER (object);
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
while (priv->track_widgets)
gimp_ruler_remove_track_widget (ruler, priv->track_widgets->data);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void static void
gimp_ruler_set_property (GObject *object, gimp_ruler_set_property (GObject *object,
guint prop_id, guint prop_id,
...@@ -333,8 +351,197 @@ gimp_ruler_new (GtkOrientation orientation) ...@@ -333,8 +351,197 @@ gimp_ruler_new (GtkOrientation orientation)
NULL); NULL);
} }
static void
gimp_ruler_update_position (GimpRuler *ruler,
gdouble x,
gdouble y)
{
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
GtkAllocation allocation;
gdouble lower;
gdouble upper;
gtk_widget_get_allocation (GTK_WIDGET (ruler), &allocation);
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
gimp_ruler_set_position (ruler,
lower +
(upper - lower) * x / allocation.width);
}
else
{
gimp_ruler_set_position (ruler,
lower +
(upper - lower) * y / allocation.height);
}
}
/* Returns TRUE if a translation should be done */
static gboolean
gtk_widget_get_translation_to_window (GtkWidget *widget,
GdkWindow *window,
int *x,
int *y)
{
GdkWindow *w, *widget_window;
if (! gtk_widget_get_has_window (widget))
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
*x = -allocation.x;
*y = -allocation.y;
}
else
{
*x = 0;
*y = 0;
}
widget_window = gtk_widget_get_window (widget);
for (w = window;
w && w != widget_window;
w = gdk_window_get_effective_parent (w))
{
gdouble px, py;
gdk_window_coords_to_parent (w, *x, *y, &px, &py);
*x += px;
*y += py;
}
if (w == NULL)
{
*x = 0;
*y = 0;
return FALSE;
}
return TRUE;
}
static void
gimp_ruler_event_to_widget_coords (GtkWidget *widget,
GdkWindow *window,
gdouble event_x,
gdouble event_y,
gint *widget_x,
gint *widget_y)
{
gint tx, ty;
if (gtk_widget_get_translation_to_window (widget, window, &tx, &ty))
{
event_x += tx;
event_y += ty;
}
*widget_x = event_x;
*widget_y = event_y;
}
static gboolean
gimp_ruler_track_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *mevent,
GimpRuler *ruler)
{
gint widget_x;
gint widget_y;
gint ruler_x;
gint ruler_y;
widget = gtk_get_event_widget ((GdkEvent *) mevent);
gimp_ruler_event_to_widget_coords (widget, mevent->window,
mevent->x, mevent->y,
&widget_x, &widget_y);
gtk_widget_translate_coordinates (widget, GTK_WIDGET (ruler),
widget_x, widget_y,
&ruler_x, &ruler_y);
gimp_ruler_update_position (ruler, ruler_x, ruler_y);
return FALSE;
}
/** /**
* gimp_ruler_set_position: * gimp_ruler_add_track_widget:
* @ruler: a #GimpRuler
* @widget: the track widget to add
*
* Adds a "track widget" to the ruler. The ruler will connect to
* GtkWidget:motion-notify-event: on the track widget and update its
* position marker accordingly. The marker is correctly updated also
* for the track widget's children, regardless of whether they are
* ordinary children of off-screen children.
*
* Since: GIMP 2.8
*/
void
gimp_ruler_add_track_widget (GimpRuler *ruler,
GtkWidget *widget)
{
GimpRulerPrivate *priv;
g_return_if_fail (GIMP_IS_RULER (ruler));
g_return_if_fail (GTK_IS_WIDGET (ruler));
priv = GIMP_RULER_GET_PRIVATE (ruler);
g_return_if_fail (g_list_find (priv->track_widgets, widget) == NULL);
priv->track_widgets = g_list_prepend (priv->track_widgets, widget);
g_signal_connect (widget, "motion-notify-event",
G_CALLBACK (gimp_ruler_track_widget_motion_notify),
ruler);
g_signal_connect_swapped (widget, "destroy",
G_CALLBACK (gimp_ruler_remove_track_widget),
ruler);
}
/**
* gimp_ruler_remove_track_widget:
* @ruler: a #GimpRuler
* @widget: the track widget to remove
*
* Removes a previously added track widget from the ruler. See
* gimp_ruler_add_track_widget().
*
* Since: GIMP 2.8
*/
void
gimp_ruler_remove_track_widget (GimpRuler *ruler,
GtkWidget *widget)
{
GimpRulerPrivate *priv;
g_return_if_fail (GIMP_IS_RULER (ruler));
g_return_if_fail (GTK_IS_WIDGET (ruler));
priv = GIMP_RULER_GET_PRIVATE (ruler);
g_return_if_fail (g_list_find (priv->track_widgets, widget) != NULL);
priv->track_widgets = g_list_remove (priv->track_widgets, widget);
g_signal_handlers_disconnect_by_func (widget,
gimp_ruler_track_widget_motion_notify,
ruler);
g_signal_handlers_disconnect_by_func (widget,
gimp_ruler_remove_track_widget,
ruler);
}
/**
* gimp_ruler_set_unit:
* @ruler: a #GimpRuler * @ruler: a #GimpRuler
* @unit: the #GimpUnit to set the ruler to * @unit: the #GimpUnit to set the ruler to
* *
...@@ -627,31 +834,11 @@ static gboolean ...@@ -627,31 +834,11 @@ static gboolean
gimp_ruler_motion_notify (GtkWidget *widget, gimp_ruler_motion_notify (GtkWidget *widget,
GdkEventMotion *event) GdkEventMotion *event)
{ {
GimpRuler *ruler = GIMP_RULER (widget); GimpRuler *ruler = GIMP_RULER (widget);
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
GtkAllocation allocation;
gdouble lower;
gdouble upper;
gdk_event_request_motions (event); gdk_event_request_motions (event);
gtk_widget_get_allocation (widget, &allocation); gimp_ruler_update_position (ruler, event->x, event->y);
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
gimp_ruler_set_position (ruler,
lower +
(upper - lower) * event->x /
allocation.width);
}
else
{
gimp_ruler_set_position (ruler,
lower +
(upper - lower) * event->y /
allocation.height);
}
return FALSE; return FALSE;
} }
...@@ -1039,7 +1226,7 @@ gimp_ruler_make_pixmap (GimpRuler *ruler) ...@@ -1039,7 +1226,7 @@ gimp_ruler_make_pixmap (GimpRuler *ruler)
cr = gdk_cairo_create (gtk_widget_get_window (widget)); cr = gdk_cairo_create (gtk_widget_get_window (widget));
surface = cairo_get_target (cr); surface = cairo_get_target (cr);
priv->backing_store = priv->backing_store =
cairo_surface_create_similar (surface, cairo_surface_create_similar (surface,
CAIRO_CONTENT_COLOR, CAIRO_CONTENT_COLOR,
allocation.width, allocation.width,
......
...@@ -48,23 +48,29 @@ struct _GimpRulerClass ...@@ -48,23 +48,29 @@ struct _GimpRulerClass
}; };
GType gimp_ruler_get_type (void) G_GNUC_CONST; GType gimp_ruler_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_ruler_new (GtkOrientation orientation); GtkWidget * gimp_ruler_new (GtkOrientation orientation);
void gimp_ruler_set_unit (GimpRuler *ruler,
GimpUnit unit); void gimp_ruler_add_track_widget (GimpRuler *ruler,
GimpUnit gimp_ruler_get_unit (GimpRuler *ruler); GtkWidget *widget);
void gimp_ruler_set_position (GimpRuler *ruler, void gimp_ruler_remove_track_widget (GimpRuler *ruler,
gdouble position); GtkWidget *widget);
gdouble gimp_ruler_get_position (GimpRuler *ruler);
void gimp_ruler_set_range (GimpRuler *ruler, void gimp_ruler_set_unit (GimpRuler *ruler,
gdouble lower, GimpUnit unit);
gdouble upper, GimpUnit gimp_ruler_get_unit (GimpRuler *ruler);
gdouble max_size); void gimp_ruler_set_position (GimpRuler *ruler,
void gimp_ruler_get_range (GimpRuler *ruler, gdouble position);
gdouble *lower, gdouble gimp_ruler_get_position (GimpRuler *ruler);
gdouble *upper, void gimp_ruler_set_range (GimpRuler *ruler,
gdouble *max_size); gdouble lower,
gdouble upper,
gdouble max_size);
void gimp_ruler_get_range (GimpRuler *ruler,
gdouble *lower,
gdouble *upper,
gdouble *max_size);
G_END_DECLS G_END_DECLS
......
...@@ -303,11 +303,13 @@ EXPORTS ...@@ -303,11 +303,13 @@ EXPORTS
gimp_radio_group_new2 gimp_radio_group_new2
gimp_radio_group_set_active gimp_radio_group_set_active
gimp_random_seed_new gimp_random_seed_new
gimp_ruler_add_track_widget
gimp_ruler_get_position gimp_ruler_get_position
gimp_ruler_get_range gimp_ruler_get_range
gimp_ruler_get_type gimp_ruler_get_type
gimp_ruler_get_unit gimp_ruler_get_unit
gimp_ruler_new gimp_ruler_new
gimp_ruler_remove_track_widget
gimp_ruler_set_position gimp_ruler_set_position
gimp_ruler_set_range gimp_ruler_set_range
gimp_ruler_set_unit gimp_ruler_set_unit
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment