mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
e8cf57f157
commit
edcbf18fe6
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue