diff --git a/app/actions/gradient-editor-commands.c b/app/actions/gradient-editor-commands.c index 01864061a86d9bd028bdc3c23b879038e5f2c625..cb30c8cda857fae4aa3335ff96b590778a795b7c 100644 --- a/app/actions/gradient-editor-commands.c +++ b/app/actions/gradient-editor-commands.c @@ -660,7 +660,7 @@ gradient_editor_zoom_cmd_callback (GimpAction *action, GimpGradientEditor *editor = GIMP_GRADIENT_EDITOR (data); GimpZoomType zoom_type = (GimpZoomType) g_variant_get_int32 (value); - gimp_gradient_editor_zoom (editor, zoom_type, 1.0); + gimp_gradient_editor_zoom (editor, zoom_type, 1.0, 0.5); } diff --git a/app/widgets/gimpgradienteditor.c b/app/widgets/gimpgradienteditor.c index d4eaeeaecb15078ef6c41a536988776b3e65c58a..d40b67a91c4c58ee5c698163fdc230b5671aa095 100644 --- a/app/widgets/gimpgradienteditor.c +++ b/app/widgets/gimpgradienteditor.c @@ -96,7 +96,8 @@ GDK_BUTTON_PRESS_MASK | \ GDK_BUTTON_RELEASE_MASK | \ GDK_SCROLL_MASK | \ - GDK_SMOOTH_SCROLL_MASK) + GDK_SMOOTH_SCROLL_MASK | \ + GDK_TOUCHPAD_GESTURE_MASK) #define GRAD_CONTROL_EVENT_MASK (GDK_EXPOSURE_MASK | \ GDK_LEAVE_NOTIFY_MASK | \ @@ -178,6 +179,16 @@ static void view_pick_color (GimpGradientEditor *editor, GimpColorPickState pick_state, gint x); +static void view_zoom_gesture_begin (GtkGestureZoom *gesture, + GdkEventSequence *sequence, + GimpGradientEditor *editor); + +static void view_zoom_gesture_update (GtkGestureZoom *gesture, + GdkEventSequence *sequence, + GimpGradientEditor *editor); + +static gdouble view_get_normalized_last_x_pos (GimpGradientEditor *editor); + /* Gradient control functions */ static gboolean control_events (GtkWidget *widget, @@ -217,6 +228,8 @@ static double control_move (GimpGradientEditor *editor, GimpGradientSegment *range_r, gdouble delta); +static gdouble control_get_normalized_last_x_pos (GimpGradientEditor *editor); + /* Control update/redraw functions */ static void control_update (GimpGradientEditor *editor, @@ -340,6 +353,18 @@ gimp_gradient_editor_init (GimpGradientEditor *editor) gradient_editor_drop_color, editor); + editor->zoom_gesture = gtk_gesture_zoom_new (GTK_WIDGET (data_editor->view)); + gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (editor->zoom_gesture), + GTK_PHASE_CAPTURE); + + + g_signal_connect (editor->zoom_gesture, "begin", + G_CALLBACK (view_zoom_gesture_begin), + editor); + g_signal_connect (editor->zoom_gesture, "update", + G_CALLBACK (view_zoom_gesture_update), + editor); + /* Gradient control */ editor->control = gtk_drawing_area_new (); gtk_widget_set_size_request (editor->control, -1, GRAD_CONTROL_HEIGHT); @@ -450,6 +475,8 @@ gimp_gradient_editor_dispose (GObject *object) gtk_dialog_response (GTK_DIALOG (editor->color_dialog), GTK_RESPONSE_CANCEL); + g_clear_object (&editor->zoom_gesture); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -651,7 +678,8 @@ gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor) void gimp_gradient_editor_zoom (GimpGradientEditor *editor, GimpZoomType zoom_type, - gdouble delta) + gdouble delta, + gdouble zoom_focus_x) { GtkAdjustment *adjustment; gdouble old_value; @@ -672,7 +700,7 @@ gimp_gradient_editor_zoom (GimpGradientEditor *editor, delta = ABS (delta); } - else + else if (zoom_type != GIMP_ZOOM_PINCH) { delta = 1.0; } @@ -690,18 +718,18 @@ gimp_gradient_editor_zoom (GimpGradientEditor *editor, editor->zoom_factor += delta; page_size = 1.0 / editor->zoom_factor; - value = old_value + (old_page_size - page_size) / 2.0; + value = old_value + (old_page_size - page_size) * zoom_focus_x; break; case GIMP_ZOOM_OUT_MORE: case GIMP_ZOOM_OUT: - if (editor->zoom_factor <= 1) - return; - editor->zoom_factor -= delta; + if (editor->zoom_factor < 1) + editor->zoom_factor = 1; + page_size = 1.0 / editor->zoom_factor; - value = old_value - (page_size - old_page_size) / 2.0; + value = old_value - (page_size - old_page_size) * zoom_focus_x; if (value < 0.0) value = 0.0; @@ -717,6 +745,26 @@ gimp_gradient_editor_zoom (GimpGradientEditor *editor, page_size = 1.0; break; + case GIMP_ZOOM_PINCH: + if (delta > 0.0) + editor->zoom_factor = editor->zoom_factor * (1.0 + delta); + else if (delta < 0.0) + editor->zoom_factor = editor->zoom_factor / (1.0 + -delta); + else + return; + + if (editor->zoom_factor < 1) + editor->zoom_factor = 1; + + page_size = 1.0 / editor->zoom_factor; + value = old_value + (old_page_size - page_size) * zoom_focus_x; + + if (value < 0.0) + value = 0.0; + else if ((value + page_size) > 1.0) + value = 1.0 - page_size; + break; + case GIMP_ZOOM_SMOOTH: /* can't happen, see above switch() */ break; } @@ -879,7 +927,7 @@ gradient_editor_scrollbar_update (GtkAdjustment *adjustment, gchar *str1; gchar *str2; - str1 = g_strdup_printf (_("Zoom factor: %d:1"), + str1 = g_strdup_printf (_("Zoom factor: %f:1"), editor->zoom_factor); str2 = g_strdup_printf (_("Displaying [%0.4f, %0.4f]"), @@ -1103,6 +1151,7 @@ view_events (GtkWidget *widget, { case GDK_LEAVE_NOTIFY: gradient_editor_set_hint (editor, NULL, NULL, NULL, NULL); + editor->view_last_x = -1; break; case GDK_MOTION_NOTIFY: @@ -1166,16 +1215,19 @@ view_events (GtkWidget *widget, switch (sevent->direction) { case GDK_SCROLL_UP: - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_IN, 1.0); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_IN, 1.0, + view_get_normalized_last_x_pos (editor)); break; case GDK_SCROLL_DOWN: - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_OUT, 1.0); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_OUT, 1.0, + view_get_normalized_last_x_pos (editor)); break; case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas (event, NULL, &delta); - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_SMOOTH, delta); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_SMOOTH, delta, + view_get_normalized_last_x_pos (editor)); break; default: @@ -1306,6 +1358,45 @@ view_pick_color (GimpGradientEditor *editor, g_free (str3); } +static void +view_zoom_gesture_begin (GtkGestureZoom *gesture, + GdkEventSequence *sequence, + GimpGradientEditor *editor) +{ + editor->last_zoom_scale = gtk_gesture_zoom_get_scale_delta (gesture); +} + +static void +view_zoom_gesture_update (GtkGestureZoom *gesture, + GdkEventSequence *sequence, + GimpGradientEditor *editor) +{ + gdouble current_scale = gtk_gesture_zoom_get_scale_delta (gesture); + gdouble delta = (current_scale - editor->last_zoom_scale) / editor->last_zoom_scale; + editor->last_zoom_scale = current_scale; + + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_PINCH, delta, + view_get_normalized_last_x_pos (editor)); +} + +static gdouble +view_get_normalized_last_x_pos (GimpGradientEditor *editor) +{ + GtkAllocation allocation; + gdouble normalized; + if (editor->view_last_x < 0) + return 0.5; + + gtk_widget_get_allocation (GIMP_DATA_EDITOR (editor)->view, &allocation); + normalized = (double) editor->view_last_x / (allocation.width - 1); + + if (normalized < 0) + return 0; + if (normalized > 1.0) + return 1; + return normalized; +} + /***** Gradient control functions *****/ static gboolean @@ -1325,6 +1416,7 @@ control_events (GtkWidget *widget, { case GDK_LEAVE_NOTIFY: gradient_editor_set_hint (editor, NULL, NULL, NULL, NULL); + editor->control_last_x = -1; break; case GDK_BUTTON_PRESS: @@ -1362,16 +1454,19 @@ control_events (GtkWidget *widget, switch (sevent->direction) { case GDK_SCROLL_UP: - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_IN, 1.0); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_IN, 1.0, + control_get_normalized_last_x_pos (editor)); break; case GDK_SCROLL_DOWN: - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_OUT, 1.0); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_OUT, 1.0, + control_get_normalized_last_x_pos (editor)); break; case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas (event, NULL, &delta); - gimp_gradient_editor_zoom (editor, GIMP_ZOOM_SMOOTH, delta); + gimp_gradient_editor_zoom (editor, GIMP_ZOOM_SMOOTH, delta, + control_get_normalized_last_x_pos (editor)); break; default: @@ -1959,6 +2054,26 @@ control_move (GimpGradientEditor *editor, /*****/ +static gdouble +control_get_normalized_last_x_pos (GimpGradientEditor *editor) +{ + GtkAllocation allocation; + gdouble normalized; + if (editor->control_last_x < 0) + return 0.5; + + gtk_widget_get_allocation (editor->control, &allocation); + normalized = (double) editor->control_last_x / (allocation.width - 1); + + if (normalized < 0) + return 0; + if (normalized > 1.0) + return 1; + return normalized; +} + +/*****/ + static void control_update (GimpGradientEditor *editor, GimpGradient *gradient, diff --git a/app/widgets/gimpgradienteditor.h b/app/widgets/gimpgradienteditor.h index 8ecc5b2e1a8d984391489e1c46d5f40e8500e38c..98dfff27f2e89a4e2c331274f3183f5a31fdd0b0 100644 --- a/app/widgets/gimpgradienteditor.h +++ b/app/widgets/gimpgradienteditor.h @@ -60,11 +60,13 @@ struct _GimpGradientEditor GtkWidget *control; /* Zoom and scrollbar */ - guint zoom_factor; + gdouble zoom_factor; GtkAdjustment *scroll_data; + GtkGesture *zoom_gesture; + gdouble last_zoom_scale; /* Gradient view */ - gint view_last_x; + gint view_last_x; /* -1 if mouse has left focus */ gboolean view_button_down; /* Gradient control */ @@ -74,7 +76,7 @@ struct _GimpGradientEditor GradientEditorDragMode control_drag_mode; /* What is being dragged? */ guint32 control_click_time; /* Time when mouse was pressed */ gboolean control_compress; /* Compressing/expanding handles */ - gint control_last_x; /* Last mouse position when dragging */ + gint control_last_x; /* Last mouse position, -1 if out of focus */ gdouble control_last_gx; /* Last position (wrt gradient) when dragging */ gdouble control_orig_pos; /* Original click position when dragging */ @@ -113,7 +115,8 @@ void gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor) void gimp_gradient_editor_zoom (GimpGradientEditor *editor, GimpZoomType zoom_type, - gdouble delta); + gdouble delta, + gdouble zoom_focus_x); #endif /* __GIMP_GRADIENT_EDITOR_H__ */