From 57eaf91fbc95ea6aaa7206a882eb6d845279ae15 Mon Sep 17 00:00:00 2001 From: Ell Date: Mon, 3 Feb 2020 12:14:08 +0200 Subject: [PATCH] app: improve empty-selection check in GimpSelectionTool Add a new GimpSelectionTool::have_selection() virtual function, which determines if the image has a selection (default implementation), or if the tool will create one upon committing (implemented by subclasses). Use this function in gimp_selection_tool_oper_update() to determine the tool function; in particular, don't use SELECTION_MOVE and SELECTION_MOVE_COPY when there's no selection. Override have_selection() in GimpFreeSelectTool, and return TRUE if we have a polygon with three or more vertices, which will create a selection upon committing. --- app/tools/gimpfreeselecttool.c | 27 ++++++++++ app/tools/gimpselectiontool.c | 93 +++++++++++++++++++++------------- app/tools/gimpselectiontool.h | 4 ++ 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/app/tools/gimpfreeselecttool.c b/app/tools/gimpfreeselecttool.c index 71baa00b0c..c97096fc01 100644 --- a/app/tools/gimpfreeselecttool.c +++ b/app/tools/gimpfreeselecttool.c @@ -73,6 +73,9 @@ static void gimp_free_select_tool_options_notify (GimpTool * GimpToolOptions *options, const GParamSpec *pspec); +static gboolean gimp_free_select_tool_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display); + static void gimp_free_select_tool_change_complete (GimpPolygonSelectTool *poly_sel, GimpDisplay *display); @@ -112,6 +115,7 @@ static void gimp_free_select_tool_class_init (GimpFreeSelectToolClass *klass) { GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass); + GimpSelectionToolClass *sel_class = GIMP_SELECTION_TOOL_CLASS (klass); GimpPolygonSelectToolClass *poly_sel_class = GIMP_POLYGON_SELECT_TOOL_CLASS (klass); tool_class->control = gimp_free_select_tool_control; @@ -119,6 +123,8 @@ gimp_free_select_tool_class_init (GimpFreeSelectToolClass *klass) tool_class->button_release = gimp_free_select_tool_button_release; tool_class->options_notify = gimp_free_select_tool_options_notify; + sel_class->have_selection = gimp_free_select_tool_have_selection; + poly_sel_class->change_complete = gimp_free_select_tool_change_complete; } @@ -248,6 +254,27 @@ gimp_free_select_tool_options_notify (GimpTool *tool, GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec); } +static gboolean +gimp_free_select_tool_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display) +{ + GimpPolygonSelectTool *poly_sel = GIMP_POLYGON_SELECT_TOOL (sel_tool); + GimpTool *tool = GIMP_TOOL (sel_tool); + + if (display == tool->display) + { + gint n_points; + + gimp_polygon_select_tool_get_points (poly_sel, NULL, &n_points); + + if (n_points > 2) + return TRUE; + } + + return GIMP_SELECTION_TOOL_CLASS (parent_class)->have_selection (sel_tool, + display); +} + static void gimp_free_select_tool_change_complete (GimpPolygonSelectTool *poly_sel, GimpDisplay *display) diff --git a/app/tools/gimpselectiontool.c b/app/tools/gimpselectiontool.c index ba94752f70..3029a38ac1 100644 --- a/app/tools/gimpselectiontool.c +++ b/app/tools/gimpselectiontool.c @@ -46,34 +46,40 @@ #include "gimp-intl.h" -static void gimp_selection_tool_control (GimpTool *tool, - GimpToolAction action, - GimpDisplay *display); -static void gimp_selection_tool_modifier_key (GimpTool *tool, - GdkModifierType key, - gboolean press, - GdkModifierType state, - GimpDisplay *display); -static void gimp_selection_tool_oper_update (GimpTool *tool, - const GimpCoords *coords, - GdkModifierType state, - gboolean proximity, - GimpDisplay *display); -static void gimp_selection_tool_cursor_update (GimpTool *tool, - const GimpCoords *coords, - GdkModifierType state, - GimpDisplay *display); +static void gimp_selection_tool_control (GimpTool *tool, + GimpToolAction action, + GimpDisplay *display); +static void gimp_selection_tool_modifier_key (GimpTool *tool, + GdkModifierType key, + gboolean press, + GdkModifierType state, + GimpDisplay *display); +static void gimp_selection_tool_oper_update (GimpTool *tool, + const GimpCoords *coords, + GdkModifierType state, + gboolean proximity, + GimpDisplay *display); +static void gimp_selection_tool_cursor_update (GimpTool *tool, + const GimpCoords *coords, + GdkModifierType state, + GimpDisplay *display); -static void gimp_selection_tool_commit (GimpSelectionTool *sel_tool); -static void gimp_selection_tool_halt (GimpSelectionTool *sel_tool, - GimpDisplay *display); +static gboolean gimp_selection_tool_real_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display); -static gboolean gimp_selection_tool_check (GimpSelectionTool *sel_tool, - GimpDisplay *display, - GError **error); +static void gimp_selection_tool_commit (GimpSelectionTool *sel_tool); +static void gimp_selection_tool_halt (GimpSelectionTool *sel_tool, + GimpDisplay *display); -static void gimp_selection_tool_set_undo_ptr (GimpUndo **undo_ptr, - GimpUndo *undo); +static gboolean gimp_selection_tool_check (GimpSelectionTool *sel_tool, + GimpDisplay *display, + GError **error); + +static gboolean gimp_selection_tool_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display); + +static void gimp_selection_tool_set_undo_ptr (GimpUndo **undo_ptr, + GimpUndo *undo); G_DEFINE_TYPE (GimpSelectionTool, gimp_selection_tool, GIMP_TYPE_DRAW_TOOL) @@ -91,6 +97,8 @@ gimp_selection_tool_class_init (GimpSelectionToolClass *klass) tool_class->key_press = gimp_edit_selection_tool_key_press; tool_class->oper_update = gimp_selection_tool_oper_update; tool_class->cursor_update = gimp_selection_tool_cursor_update; + + klass->have_selection = gimp_selection_tool_real_have_selection; } static void @@ -210,18 +218,16 @@ gimp_selection_tool_oper_update (GimpTool *tool, GimpSelectionTool *selection_tool = GIMP_SELECTION_TOOL (tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpImage *image; - GimpChannel *selection; GimpDrawable *drawable; GimpLayer *layer; GimpLayer *floating_sel; GdkModifierType extend_mask; GdkModifierType modify_mask; + gboolean have_selection; gboolean move_layer = FALSE; gboolean move_floating_sel = FALSE; - gboolean selection_empty; image = gimp_display_get_image (display); - selection = gimp_image_get_mask (image); drawable = gimp_image_get_active_drawable (image); layer = gimp_image_pick_layer (image, coords->x, coords->y, NULL); floating_sel = gimp_image_get_floating_selection (image); @@ -229,6 +235,8 @@ gimp_selection_tool_oper_update (GimpTool *tool, extend_mask = gimp_get_extend_selection_mask (); modify_mask = gimp_get_modify_selection_mask (); + have_selection = gimp_selection_tool_have_selection (selection_tool, display); + if (drawable) { if (floating_sel) @@ -236,15 +244,14 @@ gimp_selection_tool_oper_update (GimpTool *tool, if (layer == floating_sel) move_floating_sel = TRUE; } - else if (gimp_item_mask_intersect (GIMP_ITEM (drawable), + else if (have_selection && + gimp_item_mask_intersect (GIMP_ITEM (drawable), NULL, NULL, NULL, NULL)) { move_layer = TRUE; } } - selection_empty = gimp_channel_is_empty (selection); - selection_tool->function = SELECTION_SELECT; if (selection_tool->allow_move && @@ -260,7 +267,7 @@ gimp_selection_tool_oper_update (GimpTool *tool, selection_tool->function = SELECTION_MOVE_COPY; } else if (selection_tool->allow_move && - (state & GDK_MOD1_MASK) && ! selection_empty) + (state & GDK_MOD1_MASK) && have_selection) { /* move the selection mask */ selection_tool->function = SELECTION_MOVE_MASK; @@ -291,7 +298,7 @@ gimp_selection_tool_oper_update (GimpTool *tool, gboolean free_status = FALSE; GdkModifierType modifiers = (extend_mask | modify_mask); - if (! selection_empty) + if (have_selection) modifiers |= GDK_MOD1_MASK; switch (selection_tool->function) @@ -300,7 +307,7 @@ gimp_selection_tool_oper_update (GimpTool *tool, switch (options->operation) { case GIMP_CHANNEL_OP_REPLACE: - if (! selection_empty) + if (have_selection) { status = gimp_suggest_modifiers (_("Click-Drag to replace the " "current selection"), @@ -439,6 +446,16 @@ gimp_selection_tool_cursor_update (GimpTool *tool, modifier); } +static gboolean +gimp_selection_tool_real_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display) +{ + GimpImage *image = gimp_display_get_image (display); + GimpChannel *selection = gimp_image_get_mask (image); + + return ! gimp_channel_is_empty (selection); +} + static void gimp_selection_tool_commit (GimpSelectionTool *sel_tool) { @@ -550,6 +567,14 @@ gimp_selection_tool_check (GimpSelectionTool *sel_tool, return TRUE; } +static gboolean +gimp_selection_tool_have_selection (GimpSelectionTool *sel_tool, + GimpDisplay *display) +{ + return GIMP_SELECTION_TOOL_GET_CLASS (sel_tool)->have_selection (sel_tool, + display); +} + static void gimp_selection_tool_set_undo_ptr (GimpUndo **undo_ptr, GimpUndo *undo) diff --git a/app/tools/gimpselectiontool.h b/app/tools/gimpselectiontool.h index e56db3c679..077605691c 100644 --- a/app/tools/gimpselectiontool.h +++ b/app/tools/gimpselectiontool.h @@ -54,6 +54,10 @@ struct _GimpSelectionTool struct _GimpSelectionToolClass { GimpDrawToolClass parent_class; + + /* virtual functions */ + gboolean (* have_selection) (GimpSelectionTool *sel_tool, + GimpDisplay *display); };