diff --git a/app/display/gimpnavigationeditor.c b/app/display/gimpnavigationeditor.c index 1b7a1603de..45be1fa064 100644 --- a/app/display/gimpnavigationeditor.c +++ b/app/display/gimpnavigationeditor.c @@ -36,6 +36,7 @@ #include "core/gimp.h" #include "core/gimpcontext.h" #include "core/gimpimage.h" +#include "core/gimpimageviewable.h" #include "widgets/gimpdocked.h" #include "widgets/gimphelp-ids.h" @@ -46,6 +47,7 @@ #include "gimpdisplay.h" #include "gimpdisplayshell.h" +#include "gimpdisplayshell-appearance.h" #include "gimpdisplayshell-scale.h" #include "gimpdisplayshell-scroll.h" #include "gimpdisplayshell-transform.h" @@ -57,46 +59,57 @@ #define UPDATE_DELAY 300 /* From GtkRange in GTK+ 2.22 */ -static void gimp_navigation_editor_docked_iface_init (GimpDockedInterface *iface); +static void gimp_navigation_editor_docked_iface_init (GimpDockedInterface *iface); -static void gimp_navigation_editor_dispose (GObject *object); +static void gimp_navigation_editor_dispose (GObject *object); -static void gimp_navigation_editor_set_context (GimpDocked *docked, - GimpContext *context); +static void gimp_navigation_editor_set_context (GimpDocked *docked, + GimpContext *context); -static GtkWidget * gimp_navigation_editor_new_private (GimpMenuFactory *menu_factory, - GimpDisplayShell *shell); +static GtkWidget * gimp_navigation_editor_new_private (GimpMenuFactory *menu_factory, + GimpDisplayShell *shell); -static void gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, - GimpDisplayShell *shell); -static gboolean gimp_navigation_editor_button_release (GtkWidget *widget, - GdkEventButton *bevent, - GimpDisplayShell *shell); -static void gimp_navigation_editor_marker_changed (GimpNavigationView *view, - gdouble center_x, - gdouble center_y, - gdouble width, - gdouble height, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_zoom (GimpNavigationView *view, - GimpZoomType direction, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_scroll (GimpNavigationView *view, - GdkScrollDirection direction, - GimpNavigationEditor *editor); +static void gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, + GimpDisplayShell *shell); +static gboolean gimp_navigation_editor_button_release (GtkWidget *widget, + GdkEventButton *bevent, + GimpDisplayShell *shell); +static void gimp_navigation_editor_marker_changed (GimpNavigationView *view, + gdouble center_x, + gdouble center_y, + gdouble width, + gdouble height, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_zoom (GimpNavigationView *view, + GimpZoomType direction, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_scroll (GimpNavigationView *view, + GdkScrollDirection direction, + GimpNavigationEditor *editor); -static void gimp_navigation_editor_zoom_adj_changed (GtkAdjustment *adj, - GimpNavigationEditor *editor); +static void gimp_navigation_editor_zoom_adj_changed (GtkAdjustment *adj, + GimpNavigationEditor *editor); -static void gimp_navigation_editor_shell_scaled (GimpDisplayShell *shell, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_shell_scrolled (GimpDisplayShell *shell, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_shell_rotated (GimpDisplayShell *shell, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_shell_reconnect (GimpDisplayShell *shell, - GimpNavigationEditor *editor); -static void gimp_navigation_editor_update_marker (GimpNavigationEditor *editor); +static void gimp_navigation_editor_shell_show_all_notify (GimpDisplayShell *shell, + const GParamSpec *pspec, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_shell_scaled (GimpDisplayShell *shell, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_shell_scrolled (GimpDisplayShell *shell, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_shell_rotated (GimpDisplayShell *shell, + GimpNavigationEditor *editor); +static void gimp_navigation_editor_shell_reconnect (GimpDisplayShell *shell, + GimpNavigationEditor *editor); + +static void gimp_navigation_editor_viewable_size_changed (GimpViewable *viewable, + GimpNavigationEditor *editor); + +static void gimp_navigation_editor_options_show_canvas_notify (GimpDisplayOptions *options, + const GParamSpec *pspec, + GimpNavigationEditor *editor); + +static void gimp_navigation_editor_update_marker (GimpNavigationEditor *editor); G_DEFINE_TYPE_WITH_CODE (GimpNavigationEditor, gimp_navigation_editor, @@ -137,7 +150,7 @@ gimp_navigation_editor_init (GimpNavigationEditor *editor) editor->view = gimp_view_new_by_types (NULL, GIMP_TYPE_NAVIGATION_VIEW, - GIMP_TYPE_IMAGE, + GIMP_TYPE_IMAGE_VIEWABLE, GIMP_VIEW_SIZE_MEDIUM, 0, TRUE); gtk_container_add (GTK_CONTAINER (frame), editor->view); gtk_widget_show (editor->view); @@ -459,6 +472,9 @@ gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, if (editor->shell) { + g_signal_handlers_disconnect_by_func (editor->shell, + gimp_navigation_editor_shell_show_all_notify, + editor); g_signal_handlers_disconnect_by_func (editor->shell, gimp_navigation_editor_shell_scaled, editor); @@ -471,6 +487,13 @@ gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, g_signal_handlers_disconnect_by_func (editor->shell, gimp_navigation_editor_shell_reconnect, editor); + + g_signal_handlers_disconnect_by_func (editor->shell->options, + gimp_navigation_editor_options_show_canvas_notify, + editor); + g_signal_handlers_disconnect_by_func (editor->shell->fullscreen_options, + gimp_navigation_editor_options_show_canvas_notify, + editor); } else if (shell) { @@ -483,9 +506,24 @@ gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, { GimpImage *image = gimp_display_get_image (shell->display); - gimp_view_set_viewable (GIMP_VIEW (editor->view), - GIMP_VIEWABLE (image)); + g_clear_object (&editor->image_viewable); + if (image) + { + editor->image_viewable = gimp_image_viewable_new (image); + + g_signal_connect ( + editor->image_viewable, "size-changed", + G_CALLBACK (gimp_navigation_editor_viewable_size_changed), + editor); + } + + gimp_view_set_viewable (GIMP_VIEW (editor->view), + GIMP_VIEWABLE (editor->image_viewable)); + + g_signal_connect (editor->shell, "notify::show-all", + G_CALLBACK (gimp_navigation_editor_shell_show_all_notify), + editor); g_signal_connect (editor->shell, "scaled", G_CALLBACK (gimp_navigation_editor_shell_scaled), editor); @@ -499,12 +537,21 @@ gimp_navigation_editor_set_shell (GimpNavigationEditor *editor, G_CALLBACK (gimp_navigation_editor_shell_reconnect), editor); + g_signal_connect (editor->shell->options, "notify::show-canvas-boundary", + G_CALLBACK (gimp_navigation_editor_options_show_canvas_notify), + editor); + g_signal_connect (editor->shell->fullscreen_options, "notify::show-canvas-boundary", + G_CALLBACK (gimp_navigation_editor_options_show_canvas_notify), + editor); + gimp_navigation_editor_shell_scaled (editor->shell, editor); } else { gimp_view_set_viewable (GIMP_VIEW (editor->view), NULL); gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE); + + g_clear_object (&editor->image_viewable); } if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor))) @@ -533,11 +580,23 @@ gimp_navigation_editor_marker_changed (GimpNavigationView *view, gdouble height, GimpNavigationEditor *editor) { + GimpViewRenderer *renderer = GIMP_VIEW (editor->view)->renderer; + if (editor->shell) { if (gimp_display_get_image (editor->shell->display)) - gimp_display_shell_scroll_center_image_xy (editor->shell, - center_x, center_y); + { + GeglRectangle bounding_box; + + bounding_box = gimp_image_viewable_get_bounding_box ( + GIMP_IMAGE_VIEWABLE (renderer->viewable)); + + center_x += bounding_box.x; + center_y += bounding_box.y; + + gimp_display_shell_scroll_center_image_xy (editor->shell, + center_x, center_y); + } } } @@ -637,6 +696,18 @@ gimp_navigation_editor_zoom_adj_changed (GtkAdjustment *adj, editor); } +static void +gimp_navigation_editor_shell_show_all_notify (GimpDisplayShell *shell, + const GParamSpec *pspec, + GimpNavigationEditor *editor) +{ + gimp_navigation_editor_update_marker (editor); + + if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor))) + gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (editor)), + gimp_editor_get_popup_data (GIMP_EDITOR (editor))); +} + static void gimp_navigation_editor_shell_scaled (GimpDisplayShell *shell, GimpNavigationEditor *editor) @@ -698,14 +769,45 @@ gimp_navigation_editor_shell_rotated (GimpDisplayShell *shell, gimp_editor_get_popup_data (GIMP_EDITOR (editor))); } +static void +gimp_navigation_editor_viewable_size_changed (GimpViewable *viewable, + GimpNavigationEditor *editor) +{ + gimp_navigation_editor_update_marker (editor); + + if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor))) + gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (editor)), + gimp_editor_get_popup_data (GIMP_EDITOR (editor))); +} + +static void +gimp_navigation_editor_options_show_canvas_notify (GimpDisplayOptions *options, + const GParamSpec *pspec, + GimpNavigationEditor *editor) +{ + gimp_navigation_editor_update_marker (editor); +} + static void gimp_navigation_editor_shell_reconnect (GimpDisplayShell *shell, GimpNavigationEditor *editor) { GimpImage *image = gimp_display_get_image (shell->display); + g_clear_object (&editor->image_viewable); + + if (image) + { + editor->image_viewable = gimp_image_viewable_new (image); + + g_signal_connect ( + editor->image_viewable, "size-changed", + G_CALLBACK (gimp_navigation_editor_viewable_size_changed), + editor); + } + gimp_view_set_viewable (GIMP_VIEW (editor->view), - GIMP_VIEWABLE (image)); + GIMP_VIEWABLE (editor->image_viewable)); if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor))) gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (editor)), @@ -724,19 +826,40 @@ gimp_navigation_editor_update_marker (GimpNavigationEditor *editor) if (renderer->viewable) { GimpNavigationView *view = GIMP_NAVIGATION_VIEW (editor->view); + GimpImage *image; + GeglRectangle bounding_box; gdouble x, y; gdouble w, h; + image = gimp_image_viewable_get_image ( + GIMP_IMAGE_VIEWABLE (renderer->viewable)); + + gimp_image_viewable_set_show_all ( + GIMP_IMAGE_VIEWABLE (renderer->viewable), + shell->show_all); + + bounding_box = gimp_image_viewable_get_bounding_box ( + GIMP_IMAGE_VIEWABLE (renderer->viewable)); + gimp_display_shell_scroll_get_viewport (shell, &x, &y, &w, &h); gimp_display_shell_untransform_xy_f (shell, shell->disp_width / 2, shell->disp_height / 2, &x, &y); + x -= bounding_box.x; + y -= bounding_box.y; + gimp_navigation_view_set_marker (view, x, y, w, h, shell->flip_horizontally, shell->flip_vertically, shell->rotate_angle); + + gimp_navigation_view_set_canvas ( + view, + shell->show_all && gimp_display_shell_get_show_canvas (shell), + -bounding_box.x, -bounding_box.y, + gimp_image_get_width (image), gimp_image_get_height (image)); } } diff --git a/app/display/gimpnavigationeditor.h b/app/display/gimpnavigationeditor.h index 83836355b7..90b8d399cc 100644 --- a/app/display/gimpnavigationeditor.h +++ b/app/display/gimpnavigationeditor.h @@ -40,23 +40,25 @@ typedef struct _GimpNavigationEditorClass GimpNavigationEditorClass; struct _GimpNavigationEditor { - GimpEditor parent_instance; + GimpEditor parent_instance; - GimpContext *context; - GimpDisplayShell *shell; + GimpContext *context; + GimpDisplayShell *shell; - GtkWidget *view; - GtkWidget *zoom_label; - GtkAdjustment *zoom_adjustment; + GimpImageViewable *image_viewable; - GtkWidget *zoom_out_button; - GtkWidget *zoom_in_button; - GtkWidget *zoom_100_button; - GtkWidget *zoom_fit_in_button; - GtkWidget *zoom_fill_button; - GtkWidget *shrink_wrap_button; + GtkWidget *view; + GtkWidget *zoom_label; + GtkAdjustment *zoom_adjustment; - guint scale_timeout; + GtkWidget *zoom_out_button; + GtkWidget *zoom_in_button; + GtkWidget *zoom_100_button; + GtkWidget *zoom_fit_in_button; + GtkWidget *zoom_fill_button; + GtkWidget *shrink_wrap_button; + + guint scale_timeout; }; struct _GimpNavigationEditorClass diff --git a/app/widgets/gimpnavigationview.c b/app/widgets/gimpnavigationview.c index 731cb90b63..d3edfd1cf5 100644 --- a/app/widgets/gimpnavigationview.c +++ b/app/widgets/gimpnavigationview.c @@ -36,6 +36,8 @@ #include "core/gimpimage.h" #include "core/gimpmarshal.h" +#include "display/gimpcanvas-style.h" + #include "gimpnavigationview.h" #include "gimpviewrenderer.h" #include "gimpwidgets-utils.h" @@ -66,12 +68,23 @@ struct _GimpNavigationView gboolean flip_vertically; gdouble rotate_angle; + gboolean canvas_visible; + gdouble canvas_x; + gdouble canvas_y; + gdouble canvas_width; + gdouble canvas_height; + /* values in view coordinates */ gint p_center_x; gint p_center_y; gint p_width; gint p_height; + gint p_canvas_x; + gint p_canvas_y; + gint p_canvas_width; + gint p_canvas_height; + gint motion_offset_x; gint motion_offset_y; gboolean has_grab; @@ -177,11 +190,22 @@ gimp_navigation_view_init (GimpNavigationView *view) view->flip_vertically = FALSE; view->rotate_angle = 0.0; + view->canvas_visible = FALSE; + view->canvas_x = 0.0; + view->canvas_y = 0.0; + view->canvas_width = 0.0; + view->canvas_height = 0.0; + view->p_center_x = 0; view->p_center_y = 0; view->p_width = 0; view->p_height = 0; + view->p_canvas_x = 0; + view->p_canvas_y = 0; + view->p_canvas_width = 0; + view->p_canvas_height = 0; + view->motion_offset_x = 0; view->motion_offset_y = 0; view->has_grab = FALSE; @@ -464,6 +488,34 @@ gimp_navigation_view_set_marker (GimpNavigationView *nav_view, gtk_widget_queue_draw (GTK_WIDGET (view)); } +void +gimp_navigation_view_set_canvas (GimpNavigationView *nav_view, + gboolean visible, + gdouble x, + gdouble y, + gdouble width, + gdouble height) +{ + GimpView *view; + + g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (nav_view)); + + view = GIMP_VIEW (nav_view); + + g_return_if_fail (view->renderer->viewable); + + nav_view->canvas_visible = visible; + nav_view->canvas_x = x; + nav_view->canvas_y = y; + nav_view->canvas_width = MAX (1.0, width); + nav_view->canvas_height = MAX (1.0, height); + + gimp_navigation_view_transform (nav_view); + + /* Marker changed, redraw */ + gtk_widget_queue_draw (GTK_WIDGET (view)); +} + void gimp_navigation_view_set_motion_offset (GimpNavigationView *view, gint motion_offset_x, @@ -505,6 +557,12 @@ gimp_navigation_view_transform (GimpNavigationView *nav_view) nav_view->p_width = ceil (nav_view->width * ratiox); nav_view->p_height = ceil (nav_view->height * ratioy); + + nav_view->p_canvas_x = RINT (nav_view->canvas_x * ratiox); + nav_view->p_canvas_y = RINT (nav_view->canvas_y * ratioy); + + nav_view->p_canvas_width = ceil (nav_view->canvas_width * ratiox); + nav_view->p_canvas_height = ceil (nav_view->canvas_height * ratioy); } static void @@ -515,11 +573,12 @@ gimp_navigation_view_draw_marker (GimpNavigationView *nav_view, if (view->renderer->viewable && nav_view->width && nav_view->height) { - GtkWidget *widget = GTK_WIDGET (view); - GtkAllocation allocation; - gint p_width_2; - gint p_height_2; - gdouble angle; + GtkWidget *widget = GTK_WIDGET (view); + GtkAllocation allocation; + cairo_matrix_t matrix; + gint p_width_2; + gint p_height_2; + gdouble angle; p_width_2 = nav_view->p_width / 2; p_height_2 = nav_view->p_height / 2; @@ -531,6 +590,9 @@ gimp_navigation_view_draw_marker (GimpNavigationView *nav_view, gtk_widget_get_allocation (widget, &allocation); cairo_translate (cr, allocation.x, allocation.y); + + cairo_get_matrix (cr, &matrix); + cairo_rectangle (cr, 0, 0, allocation.width, allocation.height); @@ -544,6 +606,24 @@ gimp_navigation_view_draw_marker (GimpNavigationView *nav_view, cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_fill (cr); + if (nav_view->canvas_visible && + nav_view->canvas_width && nav_view->canvas_height) + { + cairo_save (cr); + + cairo_set_matrix (cr, &matrix); + + cairo_rectangle (cr, + nav_view->p_canvas_x + 0.5, + nav_view->p_canvas_y + 0.5, + nav_view->p_canvas_width - 1.0, + nav_view->p_canvas_height - 1.0); + gimp_canvas_set_canvas_style (GTK_WIDGET (nav_view), cr, 0, 0); + cairo_stroke (cr); + + cairo_restore (cr); + } + cairo_rectangle (cr, -p_width_2, -p_height_2, nav_view->p_width, nav_view->p_height); @@ -581,14 +661,13 @@ gimp_navigation_view_get_ratio (GimpNavigationView *nav_view, gdouble *ratioy) { GimpView *view = GIMP_VIEW (nav_view); - GimpImage *image; + gint width; + gint height; - image = GIMP_IMAGE (view->renderer->viewable); + gimp_viewable_get_size (view->renderer->viewable, &width, &height); - *ratiox = (gdouble) view->renderer->width / - (gdouble) gimp_image_get_width (image); - *ratioy = (gdouble) view->renderer->height / - (gdouble) gimp_image_get_height (image); + *ratiox = (gdouble) view->renderer->width / (gdouble) width; + *ratioy = (gdouble) view->renderer->height / (gdouble) height; } static gboolean diff --git a/app/widgets/gimpnavigationview.h b/app/widgets/gimpnavigationview.h index 213ff25af2..06c1318b8a 100644 --- a/app/widgets/gimpnavigationview.h +++ b/app/widgets/gimpnavigationview.h @@ -63,6 +63,12 @@ void gimp_navigation_view_set_marker (GimpNavigationView *view, gboolean flip_horizontally, gboolean flip_vertically, gdouble rotate_angle); +void gimp_navigation_view_set_canvas (GimpNavigationView *view, + gboolean visible, + gdouble x, + gdouble y, + gdouble width, + gdouble height); void gimp_navigation_view_set_motion_offset (GimpNavigationView *view, gint motion_offset_x,