/** * gimp_display_shell_scale_get_zoom_focus: * @shell: * @new_scale: * @x: * @y: * * Calculates the viewport coordinate to focus on when zooming * independently for each axis. **/ static void gimp_display_shell_scale_get_zoom_focus (GimpDisplayShell *shell, gdouble new_scale, gdouble current_scale, gdouble *x, gdouble *y, GimpZoomFocus zoom_focus) { GtkWidget *window = GTK_WIDGET (gimp_display_shell_get_window (shell)); GdkEvent *event; gint image_center_x; gint image_center_y; gint other_x; gint other_y; /* Calculate stops-to-fit focus point */ gimp_display_shell_scale_get_image_center_viewport (shell, &image_center_x, &image_center_y); /* Calculate other focus point, default is the canvas center */ other_x = shell->disp_width / 2; other_y = shell->disp_height / 2; /* Center on the mouse position instead of the display center if * one of the following conditions are fulfilled and pointer is * within the canvas: * * (1) there's no current event (the action was triggered by an * input controller) * (2) the event originates from the canvas (a scroll event) * (3) the event originates from the window (a key press event) * * Basically the only situation where we don't want to center on * mouse position is if the action is being called from a menu. */ event = gtk_get_current_event (); if (! event || gtk_get_event_widget (event) == shell->canvas || gtk_get_event_widget (event) == window) { GdkPoint *point = g_queue_pop_head (shell->zoom_focus_pointer_queue); gint canvas_pointer_x; gint canvas_pointer_y; if (point) { canvas_pointer_x = point->x; canvas_pointer_y = point->y; g_slice_free (GdkPoint, point); } else { gtk_widget_get_pointer (shell->canvas, &canvas_pointer_x, &canvas_pointer_y); } if (canvas_pointer_x >= 0 && canvas_pointer_y >= 0 && canvas_pointer_x < shell->disp_width && canvas_pointer_y < shell->disp_height) { other_x = canvas_pointer_x; other_y = canvas_pointer_y; } } /* Decide which one to use for each axis */ if (zoom_focus == GIMP_ZOOM_FOCUS_RETAIN_CENTERING_ELSE_BEST_GUESS) { if (gimp_display_shell_scale_viewport_coord_almost_centered (shell, image_center_x, image_center_y, NULL, NULL)) { zoom_focus = GIMP_ZOOM_FOCUS_IMAGE_CENTER; } else { zoom_focus = GIMP_ZOOM_FOCUS_BEST_GUESS; } } switch (zoom_focus) { case GIMP_ZOOM_FOCUS_POINTER: *x = other_x; *y = other_y; break; case GIMP_ZOOM_FOCUS_IMAGE_CENTER: *x = image_center_x; *y = image_center_y; break; case GIMP_ZOOM_FOCUS_BEST_GUESS: default: { gboolean within_horizontally, within_vertically; gboolean stops_horizontally, stops_vertically; gimp_display_shell_scale_image_is_within_viewport (shell, &within_horizontally, &within_vertically); gimp_display_shell_scale_image_stops_to_fit (shell, new_scale, current_scale, &stops_horizontally, &stops_vertically); *x = within_horizontally && ! stops_horizontally ? image_center_x : other_x; *y = within_vertically && ! stops_vertically ? image_center_y : other_y; } break; } }
/** * gimp_display_shell_scale: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in, our or to a specific scale * @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO * * This function figures out the context of the zoom and behaves * appropriatley thereafter. * **/ void gimp_display_shell_scale (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble new_scale, GimpZoomFocus zoom_focus) { gdouble current_scale; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (shell->canvas != NULL); current_scale = gimp_zoom_model_get_factor (shell->zoom); if (zoom_type != GIMP_ZOOM_TO) new_scale = gimp_zoom_model_zoom_step (zoom_type, current_scale); if (! SCALE_EQUALS (new_scale, current_scale)) { GimpDisplayConfig *config = shell->display->config; gboolean resize_window; /* Resize windows only in multi-window mode */ resize_window = (config->resize_windows_on_zoom && ! GIMP_GUI_CONFIG (config)->single_window_mode); if (resize_window) { /* If the window is resized on zoom, simply do the zoom and * get things rolling */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, new_scale); gimp_display_shell_scale_resize (shell, TRUE, FALSE); } else { gboolean starts_fitting_horiz; gboolean starts_fitting_vert; gboolean zoom_focus_almost_centered_horiz; gboolean zoom_focus_almost_centered_vert; gboolean image_center_almost_centered_horiz; gboolean image_center_almost_centered_vert; gdouble x, y; gint image_center_x; gint image_center_y; gimp_display_shell_scale_get_zoom_focus (shell, new_scale, current_scale, &x, &y, zoom_focus); gimp_display_shell_scale_get_image_center_viewport (shell, &image_center_x, &image_center_y); gimp_display_shell_scale_to (shell, new_scale, x, y); /* If an image axis started to fit due to zooming out or if * the focus point is as good as in the center, center on * that axis */ gimp_display_shell_scale_image_starts_to_fit (shell, new_scale, current_scale, &starts_fitting_horiz, &starts_fitting_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, x, y, &zoom_focus_almost_centered_horiz, &zoom_focus_almost_centered_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, image_center_x, image_center_y, &image_center_almost_centered_horiz, &image_center_almost_centered_vert); gimp_display_shell_scroll_center_image (shell, starts_fitting_horiz || (zoom_focus_almost_centered_horiz && image_center_almost_centered_horiz), starts_fitting_vert || (zoom_focus_almost_centered_vert && image_center_almost_centered_vert)); } } }
/** * gimp_display_shell_scale: * @shell: the #GimpDisplayShell * @zoom_type: whether to zoom in, our or to a specific scale * @scale: ignored unless @zoom_type == %GIMP_ZOOM_TO * * This function figures out the context of the zoom and behaves * appropriatley thereafter. * **/ void gimp_display_shell_scale (GimpDisplayShell *shell, GimpZoomType zoom_type, gdouble new_scale, GimpZoomFocus zoom_focus) { gint x, y; gdouble current_scale; gdouble real_new_scale; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (shell->canvas != NULL); current_scale = gimp_zoom_model_get_factor (shell->zoom); if (zoom_type != GIMP_ZOOM_TO) { real_new_scale = gimp_zoom_model_zoom_step (zoom_type, current_scale); } else { real_new_scale = new_scale; } if (! SCALE_EQUALS (real_new_scale, current_scale)) { if (shell->display->config->resize_windows_on_zoom) { GimpImageWindow *window = gimp_display_shell_get_window (shell); /* If the window is resized on zoom, simply do the zoom and * get things rolling */ gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, real_new_scale); gimp_display_shell_scaled (shell); if (window && gimp_image_window_get_active_shell (window) == shell) { gimp_image_window_shrink_wrap (window, FALSE); } } else { gboolean starts_fitting_horiz; gboolean starts_fitting_vert; gboolean zoom_focus_almost_centered_horiz; gboolean zoom_focus_almost_centered_vert; gboolean image_center_almost_centered_horiz; gboolean image_center_almost_centered_vert; gint image_center_x; gint image_center_y; gimp_display_shell_scale_get_zoom_focus (shell, real_new_scale, current_scale, &x, &y, zoom_focus); gimp_display_shell_scale_get_image_center_viewport (shell, &image_center_x, &image_center_y); gimp_display_shell_scale_to (shell, real_new_scale, x, y); /* If an image axis started to fit due to zooming out or if * the focus point is as good as in the center, center on * that axis */ gimp_display_shell_scale_image_starts_to_fit (shell, real_new_scale, current_scale, &starts_fitting_horiz, &starts_fitting_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, x, y, &zoom_focus_almost_centered_horiz, &zoom_focus_almost_centered_vert); gimp_display_shell_scale_viewport_coord_almost_centered (shell, image_center_x, image_center_y, &image_center_almost_centered_horiz, &image_center_almost_centered_vert); gimp_display_shell_scroll_center_image (shell, starts_fitting_horiz || (zoom_focus_almost_centered_horiz && image_center_almost_centered_horiz), starts_fitting_vert || (zoom_focus_almost_centered_vert && image_center_almost_centered_vert)); } } }