[gimp] app: Implement exclusiveness of zoom and rotate gestures
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: Implement exclusiveness of zoom and rotate gestures
- Date: Wed, 6 Apr 2022 19:34:12 +0000 (UTC)
commit edcbf18fe682cf78f8589b4b66208886deb8b0ff
Author: Povilas Kanapickas <povilas radix lt>
Date: Thu Mar 17 14:55:04 2022 +0200
app: Implement exclusiveness of zoom and rotate gestures
Performing zoom and rotation at the same time is inconvenient because
most of the time the user will want either zoom or rotation. This can be
solved by recognizing a "significant enough" zoom or rotation change
initiated by the gesture recognizer and then ignoring the other gesture.
app/display/gimpdisplayshell-tool-events.c | 90 +++++++++++++++++++++++++++---
app/display/gimpdisplayshell-tool-events.h | 6 ++
app/display/gimpdisplayshell.c | 9 ++-
app/display/gimpdisplayshell.h | 2 +
4 files changed, 97 insertions(+), 10 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-tool-events.c b/app/display/gimpdisplayshell-tool-events.c
index 16df65ff58..35bc8b6424 100644
--- a/app/display/gimpdisplayshell-tool-events.c
+++ b/app/display/gimpdisplayshell-tool-events.c
@@ -1255,6 +1255,35 @@ gimp_display_shell_canvas_grab_notify (GtkWidget *canvas,
}
}
+/* The ratio of the following defines what finger movement we interpret as
+ * a rotation versus zoom gesture. If finger movement is partially a zoom
+ * and partially a rotation, the detected gesture will be whichever gesture
+ * we detect first
+ *
+ * Let's define "finger movement angle" as the angle between the direction of
+ * finger movement and the line between fingers. If this angle is zero then
+ * the gesture is completely a zoom gesture. If this angle is 90 degrees
+ * then the gesture is completely a rotation gesture.
+ *
+ * The boundary finger movement angle (below which the gesture is zoom gesture
+ * and above which the gesture is rotate gesture) will be defined as follows:
+ *
+ * boundary = arctan(deg2rad(ROTATE_GESTURE_ACTIVATION_DEG_DIFF) /
+ * (ZOOM_GESTURE_ACTIVATION_SCALE_DIFF / 2))
+ *
+ * Note that ZOOM_GESTURE_ACTIVATION_SCALE_DIFF needs to be divided by 2
+ * because both fingers are moving so the distance between them is increasing
+ * twice as fast.
+ *
+ * We probably want boundary angle to be around 60 degrees to prevent
+ * accidentally starting rotations.
+ *
+ * With ZOOM_GESTURE_ACTIVATION_SCALE_DIFF==0.02 and
+ * ROTATE_GESTURE_ACTIVATION_DEG_DIFF==1 boundary is 60.2 degrees.
+ */
+#define ZOOM_GESTURE_ACTIVATION_SCALE_DIFF 0.02
+#define ROTATE_GESTURE_ACTIVATION_DEG_DIFF 1
+
void
gimp_display_shell_zoom_gesture_begin (GtkGestureZoom *gesture,
GdkEventSequence *sequence,
@@ -1268,8 +1297,23 @@ gimp_display_shell_zoom_gesture_update (GtkGestureZoom *gesture,
GdkEventSequence *sequence,
GimpDisplayShell *shell)
{
- gdouble current_scale = gtk_gesture_zoom_get_scale_delta (gesture);
- gdouble delta = (current_scale - shell->last_zoom_scale) / shell->last_zoom_scale;
+ gdouble current_scale;
+ gdouble delta;
+
+ if (shell->rotate_gesture_active)
+ return;
+
+ /* we only activate zoom gesture handling if rotate gesture was inactive and
+ * the zoom difference is significant enough */
+ current_scale = gtk_gesture_zoom_get_scale_delta (gesture);
+ if (!shell->zoom_gesture_active &&
+ current_scale > (1 - ZOOM_GESTURE_ACTIVATION_SCALE_DIFF) &&
+ current_scale < (1 + ZOOM_GESTURE_ACTIVATION_SCALE_DIFF))
+ return;
+
+ shell->zoom_gesture_active = TRUE;
+
+ delta = (current_scale - shell->last_zoom_scale) / shell->last_zoom_scale;
shell->last_zoom_scale = current_scale;
gimp_display_shell_scale (shell,
@@ -1278,6 +1322,14 @@ gimp_display_shell_zoom_gesture_update (GtkGestureZoom *gesture,
GIMP_ZOOM_FOCUS_POINTER);
}
+void
+gimp_display_shell_zoom_gesture_end (GtkGestureZoom *gesture,
+ GdkEventSequence *sequence,
+ GimpDisplayShell *shell)
+{
+ shell->zoom_gesture_active = FALSE;
+}
+
void
gimp_display_shell_rotate_gesture_begin (GtkGestureRotate *gesture,
GdkEventSequence *sequence,
@@ -1295,19 +1347,39 @@ gimp_display_shell_rotate_gesture_update (GtkGestureRotate *gesture,
GdkEventSequence *sequence,
GimpDisplayShell *shell)
{
- gdouble angle;
- gboolean constrain;
+ gdouble angle;
+ gdouble angle_delta_deg;
+ gboolean constrain;
+
+ /* we only activate rotate gesture handling if zoom gesture was inactive and
+ * the rotation is significant enough */
+ if (shell->zoom_gesture_active)
+ return;
+
+ angle_delta_deg = 180.0 * gtk_gesture_rotate_get_angle_delta (gesture) / G_PI;
+ if (!shell->rotate_gesture_active &&
+ angle_delta_deg > -ROTATE_GESTURE_ACTIVATION_DEG_DIFF &&
+ angle_delta_deg < ROTATE_GESTURE_ACTIVATION_DEG_DIFF)
+ return;
+
+ shell->rotate_gesture_active = TRUE;
+
+ angle = shell->initial_gesture_rotate_angle + angle_delta_deg;
gimp_display_shell_rotate_gesture_maybe_get_state (gesture, sequence,
&shell->last_gesture_rotate_state);
- angle = shell->initial_gesture_rotate_angle +
- 180.0 * gtk_gesture_rotate_get_angle_delta (gesture) / G_PI;
-
constrain = (shell->last_gesture_rotate_state & GDK_CONTROL_MASK) ? TRUE : FALSE;
- gimp_display_shell_rotate_to (shell,
- constrain ? RINT (angle / 15.0) * 15.0 : angle);
+ gimp_display_shell_rotate_to (shell, constrain ? RINT (angle / 15.0) * 15.0 : angle);
+}
+
+void
+gimp_display_shell_rotate_gesture_end (GtkGestureRotate *gesture,
+ GdkEventSequence *sequence,
+ GimpDisplayShell *shell)
+{
+ shell->rotate_gesture_active = FALSE;
}
void
diff --git a/app/display/gimpdisplayshell-tool-events.h b/app/display/gimpdisplayshell-tool-events.h
index a491999d04..0e3cf93e02 100644
--- a/app/display/gimpdisplayshell-tool-events.h
+++ b/app/display/gimpdisplayshell-tool-events.h
@@ -36,6 +36,9 @@ void gimp_display_shell_zoom_gesture_begin (GtkGestureZoom *gesture
void gimp_display_shell_zoom_gesture_update (GtkGestureZoom *gesture,
GdkEventSequence *sequence,
GimpDisplayShell *shell);
+void gimp_display_shell_zoom_gesture_end (GtkGestureZoom *gesture,
+ GdkEventSequence *sequence,
+ GimpDisplayShell *shell);
void gimp_display_shell_rotate_gesture_begin (GtkGestureRotate *gesture,
GdkEventSequence *sequence,
@@ -43,6 +46,9 @@ void gimp_display_shell_rotate_gesture_begin (GtkGestureRotate *gesture
void gimp_display_shell_rotate_gesture_update (GtkGestureRotate *gesture,
GdkEventSequence *sequence,
GimpDisplayShell *shell);
+void gimp_display_shell_rotate_gesture_end (GtkGestureRotate *gesture,
+ GdkEventSequence *sequence,
+ GimpDisplayShell *shell);
void gimp_display_shell_buffer_stroke (GimpMotionBuffer *buffer,
const GimpCoords *coords,
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 8ca3d1efa4..066d935c25 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -515,10 +515,12 @@ gimp_display_shell_constructed (GObject *object)
shell->zoom_gesture = gtk_gesture_zoom_new (GTK_WIDGET (shell->canvas));
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (shell->zoom_gesture),
GTK_PHASE_CAPTURE);
+ shell->zoom_gesture_active = FALSE;
shell->rotate_gesture = gtk_gesture_rotate_new (GTK_WIDGET (shell->canvas));
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (shell->rotate_gesture),
GTK_PHASE_CAPTURE);
+ shell->rotate_gesture_active = FALSE;
/* the horizontal ruler */
shell->hrule = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
@@ -612,13 +614,18 @@ gimp_display_shell_constructed (GObject *object)
g_signal_connect (shell->zoom_gesture, "update",
G_CALLBACK (gimp_display_shell_zoom_gesture_update),
shell);
+ g_signal_connect (shell->zoom_gesture, "end",
+ G_CALLBACK (gimp_display_shell_zoom_gesture_end),
+ shell);
g_signal_connect (shell->rotate_gesture, "begin",
G_CALLBACK (gimp_display_shell_rotate_gesture_begin),
shell);
g_signal_connect (shell->rotate_gesture, "update",
G_CALLBACK (gimp_display_shell_rotate_gesture_update),
shell);
-
+ g_signal_connect (shell->rotate_gesture, "end",
+ G_CALLBACK (gimp_display_shell_rotate_gesture_end),
+ shell);
/* the zoom button */
shell->zoom_button = g_object_new (GTK_TYPE_CHECK_BUTTON,
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index 7a4a0a41f3..9b81c639e4 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -203,10 +203,12 @@ struct _GimpDisplayShell
/* the state of gimp_display_shell_zoom_gesture_*() */
gdouble last_zoom_scale;
+ gboolean zoom_gesture_active;
/* the state of gimp_display_shell_rotate_gesture_*() */
guint last_gesture_rotate_state;
gdouble initial_gesture_rotate_angle;
+ gboolean rotate_gesture_active;
/* Two states are possible when the shell is grabbed: it can be
* grabbed with space (or space+button1 which is the same state),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]