mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
e27b5f6da2
commit
d155be622d
|
@ -516,9 +516,7 @@ gimp_display_shell_constructed (GObject *object)
|
|||
gtk_widget_set_events (GTK_WIDGET (shell->hrule),
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
|
||||
g_signal_connect_swapped (shell->canvas, "motion-notify-event",
|
||||
G_CALLBACK (GTK_WIDGET_GET_CLASS (shell->hrule)->motion_notify_event),
|
||||
shell->hrule);
|
||||
gimp_ruler_add_track_widget (GIMP_RULER (shell->hrule), shell->canvas);
|
||||
g_signal_connect (shell->hrule, "button-press-event",
|
||||
G_CALLBACK (gimp_display_shell_hruler_button_press),
|
||||
shell);
|
||||
|
@ -530,9 +528,7 @@ gimp_display_shell_constructed (GObject *object)
|
|||
gtk_widget_set_events (GTK_WIDGET (shell->vrule),
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
|
||||
g_signal_connect_swapped (shell->canvas, "motion-notify-event",
|
||||
G_CALLBACK (GTK_WIDGET_GET_CLASS (shell->vrule)->motion_notify_event),
|
||||
shell->vrule);
|
||||
gimp_ruler_add_track_widget (GIMP_RULER (shell->vrule), shell->canvas);
|
||||
g_signal_connect (shell->vrule, "button-press-event",
|
||||
G_CALLBACK (gimp_display_shell_vruler_button_press),
|
||||
shell);
|
||||
|
|
|
@ -73,8 +73,13 @@ typedef struct
|
|||
|
||||
gint xsrc;
|
||||
gint ysrc;
|
||||
|
||||
GList *track_widgets;
|
||||
} GimpRulerPrivate;
|
||||
|
||||
#define GIMP_RULER_GET_PRIVATE(ruler) \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_RULER, GimpRulerPrivate)
|
||||
|
||||
|
||||
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,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
|
@ -119,8 +125,7 @@ static PangoLayout * gimp_ruler_get_layout (GtkWidget *widget,
|
|||
|
||||
G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET)
|
||||
|
||||
#define GIMP_RULER_GET_PRIVATE(ruler) \
|
||||
G_TYPE_INSTANCE_GET_PRIVATE (ruler, GIMP_TYPE_RULER, GimpRulerPrivate)
|
||||
#define parent_class gimp_ruler_parent_class
|
||||
|
||||
|
||||
static void
|
||||
|
@ -129,6 +134,7 @@ gimp_ruler_class_init (GimpRulerClass *klass)
|
|||
GObjectClass *object_class = G_OBJECT_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->get_property = gimp_ruler_get_property;
|
||||
|
||||
|
@ -224,6 +230,18 @@ gimp_ruler_init (GimpRuler *ruler)
|
|||
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
|
||||
gimp_ruler_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
|
@ -333,8 +351,197 @@ gimp_ruler_new (GtkOrientation orientation)
|
|||
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
|
||||
* @unit: the #GimpUnit to set the ruler to
|
||||
*
|
||||
|
@ -627,31 +834,11 @@ static gboolean
|
|||
gimp_ruler_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
GimpRuler *ruler = GIMP_RULER (widget);
|
||||
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
|
||||
GtkAllocation allocation;
|
||||
gdouble lower;
|
||||
gdouble upper;
|
||||
GimpRuler *ruler = GIMP_RULER (widget);
|
||||
|
||||
gdk_event_request_motions (event);
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
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);
|
||||
}
|
||||
gimp_ruler_update_position (ruler, event->x, event->y);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1039,7 +1226,7 @@ gimp_ruler_make_pixmap (GimpRuler *ruler)
|
|||
cr = gdk_cairo_create (gtk_widget_get_window (widget));
|
||||
surface = cairo_get_target (cr);
|
||||
|
||||
priv->backing_store =
|
||||
priv->backing_store =
|
||||
cairo_surface_create_similar (surface,
|
||||
CAIRO_CONTENT_COLOR,
|
||||
allocation.width,
|
||||
|
|
|
@ -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);
|
||||
void gimp_ruler_set_unit (GimpRuler *ruler,
|
||||
GimpUnit unit);
|
||||
GimpUnit gimp_ruler_get_unit (GimpRuler *ruler);
|
||||
void gimp_ruler_set_position (GimpRuler *ruler,
|
||||
gdouble position);
|
||||
gdouble gimp_ruler_get_position (GimpRuler *ruler);
|
||||
void gimp_ruler_set_range (GimpRuler *ruler,
|
||||
gdouble lower,
|
||||
gdouble upper,
|
||||
gdouble max_size);
|
||||
void gimp_ruler_get_range (GimpRuler *ruler,
|
||||
gdouble *lower,
|
||||
gdouble *upper,
|
||||
gdouble *max_size);
|
||||
GtkWidget * gimp_ruler_new (GtkOrientation orientation);
|
||||
|
||||
void gimp_ruler_add_track_widget (GimpRuler *ruler,
|
||||
GtkWidget *widget);
|
||||
void gimp_ruler_remove_track_widget (GimpRuler *ruler,
|
||||
GtkWidget *widget);
|
||||
|
||||
void gimp_ruler_set_unit (GimpRuler *ruler,
|
||||
GimpUnit unit);
|
||||
GimpUnit gimp_ruler_get_unit (GimpRuler *ruler);
|
||||
void gimp_ruler_set_position (GimpRuler *ruler,
|
||||
gdouble position);
|
||||
gdouble gimp_ruler_get_position (GimpRuler *ruler);
|
||||
void gimp_ruler_set_range (GimpRuler *ruler,
|
||||
gdouble lower,
|
||||
gdouble upper,
|
||||
gdouble max_size);
|
||||
void gimp_ruler_get_range (GimpRuler *ruler,
|
||||
gdouble *lower,
|
||||
gdouble *upper,
|
||||
gdouble *max_size);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -303,11 +303,13 @@ EXPORTS
|
|||
gimp_radio_group_new2
|
||||
gimp_radio_group_set_active
|
||||
gimp_random_seed_new
|
||||
gimp_ruler_add_track_widget
|
||||
gimp_ruler_get_position
|
||||
gimp_ruler_get_range
|
||||
gimp_ruler_get_type
|
||||
gimp_ruler_get_unit
|
||||
gimp_ruler_new
|
||||
gimp_ruler_remove_track_widget
|
||||
gimp_ruler_set_position
|
||||
gimp_ruler_set_range
|
||||
gimp_ruler_set_unit
|
||||
|
|
Loading…
Reference in New Issue