app: use the same mode box in Paint Select as in other Selection tools.

To avoid duplicating code, I make a friend function to be reusable in
Paint Select options code: gimp_selection_options_get_mode_box().

I also get rid of GimpPaintSelectMode enum, which was clearly a
duplicate type to GimpChannelOps. Right now only ADD and SUBTRACT are
supported in Paint Select tool, yet we are perfectly able to generate
widgets showing only partial data. Which is what I do here by adding
appropriate min/max value args to the new function.

Note though that I don't see why we should not be able to replace or
intersect using Paint Select. But since these 2 modes are not
implemented right now, I haven't tried to add support in this commit.
For now, only making our GUI consistent so that Paint Select looks like
any other selection tools (simply only with 2 modes).
This commit is contained in:
Jehan 2025-11-27 22:16:00 +01:00
parent e97c9af519
commit 046c8f2745
8 changed files with 170 additions and 233 deletions

View file

@ -26,12 +26,11 @@
#include "tools-types.h"
#include "widgets/gimppropwidgets.h"
#include "widgets/gimpwidgets-constructors.h"
#include "widgets/gimpwidgets-utils.h"
#include "core/gimptooloptions.h"
#include "gimppaintselectoptions.h"
#include "gimpselectionoptions.h"
#include "gimptooloptions-gui.h"
#include "gimp-intl.h"
@ -40,7 +39,7 @@
enum
{
PROP_0,
PROP_MODE,
PROP_OPERATION,
PROP_STROKE_WIDTH,
PROP_SHOW_SCRIBBLES,
};
@ -68,13 +67,11 @@ gimp_paint_select_options_class_init (GimpPaintSelectOptionsClass *klass)
object_class->set_property = gimp_paint_select_options_set_property;
object_class->get_property = gimp_paint_select_options_get_property;
GIMP_CONFIG_PROP_ENUM (object_class, PROP_MODE,
"mode",
_("Mode"),
_("Paint over areas to mark pixels for "
"inclusion or exclusion from selection"),
GIMP_TYPE_PAINT_SELECT_MODE,
GIMP_PAINT_SELECT_MODE_ADD,
GIMP_CONFIG_PROP_ENUM (object_class, PROP_OPERATION,
"operation",
NULL, NULL,
GIMP_TYPE_CHANNEL_OPS,
GIMP_CHANNEL_OP_ADD,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_INT (object_class, PROP_STROKE_WIDTH,
@ -107,8 +104,8 @@ gimp_paint_select_options_set_property (GObject *object,
switch (property_id)
{
case PROP_MODE:
options->mode = g_value_get_enum (value);
case PROP_OPERATION:
options->operation = g_value_get_enum (value);
break;
case PROP_STROKE_WIDTH:
@ -135,8 +132,8 @@ gimp_paint_select_options_get_property (GObject *object,
switch (property_id)
{
case PROP_MODE:
g_value_set_enum (value, options->mode);
case PROP_OPERATION:
g_value_set_enum (value, options->operation);
break;
case PROP_STROKE_WIDTH:
@ -167,54 +164,20 @@ gimp_paint_select_options_gui (GimpToolOptions *tool_options)
GtkWidget *vbox = gimp_tool_options_gui (tool_options);
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *frame;
GList *children;
GList *radio_children;
GList *list;
GtkWidget *scale;
gint i;
frame = gimp_prop_enum_radio_frame_new (config, "mode", NULL,
0, 0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
/* Mode box */
hbox = gimp_selection_options_get_mode_box (tool_options,
GIMP_CHANNEL_OP_ADD,
GIMP_CHANNEL_OP_SUBTRACT);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* stroke width */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_set_visible (hbox, TRUE);
/* add modifier to tooltips */
children = gtk_container_get_children (GTK_CONTAINER (frame));
radio_children = gtk_container_get_children (GTK_CONTAINER (children->data));
for (list = radio_children, i = 0; list; list = list->next, i++)
{
GtkWidget *button = list->data;
const gchar *modifier = NULL;
const gchar *label = NULL;
if (i == 0)
modifier = gimp_get_mod_string (gimp_get_extend_selection_mask ());
else if (i == 1)
modifier = gimp_get_mod_string (gimp_get_modify_selection_mask ());
if (! modifier)
continue;
label = gtk_button_get_label (GTK_BUTTON (button));
if (label)
{
gchar *tip = g_strdup_printf ("%s <b>%s</b>", label, modifier);
gimp_help_set_help_data_with_markup (button, tip, NULL);
g_free (tip);
}
}
g_list_free (children);
g_list_free (radio_children);
g_list_free (list);
/* stroke width */
scale = gimp_prop_spin_scale_new (config, "stroke-width",
1.0, 10.0, 2);
gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 1.0, 1000.0);

View file

@ -35,7 +35,7 @@ struct _GimpPaintSelectOptions
{
GimpToolOptions parent_instance;
GimpPaintSelectMode mode;
GimpChannelOps operation;
gint stroke_width;
gboolean show_scribbles;
};

View file

@ -250,7 +250,7 @@ gimp_paint_select_tool_button_press (GimpTool *tool,
/* Always reset the "scribbles" to start with a blank slate. */
gegl_buffer_set_color (ps_tool->trimap, NULL, grey);
if (options->mode == GIMP_PAINT_SELECT_MODE_ADD)
if (options->operation == GIMP_CHANNEL_OP_ADD)
{
gegl_node_set (ps_tool->ps_node, "mode", 0, NULL);
gegl_node_set (ps_tool->threshold_node, "value", 0.99, NULL);
@ -260,7 +260,7 @@ gimp_paint_select_tool_button_press (GimpTool *tool,
gegl_node_set (ps_tool->ps_node, "mode", 1, NULL);
gegl_node_set (ps_tool->threshold_node, "value", 0.01, NULL);
}
ps_tool->painting_mode = options->mode;
ps_tool->painting_op = options->operation;
ps_tool->process = gimp_paint_select_tool_paint_scribble (ps_tool);
@ -375,7 +375,7 @@ gimp_paint_select_tool_cursor_update (GimpTool *tool,
GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (tool);
GimpCursorModifier modifier = GIMP_CURSOR_MODIFIER_NONE;
if (options->mode == GIMP_PAINT_SELECT_MODE_ADD)
if (options->operation == GIMP_CHANNEL_OP_ADD)
{
modifier = GIMP_CURSOR_MODIFIER_PLUS;
}
@ -500,24 +500,24 @@ gimp_paint_select_tool_modifier_key (GimpTool *tool,
key == modify_mask ||
key == GDK_MOD1_MASK)
{
GimpPaintSelectMode button_mode = options->mode;
GimpChannelOps button_op = options->operation;
state &= extend_mask | modify_mask | GDK_MOD1_MASK;
if (press)
{
if (key == state || ! state)
ps_tool->saved_mode = options->mode;
ps_tool->saved_op = options->operation;
}
else
{
if (! state)
button_mode = ps_tool->saved_mode;
button_op = ps_tool->saved_op;
}
if (state & GDK_MOD1_MASK)
{
button_mode = ps_tool->saved_mode;
button_op = ps_tool->saved_op;
}
else if (state & (extend_mask | modify_mask))
{
@ -526,11 +526,11 @@ gimp_paint_select_tool_modifier_key (GimpTool *tool,
switch (op)
{
case GIMP_CHANNEL_OP_ADD:
button_mode = GIMP_PAINT_SELECT_MODE_ADD;
button_op = GIMP_CHANNEL_OP_ADD;
break;
case GIMP_CHANNEL_OP_SUBTRACT:
button_mode = GIMP_PAINT_SELECT_MODE_SUBTRACT;
button_op = GIMP_CHANNEL_OP_SUBTRACT;
break;
default:
@ -538,8 +538,8 @@ gimp_paint_select_tool_modifier_key (GimpTool *tool,
}
}
if (button_mode != options->mode)
g_object_set (options, "mode", button_mode, NULL);
if (button_op != options->operation)
g_object_set (options, "operation", button_op, NULL);
}
}
@ -692,24 +692,18 @@ gimp_paint_select_tool_update_image_mask (GimpPaintSelectTool *ps_tool,
gint offset_x,
gint offset_y)
{
GimpTool *tool = GIMP_TOOL (ps_tool);
GimpChannelOps op;
GimpTool *tool = GIMP_TOOL (ps_tool);
if (tool->display)
{
GimpImage *image = gimp_display_get_image (tool->display);
if (ps_tool->painting_mode == GIMP_PAINT_SELECT_MODE_ADD)
op = GIMP_CHANNEL_OP_ADD;
else
op = GIMP_CHANNEL_OP_SUBTRACT;
gimp_channel_select_buffer (gimp_image_get_mask (image),
C_("command", "Paint Select"),
buffer,
offset_x,
offset_y,
op,
ps_tool->painting_op,
FALSE,
0,
0);
@ -795,7 +789,7 @@ gimp_paint_select_tool_paint_scribble (GimpPaintSelectTool *ps_tool)
an optimization should be triggered.
*/
if (ps_tool->painting_mode == GIMP_PAINT_SELECT_MODE_ADD)
if (ps_tool->painting_op == GIMP_CHANNEL_OP_ADD)
{
scribble_value = 1.f;
}

View file

@ -37,9 +37,9 @@ struct _GimpPaintSelectTool
{
GimpDrawTool parent_instance;
GimpPaintSelectMode saved_mode; /* selection mode before modifier press */
GimpChannelOps saved_op; /* selection mode before modifier press */
GimpPaintSelectMode painting_mode; /* selection mode at start of painting. */
GimpChannelOps painting_op; /* selection mode at start of painting. */
GeglBuffer *trimap;
GeglBuffer *image_mask;
GeglBuffer *drawable;

View file

@ -49,17 +49,19 @@ enum
};
static void gimp_selection_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_selection_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_selection_options_style_updated (GimpGuiConfig *config,
GParamSpec *pspec,
GtkWidget *box);
static void gimp_selection_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_selection_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static const gchar * gimp_selection_options_get_modifiers (GimpChannelOps operation);
static void gimp_selection_options_style_updated (GimpGuiConfig *config,
GParamSpec *pspec,
GtkWidget *box);
@ -175,6 +177,120 @@ gimp_selection_options_get_property (GObject *object,
}
}
GtkWidget *
gimp_selection_options_gui (GimpToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GimpSelectionOptions *options = GIMP_SELECTION_OPTIONS (tool_options);
GtkWidget *vbox = gimp_tool_options_gui (tool_options);
GtkWidget *button;
GtkWidget *mode_box;
/* the selection operation radio buttons */
mode_box = gimp_selection_options_get_mode_box (tool_options, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), mode_box, FALSE, FALSE, 0);
gtk_widget_show (mode_box);
options->mode_box = mode_box;
/* the antialias toggle button */
button = gimp_prop_check_button_new (config, "antialias", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
options->antialias_toggle = button;
/* the feather frame */
{
GtkWidget *frame;
GtkWidget *scale;
/* the feather radius scale */
scale = gimp_prop_spin_scale_new (config, "feather-radius",
1.0, 10.0, 1);
frame = gimp_prop_expanding_frame_new (config, "feather", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
}
return vbox;
}
GtkWidget *
gimp_selection_options_get_mode_box (GimpToolOptions *tool_options,
GimpChannelOps min_op,
GimpChannelOps max_op)
{
GObject *config = G_OBJECT (tool_options);
GimpContext *context = GIMP_CONTEXT (tool_options);
GimpGuiConfig *gui_config = GIMP_GUI_CONFIG (context->gimp->config);
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *box;
GList *children;
GList *list;
gint i;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
label = gtk_label_new (_("Mode:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
box = gimp_prop_enum_icon_box_new (config, "operation", "gimp-selection",
min_op, max_op);
g_signal_connect_object (gui_config,
"notify::override-theme-icon-size",
G_CALLBACK (gimp_selection_options_style_updated),
box, G_CONNECT_AFTER);
g_signal_connect_object (gui_config,
"notify::custom-icon-size",
G_CALLBACK (gimp_selection_options_style_updated),
box, G_CONNECT_AFTER);
gimp_selection_options_style_updated (gui_config, NULL, box);
gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, FALSE, 0);
children = gtk_container_get_children (GTK_CONTAINER (box));
/* add modifier keys to the tooltips */
for (list = children, i = 0; list; list = list->next, i++)
{
GtkWidget *button = list->data;
const gchar *modifier = gimp_selection_options_get_modifiers (i);
gchar *tooltip;
if (! modifier)
continue;
tooltip = gtk_widget_get_tooltip_text (button);
if (tooltip)
{
gchar *tip = g_strdup_printf ("%s <b>%s</b>", tooltip, modifier);
gimp_help_set_help_data_with_markup (button, tip, NULL);
g_free (tip);
g_free (tooltip);
}
else
{
gimp_help_set_help_data (button, modifier, NULL);
}
}
if (GIMP_CHANNEL_OP_REPLACE >= min_op &&
GIMP_CHANNEL_OP_REPLACE <= max_op)
/* move GIMP_CHANNEL_OP_REPLACE to the front */
gtk_box_reorder_child (GTK_BOX (box),
GTK_WIDGET (children->next->next->data), 0);
g_list_free (children);
return hbox;
}
static const gchar *
gimp_selection_options_get_modifiers (GimpChannelOps operation)
{
@ -207,109 +323,6 @@ gimp_selection_options_get_modifiers (GimpChannelOps operation)
return gimp_get_mod_string (modifiers);
}
GtkWidget *
gimp_selection_options_gui (GimpToolOptions *tool_options)
{
GObject *config = G_OBJECT (tool_options);
GimpContext *context = GIMP_CONTEXT (tool_options);
GimpGuiConfig *gui_config = GIMP_GUI_CONFIG (context->gimp->config);
GimpSelectionOptions *options = GIMP_SELECTION_OPTIONS (tool_options);
GtkWidget *vbox = gimp_tool_options_gui (tool_options);
GtkWidget *button;
/* the selection operation radio buttons */
{
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *box;
GList *children;
GList *list;
gint i;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
options->mode_box = hbox;
label = gtk_label_new (_("Mode:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
box = gimp_prop_enum_icon_box_new (config, "operation",
"gimp-selection", 0, 0);
g_signal_connect_object (gui_config,
"notify::override-theme-icon-size",
G_CALLBACK (gimp_selection_options_style_updated),
box, G_CONNECT_AFTER);
g_signal_connect_object (gui_config,
"notify::custom-icon-size",
G_CALLBACK (gimp_selection_options_style_updated),
box, G_CONNECT_AFTER);
gimp_selection_options_style_updated (gui_config, NULL, box);
gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, FALSE, 0);
children = gtk_container_get_children (GTK_CONTAINER (box));
/* add modifier keys to the tooltips */
for (list = children, i = 0; list; list = list->next, i++)
{
GtkWidget *button = list->data;
const gchar *modifier = gimp_selection_options_get_modifiers (i);
gchar *tooltip;
if (! modifier)
continue;
tooltip = gtk_widget_get_tooltip_text (button);
if (tooltip)
{
gchar *tip = g_strdup_printf ("%s <b>%s</b>", tooltip, modifier);
gimp_help_set_help_data_with_markup (button, tip, NULL);
g_free (tip);
g_free (tooltip);
}
else
{
gimp_help_set_help_data (button, modifier, NULL);
}
}
/* move GIMP_CHANNEL_OP_REPLACE to the front */
gtk_box_reorder_child (GTK_BOX (box),
GTK_WIDGET (children->next->next->data), 0);
g_list_free (children);
}
/* the antialias toggle button */
button = gimp_prop_check_button_new (config, "antialias", NULL);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
options->antialias_toggle = button;
/* the feather frame */
{
GtkWidget *frame;
GtkWidget *scale;
/* the feather radius scale */
scale = gimp_prop_spin_scale_new (config, "feather-radius",
1.0, 10.0, 1);
frame = gimp_prop_expanding_frame_new (config, "feather", NULL,
scale, NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
}
return vbox;
}
static void
gimp_selection_options_style_updated (GimpGuiConfig *config,
GParamSpec *pspec,

View file

@ -46,6 +46,12 @@ struct _GimpSelectionOptions
};
GType gimp_selection_options_get_type (void) G_GNUC_CONST;
GType gimp_selection_options_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_selection_options_gui (GimpToolOptions *tool_options);
GtkWidget * gimp_selection_options_gui (GimpToolOptions *tool_options);
/* For usage in gimppaintselectoptions.c */
GtkWidget * gimp_selection_options_get_mode_box (GimpToolOptions *tool_options,
GimpChannelOps min_op,
GimpChannelOps max_op);

View file

@ -338,35 +338,6 @@ gimp_warp_behavior_get_type (void)
return type;
}
GType
gimp_paint_select_mode_get_type (void)
{
static const GEnumValue values[] =
{
{ GIMP_PAINT_SELECT_MODE_ADD, "GIMP_PAINT_SELECT_MODE_ADD", "add" },
{ GIMP_PAINT_SELECT_MODE_SUBTRACT, "GIMP_PAINT_SELECT_MODE_SUBTRACT", "subtract" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
{ GIMP_PAINT_SELECT_MODE_ADD, NC_("paint-select-mode", "Add to selection"), NULL },
{ GIMP_PAINT_SELECT_MODE_SUBTRACT, NC_("paint-select-mode", "Subtract from selection"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("GimpPaintSelectMode", values);
gimp_type_set_translation_context (type, "paint-select-mode");
gimp_enum_set_value_descriptions (type, descs);
}
return type;
}
/* Generated data ends here */

View file

@ -165,16 +165,6 @@ typedef enum
} GimpWarpBehavior;
#define GIMP_TYPE_PAINT_SELECT_MODE (gimp_paint_select_mode_get_type ())
GType gimp_paint_select_mode_get_type (void) G_GNUC_CONST;
typedef enum
{
GIMP_PAINT_SELECT_MODE_ADD, /*< desc="Add to selection" >*/
GIMP_PAINT_SELECT_MODE_SUBTRACT, /*< desc="Subtract from selection" >*/
} GimpPaintSelectMode;
/*
* non-registered enums; register them if needed
*/