/** * gimp_display_shell_scale_image_is_within_viewport: * @shell: * * Returns: %TRUE if the (scaled) image is smaller than and within the * viewport. **/ gboolean gimp_display_shell_scale_image_is_within_viewport (GimpDisplayShell *shell, gboolean *horizontally, gboolean *vertically) { gint sw, sh; gboolean horizontally_dummy, vertically_dummy; g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE); if (! horizontally) horizontally = &horizontally_dummy; if (! vertically) vertically = &vertically_dummy; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); *horizontally = sw <= shell->disp_width && shell->offset_x <= 0 && shell->offset_x >= sw - shell->disp_width; *vertically = sh <= shell->disp_height && shell->offset_y <= 0 && shell->offset_y >= sh - shell->disp_height; return *vertically && *horizontally; }
/** * gimp_display_shell_scroll_setup_vscrollbar: * @shell: * @value: * * Setup the limits of the vertical scrollbar * **/ void gimp_display_shell_scroll_setup_vscrollbar (GimpDisplayShell *shell, gdouble value) { gint sh; gdouble lower; gdouble upper; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); if (! shell->display || ! gimp_display_get_image (shell->display)) return; gimp_display_shell_scale_get_image_size (shell, NULL, &sh); if (shell->disp_height < sh) { lower = MIN (value, 0); upper = MAX (value + shell->disp_height, sh); } else { lower = MIN (value, -(shell->disp_height - sh) / 2); upper = MAX (value + shell->disp_height, sh + (shell->disp_height - sh) / 2); } g_object_set (shell->vsbdata, "lower", lower, "upper", upper, "step-increment", (gdouble) MAX (shell->scale_y, MINIMUM_STEP_AMOUNT), NULL); }
/** * gimp_display_shell_scroll_center_image: * @shell: * @horizontally: * @vertically: * * Centers the image in the display shell on the desired axes. * **/ void gimp_display_shell_scroll_center_image (GimpDisplayShell *shell, gboolean horizontally, gboolean vertically) { gint sw, sh; gint target_offset_x, target_offset_y; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); if (! shell->display || ! gimp_display_get_image (shell->display) || (! vertically && ! horizontally)) return; target_offset_x = shell->offset_x; target_offset_y = shell->offset_y; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); if (horizontally) { target_offset_x = (sw - shell->disp_width) / 2; } if (vertically) { target_offset_y = (sh - shell->disp_height) / 2; } gimp_display_shell_scroll_set_offset (shell, target_offset_x, target_offset_y); }
static void gimp_display_shell_scale_get_image_center_viewport (GimpDisplayShell *shell, gint *image_center_x, gint *image_center_y) { gint sw, sh; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); if (image_center_x) *image_center_x = -shell->offset_x + sw / 2; if (image_center_y) *image_center_y = -shell->offset_y + sh / 2; }
static void gimp_canvas_passe_partout_draw (GimpCanvasItem *item, cairo_t *cr) { GimpDisplayShell *shell = gimp_canvas_item_get_shell (item); gint w, h; gimp_display_shell_scale_get_image_size (shell, &w, &h); cairo_rectangle (cr, - shell->offset_x, - shell->offset_y, w, h); GIMP_CANVAS_ITEM_CLASS (parent_class)->draw (item, cr); }
void gimp_display_shell_rotate_drag (GimpDisplayShell *shell, gdouble last_x, gdouble last_y, gdouble cur_x, gdouble cur_y, gboolean constrain) { gint image_width, image_height; gdouble px, py; gdouble x1, y1, x2, y2; gdouble angle1, angle2, angle; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); gimp_display_shell_scale_get_image_size (shell, &image_width, &image_height); px = -shell->offset_x + image_width / 2; py = -shell->offset_y + image_height / 2; x1 = cur_x - px; x2 = last_x - px; y1 = py - cur_y; y2 = py - last_y; /* find the first angle */ angle1 = atan2 (y1, x1); /* find the angle */ angle2 = atan2 (y2, x2); angle = angle2 - angle1; if (angle > G_PI || angle < -G_PI) angle = angle2 - ((angle1 < 0) ? 2.0 * G_PI + angle1 : angle1 - 2.0 * G_PI); shell->rotate_drag_angle += (angle * 180.0 / G_PI); if (shell->rotate_drag_angle < 0.0) shell->rotate_drag_angle += 360; if (shell->rotate_drag_angle >= 360.0) shell->rotate_drag_angle -= 360; gimp_display_shell_rotate_to (shell, constrain ? (gint) shell->rotate_drag_angle / 15 * 15 : shell->rotate_drag_angle); }
/** * gimp_display_shell_scroll_unoverscrollify: * @shell: * @in_offset_x: * @in_offset_y: * @out_offset_x: * @out_offset_y: * * Takes a scroll offset and returns the offset that will not result * in a scroll beyond the image border. If the image is already * overscrolled, the return value is 0 for that given axis. **/ void gimp_display_shell_scroll_unoverscrollify (GimpDisplayShell *shell, gint in_offset_x, gint in_offset_y, gint *out_offset_x, gint *out_offset_y) { gint sw, sh; gint out_offset_x_dummy, out_offset_y_dummy; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); if (! out_offset_x) out_offset_x = &out_offset_x_dummy; if (! out_offset_y) out_offset_y = &out_offset_y_dummy; *out_offset_x = in_offset_x; *out_offset_y = in_offset_y; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); if (in_offset_x < 0) { *out_offset_x = MAX (in_offset_x, MIN (0, 0 - shell->offset_x)); } else if (in_offset_x > 0) { gint min_offset = sw - shell->disp_width; *out_offset_x = MIN (in_offset_x, MAX (0, min_offset - shell->offset_x)); } if (in_offset_y < 0) { *out_offset_y = MAX (in_offset_y, MIN (0, 0 - shell->offset_y)); } else if (in_offset_y > 0) { gint min_offset = sh - shell->disp_height; *out_offset_y = MIN (in_offset_y, MAX (0, min_offset - shell->offset_y)); } }
static cairo_region_t * gimp_canvas_passe_partout_get_extents (GimpCanvasItem *item) { GimpDisplayShell *shell = gimp_canvas_item_get_shell (item); cairo_rectangle_int_t rectangle; cairo_region_t *inner; cairo_region_t *outer; rectangle.x = - shell->offset_x; rectangle.y = - shell->offset_y; gimp_display_shell_scale_get_image_size (shell, &rectangle.width, &rectangle.height); outer = cairo_region_create_rectangle (&rectangle); inner = GIMP_CANVAS_ITEM_CLASS (parent_class)->get_extents (item); cairo_region_subtract (outer, inner); return outer; }
void gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell) { g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_free (shell->rotate_transform); g_free (shell->rotate_untransform); if (shell->rotate_angle != 0.0 && gimp_display_get_image (shell->display)) { gint image_width, image_height; gdouble cx, cy; shell->rotate_transform = g_new (cairo_matrix_t, 1); shell->rotate_untransform = g_new (cairo_matrix_t, 1); gimp_display_shell_scale_get_image_size (shell, &image_width, &image_height); cx = -shell->offset_x + image_width / 2; cy = -shell->offset_y + image_height / 2; cairo_matrix_init_translate (shell->rotate_transform, cx, cy); cairo_matrix_rotate (shell->rotate_transform, shell->rotate_angle / 180.0 * G_PI); cairo_matrix_translate (shell->rotate_transform, -cx, -cy); *shell->rotate_untransform = *shell->rotate_transform; cairo_matrix_invert (shell->rotate_untransform); } else { shell->rotate_transform = NULL; shell->rotate_untransform = NULL; } }
static void gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell, cairo_t *cr) { cairo_rectangle_list_t *clip_rectangles; cairo_rectangle_int_t image_rect; image_rect.x = - shell->offset_x; image_rect.y = - shell->offset_y; gimp_display_shell_scale_get_image_size (shell, &image_rect.width, &image_rect.height); /* first, clear the exposed part of the region that is outside the * image, which is the exposed region minus the image rectangle */ cairo_save (cr); if (shell->rotate_transform) cairo_transform (cr, shell->rotate_transform); cairo_rectangle (cr, image_rect.x, image_rect.y, image_rect.width, image_rect.height); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip (cr); if (gdk_cairo_get_clip_rectangle (cr, NULL)) gimp_display_shell_draw_background (shell, cr); cairo_restore (cr); /* then, draw the exposed part of the region that is inside the * image */ cairo_save (cr); clip_rectangles = cairo_copy_clip_rectangle_list (cr); if (shell->rotate_transform) cairo_transform (cr, shell->rotate_transform); cairo_rectangle (cr, image_rect.x, image_rect.y, image_rect.width, image_rect.height); cairo_clip (cr); if (gdk_cairo_get_clip_rectangle (cr, NULL)) { gint i; cairo_save (cr); gimp_display_shell_draw_checkerboard (shell, cr); cairo_restore (cr); for (i = 0; i < clip_rectangles->num_rectangles; i++) { cairo_rectangle_t rect = clip_rectangles->rectangles[i]; gimp_display_shell_draw_image (shell, cr, floor (rect.x), floor (rect.y), ceil (rect.width), ceil (rect.height)); } } cairo_rectangle_list_destroy (clip_rectangles); cairo_restore (cr); /* finally, draw all the remaining image window stuff on top */ /* draw canvas items */ cairo_save (cr); if (shell->rotate_transform) cairo_transform (cr, shell->rotate_transform); gimp_canvas_item_draw (shell->canvas_item, cr); cairo_restore (cr); gimp_canvas_item_draw (shell->unrotated_item, cr); /* restart (and recalculate) the selection boundaries */ gimp_display_shell_selection_restart (shell); }
void gimp_display_shell_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GimpDisplayShell *shell) { /* are we in destruction? */ if (! shell->display || ! gimp_display_get_shell (shell->display)) return; if ((shell->disp_width != allocation->width) || (shell->disp_height != allocation->height)) { if (shell->zoom_on_resize && shell->disp_width > 64 && shell->disp_height > 64 && allocation->width > 64 && allocation->height > 64) { gdouble scale = gimp_zoom_model_get_factor (shell->zoom); gint offset_x; gint offset_y; /* FIXME: The code is a bit of a mess */ /* multiply the zoom_factor with the ratio of the new and * old canvas diagonals */ scale *= (sqrt (SQR (allocation->width) + SQR (allocation->height)) / sqrt (SQR (shell->disp_width) + SQR (shell->disp_height))); offset_x = UNSCALEX (shell, shell->offset_x); offset_y = UNSCALEX (shell, shell->offset_y); gimp_zoom_model_zoom (shell->zoom, GIMP_ZOOM_TO, scale); shell->offset_x = SCALEX (shell, offset_x); shell->offset_y = SCALEY (shell, offset_y); } shell->disp_width = allocation->width; shell->disp_height = allocation->height; /* When we size-allocate due to resize of the top level window, * we want some additional logic. Don't apply it on * zoom_on_resize though. */ if (shell->size_allocate_from_configure_event && ! shell->zoom_on_resize) { gboolean center_horizontally; gboolean center_vertically; gint target_offset_x; gint target_offset_y; gint sw; gint sh; gimp_display_shell_scale_get_image_size (shell, &sw, &sh); center_horizontally = sw <= shell->disp_width; center_vertically = sh <= shell->disp_height; gimp_display_shell_scroll_center_image (shell, center_horizontally, center_vertically); /* This is basically the best we can do before we get an * API for storing the image offset at the start of an * image window resize using the mouse */ target_offset_x = shell->offset_x; target_offset_y = shell->offset_y; if (! center_horizontally) { target_offset_x = MAX (shell->offset_x, 0); } if (! center_vertically) { target_offset_y = MAX (shell->offset_y, 0); } gimp_display_shell_scroll_set_offset (shell, target_offset_x, target_offset_y); } gimp_display_shell_scroll_clamp_and_update (shell); gimp_display_shell_scaled (shell); /* Reset */ shell->size_allocate_from_configure_event = FALSE; } }