tools: allow on-canvas text editor to move

This commit implements the ability to freely move the on-canvas
text editor across the screen by introducing a drag-and-drop mechanism.
This commit is contained in:
Gabriele Barbero 2025-06-05 21:01:23 +02:00
parent a989cec59c
commit 9afdd3ad04
5 changed files with 131 additions and 3 deletions

View file

@ -1365,6 +1365,11 @@ gimp_display_shell_transform_overlay (GimpDisplayShell *shell,
*x -= requisition.width + overlay->spacing_x; *x -= requisition.width + overlay->spacing_x;
*y -= requisition.height / 2; *y -= requisition.height / 2;
break; break;
default:
*x -= overlay->spacing_x;
*y -= overlay->spacing_y;
break;
} }
} }

View file

@ -128,6 +128,20 @@ static void gimp_text_tool_fix_position (GimpTextTool *text_tool,
static void gimp_text_tool_convert_gdkkeyevent (GimpTextTool *text_tool, static void gimp_text_tool_convert_gdkkeyevent (GimpTextTool *text_tool,
GdkEventKey *kevent); GdkEventKey *kevent);
static gboolean gimp_text_tool_style_overlay_button_press
(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
static gboolean gimp_text_tool_style_overlay_button_release
(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
static gboolean gimp_text_tool_style_overlay_button_motion
(GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data);
#define DEFAULT_DRAG_OFFSET 25
/* public functions */ /* public functions */
@ -214,6 +228,23 @@ gimp_text_tool_editor_start (GimpTextTool *text_tool)
gimp_overlay_box_set_child_opacity (GIMP_OVERLAY_BOX (shell->canvas), gimp_overlay_box_set_child_opacity (GIMP_OVERLAY_BOX (shell->canvas),
text_tool->style_overlay, 0.85); text_tool->style_overlay, 0.85);
gtk_widget_add_events (text_tool->style_overlay,
(GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK));
g_signal_connect_object (text_tool->style_overlay, "button-press-event",
G_CALLBACK (gimp_text_tool_style_overlay_button_press),
text_tool, 0);
g_signal_connect_object (text_tool->style_overlay, "button-release-event",
G_CALLBACK (gimp_text_tool_style_overlay_button_release),
text_tool, 0);
g_signal_connect_object (text_tool->style_overlay, "motion-notify-event",
G_CALLBACK (gimp_text_tool_style_overlay_button_motion),
text_tool, 0);
text_tool->overlay_dragging = FALSE;
if (text_tool->image) if (text_tool->image)
gimp_image_get_resolution (text_tool->image, &xres, &yres); gimp_image_get_resolution (text_tool->image, &xres, &yres);
@ -1893,3 +1924,89 @@ gimp_text_tool_convert_gdkkeyevent (GimpTextTool *text_tool,
break; break;
} }
} }
static gboolean
gimp_text_tool_style_overlay_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (user_data);
GtkWidget *event_widget = gtk_get_event_widget ((GdkEvent*) event);
if (event_widget != GTK_WIDGET (text_tool->style_overlay) &&
gtk_widget_is_ancestor (event_widget, GTK_WIDGET (text_tool->style_editor)))
{
return FALSE;
}
if (gtk_widget_get_window (GTK_WIDGET (text_tool->style_overlay)))
{
GdkCursor *cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (text_tool->style_overlay)),
GDK_FLEUR);
if (cursor)
{
gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (text_tool->style_overlay)),
cursor);
g_object_unref (cursor);
}
}
text_tool->overlay_dragging = TRUE;
text_tool->drag_offset_x = event->x;
text_tool->drag_offset_y = event->y;
return TRUE;
}
static gboolean
gimp_text_tool_style_overlay_button_release (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (user_data);
GtkWidget *event_widget = gtk_get_event_widget ((GdkEvent*) event);
if (event_widget != GTK_WIDGET (text_tool->style_overlay) &&
gtk_widget_is_ancestor (event_widget, GTK_WIDGET (text_tool->style_editor)))
{
return FALSE;
}
text_tool->overlay_dragging = FALSE;
if (gtk_widget_get_window (GTK_WIDGET (text_tool->style_overlay)))
gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (text_tool->style_overlay)), NULL);
return TRUE;
}
static gboolean
gimp_text_tool_style_overlay_button_motion (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (user_data);
if (text_tool->overlay_dragging)
{
GimpTool *tool = GIMP_TOOL (text_tool);
GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
gdouble x, y;
gdk_window_get_device_position_double (gtk_widget_get_window (GTK_WIDGET (shell)),
event->device,
&x, &y, NULL);
gimp_display_shell_untransform_xy_f (shell,
x, y,
&x, &y);
gimp_display_shell_move_overlay (shell,
text_tool->style_overlay,
x, y, -1,
text_tool->drag_offset_x + DEFAULT_DRAG_OFFSET,
text_tool->drag_offset_y + DEFAULT_DRAG_OFFSET);
}
return TRUE;
}

View file

@ -71,6 +71,12 @@ struct _GimpTextTool
GtkWidget *style_overlay; GtkWidget *style_overlay;
GtkWidget *style_editor; GtkWidget *style_editor;
/* style overlay dragging: */
gboolean overlay_dragging;
gdouble drag_offset_x;
gdouble drag_offset_y;
gboolean selecting; gboolean selecting;
GtkTextIter select_start_iter; GtkTextIter select_start_iter;
gboolean select_words; gboolean select_words;

View file

@ -36,7 +36,7 @@ static gboolean gimp_overlay_frame_draw (GtkWidget *widget,
cairo_t *cr); cairo_t *cr);
G_DEFINE_TYPE (GimpOverlayFrame, gimp_overlay_frame, GTK_TYPE_BIN) G_DEFINE_TYPE (GimpOverlayFrame, gimp_overlay_frame, GTK_TYPE_EVENT_BOX)
#define parent_class gimp_overlay_frame_parent_class #define parent_class gimp_overlay_frame_parent_class

View file

@ -35,12 +35,12 @@ typedef struct _GimpOverlayFrameClass GimpOverlayFrameClass;
struct _GimpOverlayFrame struct _GimpOverlayFrame
{ {
GtkBin parent_instance; GtkEventBox parent_instance;
}; };
struct _GimpOverlayFrameClass struct _GimpOverlayFrameClass
{ {
GtkBinClass parent_class; GtkEventBoxClass parent_class;
}; };