diff --git a/app/actions/view-actions.c b/app/actions/view-actions.c index 4d577a4a1a..852e2df542 100644 --- a/app/actions/view-actions.c +++ b/app/actions/view-actions.c @@ -172,6 +172,14 @@ static const GimpActionEntry view_actions[] = static const GimpToggleActionEntry view_toggle_actions[] = { + + { "view-show-all", NULL, + NC_("view-action", "Show _All"), NULL, + NC_("view-action", "Show full image content"), + view_show_all_cmd_callback, + FALSE, + GIMP_HELP_VIEW_SHOW_ALL }, + { "view-dot-for-dot", NULL, NC_("view-action", "_Dot for Dot"), NULL, NC_("view-action", "A pixel on the screen represents an image pixel"), @@ -251,7 +259,7 @@ static const GimpToggleActionEntry view_toggle_actions[] = GIMP_HELP_VIEW_SHOW_SAMPLE_POINTS }, { "view-snap-to-guides", NULL, - NC_("view-action", "Sn_ap to Guides"), NULL, + NC_("view-action", "Snap to Gu_ides"), NULL, NC_("view-action", "Tool operations snap to guides"), view_snap_to_guides_cmd_callback, TRUE, @@ -899,6 +907,9 @@ view_actions_update (GimpActionGroup *group, SET_SENSITIVE ("view-new", image); SET_SENSITIVE ("view-close", image); + SET_SENSITIVE ("view-show-all", image); + SET_ACTIVE ("view-show-all", display && shell->show_all); + SET_SENSITIVE ("view-dot-for-dot", image); SET_ACTIVE ("view-dot-for-dot", display && shell->dot_for_dot); diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c index 3e17f3276f..71026c527d 100644 --- a/app/actions/view-commands.c +++ b/app/actions/view-commands.c @@ -309,6 +309,36 @@ view_zoom_other_cmd_callback (GimpAction *action, } } +void +view_show_all_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data) +{ + GimpDisplay *display; + GimpDisplayShell *shell; + gboolean active; + return_if_no_display (display, data); + + shell = gimp_display_get_shell (display); + + active = g_variant_get_boolean (value); + + if (active != shell->show_all) + { + GimpImageWindow *window = gimp_display_shell_get_window (shell); + + gimp_display_shell_set_show_all (shell, active); + + if (window) + SET_ACTIVE (gimp_image_window_get_ui_manager (window), + "view-show-all", shell->show_all); + + if (IS_ACTIVE_DISPLAY (display)) + SET_ACTIVE (shell->popup_manager, "view-show-all", + shell->show_all); + } +} + void view_dot_for_dot_cmd_callback (GimpAction *action, GVariant *value, diff --git a/app/actions/view-commands.h b/app/actions/view-commands.h index 72afae9b2c..c28a24ef2e 100644 --- a/app/actions/view-commands.h +++ b/app/actions/view-commands.h @@ -53,6 +53,10 @@ void view_zoom_explicit_cmd_callback (GimpAction *action, void view_zoom_other_cmd_callback (GimpAction *action, gpointer data); +void view_show_all_cmd_callback (GimpAction *action, + GVariant *value, + gpointer data); + void view_dot_for_dot_cmd_callback (GimpAction *action, GVariant *value, gpointer data); diff --git a/app/config/gimpdisplayconfig.c b/app/config/gimpdisplayconfig.c index 1e285ca518..3c55522020 100644 --- a/app/config/gimpdisplayconfig.c +++ b/app/config/gimpdisplayconfig.c @@ -51,6 +51,7 @@ enum PROP_MARCHING_ANTS_SPEED, PROP_RESIZE_WINDOWS_ON_ZOOM, PROP_RESIZE_WINDOWS_ON_RESIZE, + PROP_DEFAULT_SHOW_ALL, PROP_DEFAULT_DOT_FOR_DOT, PROP_INITIAL_ZOOM_TO_FIT, PROP_CURSOR_MODE, @@ -158,6 +159,13 @@ gimp_display_config_class_init (GimpDisplayConfigClass *klass) FALSE, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_DEFAULT_SHOW_ALL, + "default-show-all", + "Default show-all", + DEFAULT_SHOW_ALL_BLURB, + FALSE, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_DEFAULT_DOT_FOR_DOT, "default-dot-for-dot", "Default dot-for-dot", @@ -401,6 +409,9 @@ gimp_display_config_set_property (GObject *object, case PROP_RESIZE_WINDOWS_ON_RESIZE: display_config->resize_windows_on_resize = g_value_get_boolean (value); break; + case PROP_DEFAULT_SHOW_ALL: + display_config->default_show_all = g_value_get_boolean (value); + break; case PROP_DEFAULT_DOT_FOR_DOT: display_config->default_dot_for_dot = g_value_get_boolean (value); break; @@ -507,6 +518,9 @@ gimp_display_config_get_property (GObject *object, case PROP_RESIZE_WINDOWS_ON_RESIZE: g_value_set_boolean (value, display_config->resize_windows_on_resize); break; + case PROP_DEFAULT_SHOW_ALL: + g_value_set_boolean (value, display_config->default_show_all); + break; case PROP_DEFAULT_DOT_FOR_DOT: g_value_set_boolean (value, display_config->default_dot_for_dot); break; diff --git a/app/config/gimpdisplayconfig.h b/app/config/gimpdisplayconfig.h index 2c6c05b0dd..3fe2050047 100644 --- a/app/config/gimpdisplayconfig.h +++ b/app/config/gimpdisplayconfig.h @@ -47,6 +47,7 @@ struct _GimpDisplayConfig gint marching_ants_speed; gboolean resize_windows_on_zoom; gboolean resize_windows_on_resize; + gboolean default_show_all; gboolean default_dot_for_dot; gboolean initial_zoom_to_fit; GimpCursorMode cursor_mode; diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h index 9b64a19fdb..e710fd6021 100644 --- a/app/config/gimprc-blurbs.h +++ b/app/config/gimprc-blurbs.h @@ -67,6 +67,9 @@ _("Context-dependent mouse pointers are helpful. They are enabled by " \ "Specify a default tool preset. The tool preset is searched for in the " \ "specified tool prests path." +#define DEFAULT_SHOW_ALL_BLURB \ +_("Show full image content by default.") + #define DEFAULT_DOT_FOR_DOT_BLURB \ _("When enabled, this will ensure that each pixel of an image gets " \ "mapped to a pixel on the screen.") diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c index 71a2a72b39..af827c335b 100644 --- a/app/dialogs/preferences-dialog.c +++ b/app/dialogs/preferences-dialog.c @@ -2817,6 +2817,10 @@ prefs_dialog_new (Gimp *gimp, /* General */ vbox2 = prefs_frame_new (_("General"), GTK_CONTAINER (vbox), FALSE); + prefs_check_button_add (object, "default-show-all", + _("Use \"Show _all\" by default"), + GTK_BOX (vbox2)); + prefs_check_button_add (object, "default-dot-for-dot", _("Use \"_Dot for dot\" by default"), GTK_BOX (vbox2)); @@ -2824,7 +2828,7 @@ prefs_dialog_new (Gimp *gimp, grid = prefs_grid_new (GTK_CONTAINER (vbox2)); prefs_spin_button_add (object, "marching-ants-speed", 1.0, 10.0, 0, - _("Marching _ants speed:"), + _("Marching ants s_peed:"), GTK_GRID (grid), 0, size_group); /* Zoom & Resize Behavior */ diff --git a/app/display/gimpdisplay-handlers.c b/app/display/gimpdisplay-handlers.c index a255d8c667..94cb863ad7 100644 --- a/app/display/gimpdisplay-handlers.c +++ b/app/display/gimpdisplay-handlers.c @@ -30,16 +30,21 @@ /* local function prototypes */ -static void gimp_display_update_handler (GimpProjection *projection, - gboolean now, - gint x, - gint y, - gint w, - gint h, - GimpDisplay *display); -static void gimp_display_flush_handler (GimpImage *image, - gboolean invalidate_preview, - GimpDisplay *display); +static void gimp_display_update_handler (GimpProjection *projection, + gboolean now, + gint x, + gint y, + gint w, + gint h, + GimpDisplay *display); + +static void gimp_display_bounds_changed_handler (GimpImage *image, + gint old_x, + gint old_y, + GimpDisplay *display); +static void gimp_display_flush_handler (GimpImage *image, + gboolean invalidate_preview, + GimpDisplay *display); /* public functions */ @@ -59,6 +64,9 @@ gimp_display_connect (GimpDisplay *display) G_CALLBACK (gimp_display_update_handler), display); + g_signal_connect (image, "bounds-changed", + G_CALLBACK (gimp_display_bounds_changed_handler), + display); g_signal_connect (image, "flush", G_CALLBACK (gimp_display_flush_handler), display); @@ -78,6 +86,9 @@ gimp_display_disconnect (GimpDisplay *display) g_signal_handlers_disconnect_by_func (image, gimp_display_flush_handler, display); + g_signal_handlers_disconnect_by_func (image, + gimp_display_bounds_changed_handler, + display); g_signal_handlers_disconnect_by_func (gimp_image_get_projection (image), gimp_display_update_handler, @@ -99,6 +110,15 @@ gimp_display_update_handler (GimpProjection *projection, gimp_display_update_area (display, now, x, y, w, h); } +static void +gimp_display_bounds_changed_handler (GimpImage *image, + gint old_x, + gint old_y, + GimpDisplay *display) +{ + gimp_display_update_bounding_box (display); +} + static void gimp_display_flush_handler (GimpImage *image, gboolean invalidate_preview, diff --git a/app/display/gimpdisplay.c b/app/display/gimpdisplay.c index 905cdc7142..8f076edab1 100644 --- a/app/display/gimpdisplay.c +++ b/app/display/gimpdisplay.c @@ -70,6 +70,8 @@ struct _GimpDisplayImplPrivate gint instance; /* the instance # of this display as * taken from the image at creation */ + GeglRectangle bounding_box; + GtkWidget *shell; cairo_region_t *update_region; }; @@ -385,6 +387,8 @@ gimp_display_new (Gimp *gimp, shell = gimp_display_get_shell (display); + gimp_display_update_bounding_box (display); + gimp_image_window_add_shell (window, shell); gimp_display_shell_present (shell); @@ -579,6 +583,8 @@ gimp_display_set_image (GimpDisplay *display, if (old_image) g_object_unref (old_image); + gimp_display_update_bounding_box (display); + if (shell) { if (image) @@ -653,6 +659,48 @@ gimp_display_fill (GimpDisplay *display, image, unit, scale); } +void +gimp_display_update_bounding_box (GimpDisplay *display) +{ + GimpDisplayImplPrivate *private; + GimpDisplayShell *shell; + GeglRectangle bounding_box = {}; + + g_return_if_fail (GIMP_IS_DISPLAY (display)); + + private = GIMP_DISPLAY_IMPL (display)->priv; + shell = gimp_display_get_shell (display); + + if (shell) + { + bounding_box = gimp_display_shell_get_bounding_box (shell); + + if (! gegl_rectangle_equal (&bounding_box, &private->bounding_box)) + { + GeglRectangle diff_rects[4]; + gint n_diff_rects; + gint i; + + n_diff_rects = gegl_rectangle_subtract (diff_rects, + &private->bounding_box, + &bounding_box); + + for (i = 0; i < n_diff_rects; i++) + { + gimp_display_paint_area (display, + diff_rects[i].x, diff_rects[i].y, + diff_rects[i].width, diff_rects[i].height); + } + + private->bounding_box = bounding_box; + } + } + else + { + private->bounding_box = bounding_box; + } +} + void gimp_display_update_area (GimpDisplay *display, gboolean now, @@ -748,27 +796,25 @@ gimp_display_paint_area (GimpDisplay *display, gint w, gint h) { - GimpDisplayImplPrivate *private = GIMP_DISPLAY_IMPL (display)->priv; - GimpDisplayShell *shell = gimp_display_get_shell (display); - gint image_width = gimp_image_get_width (private->image); - gint image_height = gimp_image_get_height (private->image); + GimpDisplayImplPrivate *private = GIMP_DISPLAY_IMPL (display)->priv; + GimpDisplayShell *shell = gimp_display_get_shell (display); + GeglRectangle rect; gint x1, y1, x2, y2; gdouble x1_f, y1_f, x2_f, y2_f; - /* Bounds check */ - x1 = CLAMP (x, 0, image_width); - y1 = CLAMP (y, 0, image_height); - x2 = CLAMP (x + w, 0, image_width); - y2 = CLAMP (y + h, 0, image_height); - - x = x1; - y = y1; - w = (x2 - x1); - h = (y2 - y1); + if (! gegl_rectangle_intersect (&rect, + &private->bounding_box, + GEGL_RECTANGLE (x, y, w, h))) + { + return; + } /* display the area */ gimp_display_shell_transform_bounds (shell, - x, y, x + w, y + h, + rect.x, + rect.y, + rect.x + rect.width, + rect.y + rect.height, &x1_f, &y1_f, &x2_f, &y2_f); /* make sure to expose a superset of the transformed sub-pixel expose diff --git a/app/display/gimpdisplay.h b/app/display/gimpdisplay.h index 6fbb5154fa..b928fdbf2b 100644 --- a/app/display/gimpdisplay.h +++ b/app/display/gimpdisplay.h @@ -77,6 +77,9 @@ void gimp_display_fill (GimpDisplay *display, GimpUnit unit, gdouble scale); +void gimp_display_update_bounding_box + (GimpDisplay *display); + void gimp_display_update_area (GimpDisplay *display, gboolean now, gint x, diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c index 31a5ae00c5..3662c180e8 100644 --- a/app/display/gimpdisplayshell-callbacks.c +++ b/app/display/gimpdisplayshell-callbacks.c @@ -44,6 +44,7 @@ #include "gimpdisplayshell-scrollbars.h" #include "gimpdisplayshell-selection.h" #include "gimpdisplayshell-title.h" +#include "gimpdisplayshell-transform.h" #include "gimpimagewindow.h" #include "gimpnavigationeditor.h" @@ -468,14 +469,18 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell, cairo_t *cr) { cairo_rectangle_list_t *clip_rectangles; - cairo_rectangle_int_t image_rect; + GeglRectangle image_rect; + GeglRectangle rotated_image_rect; cairo_matrix_t matrix; + gdouble x1, y1; + gdouble x2, y2; - 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); + gimp_display_shell_scale_get_image_unrotated_bounding_box ( + shell, + &image_rect.x, + &image_rect.y, + &image_rect.width, + &image_rect.height); /* first, draw the background */ @@ -494,6 +499,13 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell, if (shell->rotate_transform) cairo_transform (cr, shell->rotate_transform); + if (shell->show_all) + { + cairo_save (cr); + gimp_display_shell_draw_checkerboard (shell, cr); + cairo_restore (cr); + } + cairo_rectangle (cr, image_rect.x, image_rect.y, @@ -501,13 +513,28 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell, image_rect.height); cairo_clip (cr); + gimp_display_shell_rotate_bounds (shell, + image_rect.x, + image_rect.y, + image_rect.x + image_rect.width, + image_rect.y + image_rect.height, + &x1, &y1, &x2, &y2); + + rotated_image_rect.x = floor (x1); + rotated_image_rect.y = floor (y1); + rotated_image_rect.width = ceil (x2) - rotated_image_rect.x; + rotated_image_rect.height = ceil (y2) - rotated_image_rect.y; + if (gdk_cairo_get_clip_rectangle (cr, NULL)) { gint i; - cairo_save (cr); - gimp_display_shell_draw_checkerboard (shell, cr); - cairo_restore (cr); + if (! shell->show_all) + { + cairo_save (cr); + gimp_display_shell_draw_checkerboard (shell, cr); + cairo_restore (cr); + } if (shell->show_image) { @@ -515,13 +542,20 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell, for (i = 0; i < clip_rectangles->num_rectangles; i++) { - cairo_rectangle_t rect = clip_rectangles->rectangles[i]; + cairo_rectangle_t clip_rect = clip_rectangles->rectangles[i]; + GeglRectangle rect; - gimp_display_shell_draw_image (shell, cr, - floor (rect.x), - floor (rect.y), - ceil (rect.width), - ceil (rect.height)); + rect.x = floor (clip_rect.x); + rect.y = floor (clip_rect.y); + rect.width = ceil (clip_rect.x + clip_rect.width) - rect.x; + rect.height = ceil (clip_rect.y + clip_rect.height) - rect.y; + + if (gegl_rectangle_intersect (&rect, &rect, &rotated_image_rect)) + { + gimp_display_shell_draw_image (shell, cr, + rect.x, rect.y, + rect.width, rect.height); + } } } } diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c index d3bac52f1c..efb82fb8fd 100644 --- a/app/display/gimpdisplayshell-handlers.c +++ b/app/display/gimpdisplayshell-handlers.c @@ -387,6 +387,13 @@ gimp_display_shell_connect (GimpDisplayShell *shell) gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary), gimp_image_get_active_layer (image)); + + if (shell->show_all) + { + gimp_image_inc_show_all_count (image); + + gimp_image_flush (image); + } } void @@ -550,6 +557,13 @@ gimp_display_shell_disconnect (GimpDisplayShell *shell) g_signal_handlers_disconnect_by_func (image, gimp_display_shell_clean_dirty_handler, shell); + + if (shell->show_all) + { + gimp_image_dec_show_all_count (image); + + gimp_image_flush (image); + } } diff --git a/app/display/gimpdisplayshell-render.c b/app/display/gimpdisplayshell-render.c index 61631cef80..f49a8206ef 100644 --- a/app/display/gimpdisplayshell-render.c +++ b/app/display/gimpdisplayshell-render.c @@ -143,6 +143,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, gint y; gint width; gint height; + GeglAbyssPolicy abyss_policy; gint filter = GEGL_BUFFER_FILTER_AUTO; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); @@ -166,13 +167,19 @@ gimp_display_shell_render (GimpDisplayShell *shell, display_config = shell->display->config; + if (shell->show_all) + abyss_policy = GEGL_ABYSS_NONE; + else + abyss_policy = GEGL_ABYSS_CLAMP; + if (display_config->zoom_quality != GIMP_ZOOM_QUALITY_HIGH) { filter = GEGL_BUFFER_FILTER_NEAREST; } image = gimp_display_get_image (shell->display); - buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image)); + buffer = gimp_pickable_get_buffer ( + gimp_display_shell_get_pickable (shell)); #ifdef USE_NODE_BLIT node = gimp_projectable_get_graph (GIMP_PROJECTABLE (image)); @@ -265,7 +272,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, GEGL_RECTANGLE (x, y, width, height), scale, gimp_projectable_get_format (GIMP_PROJECTABLE (image)), shell->profile_data, shell->profile_stride, - GEGL_ABYSS_CLAMP | filter); + abyss_policy | filter); #else gegl_node_blit (node, scale, GEGL_RECTANGLE (x, y, width, height), @@ -283,7 +290,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, GEGL_RECTANGLE (x, y, width, height), scale, shell->filter_format, shell->filter_data, shell->filter_stride, - GEGL_ABYSS_CLAMP | filter); + abyss_policy | filter); #else gegl_node_blit (node, scale, GEGL_RECTANGLE (x, y, width, height), @@ -396,7 +403,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, GEGL_RECTANGLE (0, 0, width, height), 1.0, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, - GEGL_ABYSS_CLAMP); + GEGL_ABYSS_NONE); } } else @@ -409,7 +416,7 @@ gimp_display_shell_render (GimpDisplayShell *shell, GEGL_RECTANGLE (x, y, width, height), scale, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, - GEGL_ABYSS_CLAMP | filter); + abyss_policy | filter); #else gegl_node_blit (node, scale, GEGL_RECTANGLE (x, y, width, height), diff --git a/app/display/gimpdisplayshell-scale.c b/app/display/gimpdisplayshell-scale.c index 440c304639..a6c40f9f07 100644 --- a/app/display/gimpdisplayshell-scale.c +++ b/app/display/gimpdisplayshell-scale.c @@ -275,6 +275,118 @@ gimp_display_shell_scale_get_image_bounds (GimpDisplayShell *shell, if (h) *h = y2 - y1; } +/** + * gimp_display_shell_scale_get_image_bounding_box: + * @shell: + * @x: + * @y: + * @w: + * @h: + * + * Gets the screen-space boudning box of the image content, after it has + * been transformed (i.e., scaled, rotated, and scrolled). + **/ +void +gimp_display_shell_scale_get_image_bounding_box (GimpDisplayShell *shell, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GeglRectangle bounding_box; + gdouble x1, y1; + gdouble x2, y2; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + bounding_box = gimp_display_shell_get_bounding_box (shell); + + gimp_display_shell_transform_bounds (shell, + bounding_box.x, + bounding_box.y, + bounding_box.x + bounding_box.width, + bounding_box.y + bounding_box.height, + &x1, &y1, + &x2, &y2); + + if (! shell->show_all) + { + x1 = ceil (x1); + y1 = ceil (y1); + x2 = floor (x2); + y2 = floor (y2); + } + else + { + x1 = floor (x1); + y1 = floor (y1); + x2 = ceil (x2); + y2 = ceil (y2); + } + + if (x) *x = x1 + shell->offset_x; + if (y) *y = y1 + shell->offset_y; + if (w) *w = x2 - x1; + if (h) *h = y2 - y1; +} + +/** + * gimp_display_shell_scale_get_image_unrotated_bounding_box: + * @shell: + * @x: + * @y: + * @w: + * @h: + * + * Gets the screen-space boudning box of the image content, after it has + * been scaled and scrolled, but before it has been rotated. + **/ +void +gimp_display_shell_scale_get_image_unrotated_bounding_box (GimpDisplayShell *shell, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GeglRectangle bounding_box; + gdouble x1, y1; + gdouble x2, y2; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + bounding_box = gimp_display_shell_get_bounding_box (shell); + + x1 = bounding_box.x * shell->scale_x - + shell->offset_x; + y1 = bounding_box.y * shell->scale_y - + shell->offset_y; + + x2 = (bounding_box.x + bounding_box.width) * shell->scale_x - + shell->offset_x; + y2 = (bounding_box.y + bounding_box.height) * shell->scale_y - + shell->offset_y; + + if (! shell->show_all) + { + x1 = ceil (x1); + y1 = ceil (y1); + x2 = floor (x2); + y2 = floor (y2); + } + else + { + x1 = floor (x1); + y1 = floor (y1); + x2 = ceil (x2); + y2 = ceil (y2); + } + + if (x) *x = x1; + if (y) *y = y1; + if (w) *w = x2 - x1; + if (h) *h = y2 - y1; +} + /** * gimp_display_shell_scale_image_is_within_viewport: * @shell: diff --git a/app/display/gimpdisplayshell-scale.h b/app/display/gimpdisplayshell-scale.h index 8489a1545a..7f38eb0264 100644 --- a/app/display/gimpdisplayshell-scale.h +++ b/app/display/gimpdisplayshell-scale.h @@ -34,6 +34,18 @@ void gimp_display_shell_scale_get_image_bounds (GimpDisplayShell *shell, gint *y, gint *w, gint *h); +void gimp_display_shell_scale_get_image_bounding_box + (GimpDisplayShell *shell, + gint *x, + gint *y, + gint *w, + gint *h); +void gimp_display_shell_scale_get_image_unrotated_bounding_box + (GimpDisplayShell *shell, + gint *x, + gint *y, + gint *w, + gint *h); gboolean gimp_display_shell_scale_image_is_within_viewport (GimpDisplayShell *shell, gboolean *horizontally, diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index c580fe9537..54c78488a1 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -45,6 +45,8 @@ #include "core/gimpimage-grid.h" #include "core/gimpimage-guides.h" #include "core/gimpimage-snap.h" +#include "core/gimppickable.h" +#include "core/gimpprojectable.h" #include "core/gimpprojection.h" #include "core/gimpmarshal.h" #include "core/gimptemplate.h" @@ -99,7 +101,8 @@ enum PROP_UNIT, PROP_TITLE, PROP_STATUS, - PROP_ICON + PROP_ICON, + PROP_SHOW_ALL }; enum @@ -289,6 +292,12 @@ gimp_display_shell_class_init (GimpDisplayShellClass *klass) GDK_TYPE_PIXBUF, GIMP_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_SHOW_ALL, + g_param_spec_boolean ("show-all", + NULL, NULL, + FALSE, + GIMP_PARAM_READWRITE)); + gtk_widget_class_set_css_name (widget_class, "GimpDisplayShell"); } @@ -316,6 +325,8 @@ gimp_display_shell_init (GimpDisplayShell *shell) shell->show_image = TRUE; + shell->show_all = FALSE; + gimp_display_shell_items_init (shell); shell->icon_size = 128; @@ -714,6 +725,8 @@ gimp_display_shell_constructed (GObject *object) /* make sure the information is up-to-date */ gimp_display_shell_scale_update (shell); + + gimp_display_shell_set_show_all (shell, config->default_show_all); } static void @@ -836,6 +849,9 @@ gimp_display_shell_set_property (GObject *object, g_object_unref (shell->icon); shell->icon = g_value_dup_object (value); break; + case PROP_SHOW_ALL: + gimp_display_shell_set_show_all (shell, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -874,6 +890,9 @@ gimp_display_shell_get_property (GObject *object, case PROP_ICON: g_value_set_object (value, shell->icon); break; + case PROP_SHOW_ALL: + g_value_set_boolean (value, shell->show_all); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -1441,6 +1460,8 @@ gimp_display_shell_fill (GimpDisplayShell *shell, config = shell->display->config; window = gimp_display_shell_get_window (shell); + shell->show_image = TRUE; + shell->dot_for_dot = config->default_dot_for_dot; gimp_display_shell_set_unit (shell, unit); @@ -1475,6 +1496,8 @@ gimp_display_shell_fill (GimpDisplayShell *shell, g_idle_add_full (GIMP_PRIORITY_DISPLAY_SHELL_FILL_IDLE, (GSourceFunc) gimp_display_shell_fill_idle, shell, NULL); + + gimp_display_shell_set_show_all (shell, config->default_show_all); } void @@ -1741,6 +1764,84 @@ gimp_display_shell_set_show_image (GimpDisplayShell *shell, } } +void +gimp_display_shell_set_show_all (GimpDisplayShell *shell, + gboolean show_all) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + if (show_all != shell->show_all) + { + GimpImage *image = gimp_display_get_image (shell->display); + + shell->show_all = show_all; + + if (image) + { + if (show_all) + gimp_image_inc_show_all_count (image); + else + gimp_image_dec_show_all_count (image); + + gimp_image_flush (image); + } + + gimp_display_update_bounding_box (shell->display); + + gimp_display_shell_expose_full (shell); + + g_object_notify (G_OBJECT (shell), "show-all"); + } +} + + +GimpPickable * +gimp_display_shell_get_pickable (GimpDisplayShell *shell) +{ + GimpImage *image; + + g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL); + + image = gimp_display_get_image (shell->display); + + if (image) + { + if (! shell->show_all) + return GIMP_PICKABLE (image); + else + return GIMP_PICKABLE (gimp_image_get_projection (image)); + } + + return NULL; +} + +GeglRectangle +gimp_display_shell_get_bounding_box (GimpDisplayShell *shell) +{ + GeglRectangle bounding_box = {}; + GimpImage *image; + + g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), bounding_box); + + image = gimp_display_get_image (shell->display); + + if (image) + { + if (! shell->show_all) + { + bounding_box.width = gimp_image_get_width (image); + bounding_box.height = gimp_image_get_height (image); + } + else + { + bounding_box = gimp_projectable_get_bounding_box ( + GIMP_PROJECTABLE (image)); + } + } + + return bounding_box; +} + void gimp_display_shell_flush (GimpDisplayShell *shell) { diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h index 3afbe3d164..fb4261eaf7 100644 --- a/app/display/gimpdisplayshell.h +++ b/app/display/gimpdisplayshell.h @@ -92,6 +92,8 @@ struct _GimpDisplayShell gboolean show_image; /* whether to show the image */ + gboolean show_all; /* show the entire image */ + Selection *selection; /* Selection (marching ants) */ GList *children; @@ -308,6 +310,13 @@ void gimp_display_shell_set_show_image (GimpDisplayShell *shell, gboolean show_image); +void gimp_display_shell_set_show_all (GimpDisplayShell *shell, + gboolean show_all); + +GimpPickable * gimp_display_shell_get_pickable (GimpDisplayShell *shell); +GeglRectangle gimp_display_shell_get_bounding_box + (GimpDisplayShell *shell); + void gimp_display_shell_flush (GimpDisplayShell *shell); void gimp_display_shell_pause (GimpDisplayShell *shell); diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h index c8da9c1739..720d47dc0f 100644 --- a/app/widgets/gimphelp-ids.h +++ b/app/widgets/gimphelp-ids.h @@ -83,6 +83,7 @@ #define GIMP_HELP_SELECTION_TO_PATH "gimp-selection-to-path" #define GIMP_HELP_VIEW_NEW "gimp-view-new" +#define GIMP_HELP_VIEW_SHOW_ALL "gimp-view-show-all" #define GIMP_HELP_VIEW_DOT_FOR_DOT "gimp-view-dot-for-dot" #define GIMP_HELP_VIEW_SCROLL_CENTER "gimp-view-scroll-center" #define GIMP_HELP_VIEW_ZOOM_REVERT "gimp-view-zoom-revert" diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in index 6b8b6de956..35291ff120 100644 --- a/menus/image-menu.xml.in +++ b/menus/image-menu.xml.in @@ -261,6 +261,7 @@ +