diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index ec22d8672e..5e3476c298 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -195,6 +195,11 @@ static void gimp_display_shell_transform_overlay (GimpDisplayShell *shell, static gboolean gimp_display_shell_draw (GimpDisplayShell *shell, cairo_t *cr, gpointer *data); +static void gimp_display_shell_push_overlay_inside_canvas + (GimpDisplayShell *shell, + GtkWidget *child, + gdouble *limits, + gdouble *corners); G_DEFINE_TYPE_WITH_CODE (GimpDisplayShell, gimp_display_shell, @@ -1276,12 +1281,39 @@ gimp_display_shell_overlay_allocate (GtkWidget *child, GtkAllocation *allocation, GimpDisplayShellOverlay *overlay) { - gdouble x, y; + gdouble tlx, tly, brx, bry; + gdouble llimit, rlimit, ulimit, blimit; - gimp_display_shell_transform_overlay (overlay->shell, child, &x, &y); + gimp_ruler_get_range ((GimpRuler *) overlay->shell->hrule, + &llimit, &rlimit, NULL); + gimp_ruler_get_range ((GimpRuler *) overlay->shell->vrule, + &ulimit, &blimit, NULL); - gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (overlay->shell->canvas), - child, x, y); + gimp_display_shell_get_overlay_corners (overlay->shell, + child, + overlay->image_x, overlay->image_y, + &tlx, &tly, + &brx, &bry); + + /* If the overlay is entirely outside the canvas, we push it inside the canvas */ + if (tlx > rlimit || + tly > blimit || + brx < llimit || + bry < ulimit) + { + gimp_display_shell_push_overlay_inside_canvas (overlay->shell, + child, + (gdouble[]) {ulimit, rlimit, blimit, llimit}, + (gdouble[]) {tlx, tly, brx, bry}); + } + else + { + gdouble x, y; + + gimp_display_shell_transform_overlay (overlay->shell, child, &x, &y); + gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (overlay->shell->canvas), + child, x, y); + } } static void @@ -1386,6 +1418,62 @@ gimp_display_shell_draw (GimpDisplayShell *shell, return FALSE; } +static void +gimp_display_shell_push_overlay_inside_canvas (GimpDisplayShell *shell, + GtkWidget *child, + gdouble *limits, + gdouble *corners) +{ + gdouble ulimit, rlimit, blimit, llimit; + gdouble tlx, tly, brx, bry; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (GTK_IS_WIDGET (shell)); + + ulimit = limits[0]; + rlimit = limits[1]; + blimit = limits[2]; + llimit = limits[3]; + + tlx = corners[0]; + tly = corners[1]; + brx = corners[2]; + bry = corners[3]; + + if (brx < llimit) + { + gimp_display_shell_move_overlay (shell, + child, + llimit, tly, + GIMP_HANDLE_ANCHOR_NORTH_WEST, + 0, 0); + } + if (bry < ulimit) + { + gimp_display_shell_move_overlay (shell, + child, + tlx, ulimit, + GIMP_HANDLE_ANCHOR_NORTH_WEST, + 0, 0); + } + if (tlx > rlimit) + { + gimp_display_shell_move_overlay (shell, + child, + rlimit, bry, + GIMP_HANDLE_ANCHOR_SOUTH_EAST, + 0, 0); + } + if (tly > blimit) + { + gimp_display_shell_move_overlay (shell, + child, + brx, blimit, + GIMP_HANDLE_ANCHOR_SOUTH_EAST, + 0, 0); + } +} + /* public functions */ GtkWidget * @@ -2340,3 +2428,96 @@ gimp_display_shell_is_drawn (GimpDisplayShell *shell) { return shell->drawn; } + +/** + * gimp_display_shell_get_overlay_corners: + * @shell: a #GimpDisplayShell + * @child: a child widget of the shell + * @image_x: the x coordinate in image coordinates + * @image_y: the y coordinate in image coordinates + * @top_left_x: return location for the top left x coordinate in image coordinates + * @top_left_y: return location for the top left y coordinate in image coordinates + * @bottom_right_x: return location for the bottom right x coordinate in image coordinates + * @bottom_right_y: return location for the bottom right y coordinate in image coordinates + * + * This function calculates the corners of an overlay widget in image coordinates. + **/ +void +gimp_display_shell_get_overlay_corners (GimpDisplayShell *shell, + GtkWidget *child, + gdouble image_x, + gdouble image_y, + gdouble *top_left_x, + gdouble *top_left_y, + gdouble *bottom_right_x, + gdouble *bottom_right_y) +{ + GimpDisplayShellOverlay *overlay; + GtkRequisition req; + gdouble tl_disp_x, tl_disp_y; + gdouble br_disp_x, br_disp_y; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + overlay = g_object_get_data (G_OBJECT (child), "image-coords-overlay"); + + gimp_display_shell_transform_xy_f (shell, + image_x, image_y, + &tl_disp_x, &tl_disp_y); + + gtk_widget_get_preferred_size (child, &req, NULL); + + switch (overlay->anchor) + { + case GIMP_HANDLE_ANCHOR_CENTER: + tl_disp_x -= req.width / 2; + tl_disp_y -= req.height / 2; + break; + case GIMP_HANDLE_ANCHOR_NORTH: + tl_disp_x -= req.width / 2; + tl_disp_y += overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_NORTH_WEST: + tl_disp_x += overlay->spacing_x; + tl_disp_y += overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_NORTH_EAST: + tl_disp_x -= req.width + overlay->spacing_x; + tl_disp_y += overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_SOUTH: + tl_disp_x -= req.width / 2; + tl_disp_y -= req.height + overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_SOUTH_WEST: + tl_disp_x += overlay->spacing_x; + tl_disp_y -= req.height + overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_SOUTH_EAST: + tl_disp_x -= req.width + overlay->spacing_x; + tl_disp_y -= req.height + overlay->spacing_y; + break; + case GIMP_HANDLE_ANCHOR_WEST: + tl_disp_x += overlay->spacing_x; + tl_disp_y -= req.height / 2; + break; + case GIMP_HANDLE_ANCHOR_EAST: + tl_disp_x -= req.width + overlay->spacing_x; + tl_disp_y -= req.height / 2; + break; + default: + tl_disp_x -= overlay->spacing_x; + tl_disp_y -= overlay->spacing_y; + break; + } + + br_disp_x = tl_disp_x + req.width; + br_disp_y = tl_disp_y + req.height; + + gimp_display_shell_untransform_xy_f (shell, + tl_disp_x, tl_disp_y, + top_left_x, top_left_y); + gimp_display_shell_untransform_xy_f (shell, + br_disp_x, br_disp_y, + bottom_right_x, bottom_right_y); +} diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h index 4137049036..c5b345e485 100644 --- a/app/display/gimpdisplayshell.h +++ b/app/display/gimpdisplayshell.h @@ -363,3 +363,13 @@ void gimp_display_shell_set_mask (GimpDisplayShell *shell, gboolean inverted); gboolean gimp_display_shell_is_drawn (GimpDisplayShell *shell); + +void gimp_display_shell_get_overlay_corners + (GimpDisplayShell *shell, + GtkWidget *child, + gdouble image_x, + gdouble image_y, + gdouble *top_left_x, + gdouble *top_left_y, + gdouble *bottom_right_x, + gdouble *bottom_right_y); diff --git a/app/text/gimptextlayer.c b/app/text/gimptextlayer.c index 3c92994c76..9bc1caccf4 100644 --- a/app/text/gimptextlayer.c +++ b/app/text/gimptextlayer.c @@ -617,6 +617,18 @@ gimp_text_layer_get_style_overlay_position (GimpTextLayer *layer, return TRUE; } +gboolean +gimp_text_layer_is_style_overlay_positioned (GimpTextLayer *layer) +{ + GimpTextLayerPrivate *priv; + + g_return_val_if_fail (GIMP_IS_TEXT_LAYER (layer), FALSE); + + priv = layer->private; + + return priv->style_overlay_positioned; +} + void gimp_text_layer_set_style_overlay_offset (GimpTextLayer *layer, gdouble offset_x, diff --git a/app/text/gimptextlayer.h b/app/text/gimptextlayer.h index 2618f537fe..07b7bbe420 100644 --- a/app/text/gimptextlayer.h +++ b/app/text/gimptextlayer.h @@ -80,6 +80,8 @@ gboolean gimp_text_layer_get_style_overlay_position (GimpTextLayer *layer, gdouble *x, gdouble *y); +gboolean gimp_text_layer_is_style_overlay_positioned + (GimpTextLayer *layer); void gimp_text_layer_set_style_overlay_offset (GimpTextLayer *layer, gdouble offset_x, diff --git a/app/tools/gimptexttool-editor.c b/app/tools/gimptexttool-editor.c index 6a2c3595ff..a7519ab2cb 100644 --- a/app/tools/gimptexttool-editor.c +++ b/app/tools/gimptexttool-editor.c @@ -2076,6 +2076,8 @@ gimp_text_tool_style_overlay_button_motion (GtkWidget *widget, GimpTool *tool = GIMP_TOOL (text_tool); GimpDisplayShell *shell = gimp_display_get_shell (tool->display); GimpTextStyleEditor *style_editor; + gdouble llimit, rlimit, ulimit, blimit; + gdouble tlx, tly, brx, bry; gdouble x, y; gdouble x_off, y_off; @@ -2089,6 +2091,33 @@ gimp_text_tool_style_overlay_button_motion (GtkWidget *widget, x, y, &x, &y); + gimp_ruler_get_range ((GimpRuler *) shell->hrule, + &llimit, &rlimit, NULL); + gimp_ruler_get_range ((GimpRuler *) shell->vrule, + &ulimit, &blimit, NULL); + + gimp_display_shell_get_overlay_corners (shell, text_tool->style_overlay, + x, y, + &tlx, &tly, + &brx, &bry); + + /* If the overlay is being dragged, we need to check if it is still + * within the image bounds. If it is not, we adjust the coordinates. + * This is to prevent the overlay from being dragged outside the image + * bounds, which would cause it to be lost. + */ + if (gimp_text_layer_is_style_overlay_positioned (text_tool->layer)) + { + if (tlx < llimit) + x += (llimit - tlx); + if (tly < ulimit) + y += (ulimit - tly); + if (brx > rlimit) + x -= (brx - rlimit); + if (bry > blimit) + y -= (bry - blimit); + } + gimp_display_shell_move_overlay (shell, text_tool->style_overlay, x, y, -1,