static GimpChannel * gimp_fuzzy_select_tool_get_mask (GimpRegionSelectTool *region_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (region_select); GimpSelectionOptions *sel_options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpRegionSelectOptions *options = GIMP_REGION_SELECT_TOOL_GET_OPTIONS (tool); GimpDrawable *drawable; gint x, y; drawable = gimp_image_get_active_drawable (display->image); x = region_select->x; y = region_select->y; if (! options->sample_merged) { gint off_x, off_y; gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); x -= off_x; y -= off_y; } return gimp_image_contiguous_region_by_seed (display->image, drawable, options->sample_merged, sel_options->antialias, options->threshold, options->select_transparent, options->select_criterion, x, y); }
static void gimp_region_select_tool_button_press (GimpTool *tool, GimpCoords *coords, guint32 time, GdkModifierType state, GimpDisplay *display) { GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); region_sel->x = coords->x; region_sel->y = coords->y; region_sel->saved_threshold = options->threshold; gimp_tool_control_activate (tool->control); tool->display = display; if (gimp_selection_tool_start_edit (GIMP_SELECTION_TOOL (region_sel), coords)) return; gimp_tool_push_status (tool, display, _("Move the mouse to change threshold")); /* calculate the region boundary */ region_sel->segs = gimp_region_select_tool_calculate (region_sel, display, ®ion_sel->num_segs); gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display); }
static GdkSegment * gimp_region_select_tool_calculate (GimpRegionSelectTool *region_sel, GimpDisplay *display, gint *num_segs) { GimpTool *tool = GIMP_TOOL (region_sel); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (display->shell); GimpDrawable *drawable; GdkSegment *segs; BoundSeg *bsegs; PixelRegion maskPR; drawable = gimp_image_get_active_drawable (display->image); gimp_display_shell_set_override_cursor (shell, GDK_WATCH); if (region_sel->region_mask) g_object_unref (region_sel->region_mask); region_sel->region_mask = GIMP_REGION_SELECT_TOOL_GET_CLASS (region_sel)->get_mask (region_sel, display); if (! region_sel->region_mask) { gimp_display_shell_unset_override_cursor (shell); *num_segs = 0; return NULL; } /* calculate and allocate a new segment array which represents the * boundary of the contiguous region */ pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (region_sel->region_mask)), 0, 0, gimp_item_width (GIMP_ITEM (region_sel->region_mask)), gimp_item_height (GIMP_ITEM (region_sel->region_mask)), FALSE); bsegs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS, 0, 0, gimp_item_width (GIMP_ITEM (region_sel->region_mask)), gimp_item_height (GIMP_ITEM (region_sel->region_mask)), BOUNDARY_HALF_WAY, num_segs); segs = g_new (GdkSegment, *num_segs); gimp_display_shell_transform_segments (shell, bsegs, segs, *num_segs, ! options->sample_merged); g_free (bsegs); gimp_display_shell_unset_override_cursor (shell); return segs; }
static GimpChannelOps gimp_rectangle_select_tool_get_operation (GimpRectangleSelectTool *rect_sel_tool) { GimpRectangleSelectToolPrivate *priv; GimpSelectionOptions *options; priv = GIMP_RECTANGLE_SELECT_TOOL_GET_PRIVATE (rect_sel_tool); options = GIMP_SELECTION_TOOL_GET_OPTIONS (rect_sel_tool); if (priv->use_saved_op) return priv->operation; else return options->operation; }
static void gimp_rectangle_select_tool_real_select (GimpRectangleSelectTool *rect_sel_tool, GimpChannelOps operation, gint x, gint y, gint w, gint h) { GimpTool *tool = GIMP_TOOL (rect_sel_tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpRectangleSelectOptions *rect_select_options; GimpChannel *channel; rect_select_options = GIMP_RECTANGLE_SELECT_TOOL_GET_OPTIONS (tool); channel = gimp_image_get_mask (gimp_display_get_image (tool->display)); if (rect_select_options->round_corners) { /* To prevent elliptification of the rectangle, * we must cap the corner radius. */ gdouble max = MIN (w / 2.0, h / 2.0); gdouble radius = MIN (rect_select_options->corner_radius, max); gimp_channel_select_round_rect (channel, x, y, w, h, radius, radius, operation, options->antialias, options->feather, options->feather_radius, options->feather_radius, TRUE); } else { gimp_channel_select_rectangle (channel, x, y, w, h, operation, options->feather, options->feather_radius, options->feather_radius, TRUE); } }
static void gimp_region_select_tool_cursor_update (GimpTool *tool, GimpCoords *coords, GdkModifierType state, GimpDisplay *display) { GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpCursorModifier modifier = GIMP_CURSOR_MODIFIER_NONE; if (! gimp_image_coords_in_active_pickable (display->image, coords, options->sample_merged, FALSE)) modifier = GIMP_CURSOR_MODIFIER_BAD; gimp_tool_control_set_cursor_modifier (tool->control, modifier); GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display); }
static void gimp_region_select_tool_motion (GimpTool *tool, GimpCoords *coords, guint32 time, GdkModifierType state, GimpDisplay *display) { GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GdkSegment *new_segs; gint num_new_segs; gint diff_x, diff_y; gdouble diff; static guint32 last_time = 0; /* don't let the events come in too fast, ignore below a delay of 100 ms */ if (time - last_time < 100) return; last_time = time; diff_x = coords->x - region_sel->x; diff_y = coords->y - region_sel->y; diff = ((ABS (diff_x) > ABS (diff_y)) ? diff_x : diff_y) / 2.0; g_object_set (options, "threshold", CLAMP (region_sel->saved_threshold + diff, 0, 255), NULL); /* calculate the new region boundary */ new_segs = gimp_region_select_tool_calculate (region_sel, display, &num_new_segs); gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool)); /* make sure the XSegment array is freed before we assign the new one */ if (region_sel->segs) g_free (region_sel->segs); region_sel->segs = new_segs; region_sel->num_segs = num_new_segs; gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); }
static GimpChannel * gimp_by_color_select_tool_get_mask (GimpRegionSelectTool *region_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (region_select); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpDrawable *drawable; GimpPickable *pickable; GimpRGB color; gint x, y; drawable = gimp_image_get_active_drawable (display->image); x = region_select->x; y = region_select->y; if (! options->sample_merged) { gint off_x, off_y; gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); x -= off_x; y -= off_y; pickable = GIMP_PICKABLE (drawable); } else { pickable = GIMP_PICKABLE (display->image->projection); } gimp_pickable_flush (pickable); if (gimp_pickable_get_color_at (pickable, x, y, &color)) return gimp_image_contiguous_region_by_color (display->image, drawable, options->sample_merged, options->antialias, options->threshold, options->select_transparent, options->select_criterion, &color); else return NULL; }
static void gimp_ellipse_select_tool_select (GimpRectangleSelectTool *rect_tool, GimpChannelOps operation, gint x, gint y, gint w, gint h) { GimpTool *tool = GIMP_TOOL (rect_tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (rect_tool); gimp_channel_select_ellipse (gimp_image_get_mask (tool->display->image), x, y, w, h, operation, options->antialias, options->feather, options->feather_radius, options->feather_radius, TRUE); }
static void gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (fg_select); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpImage *image = gimp_display_get_image (display); g_return_if_fail (fg_select->mask != NULL); gimp_channel_select_channel (gimp_image_get_mask (image), C_("command", "Foreground Select"), fg_select->mask, 0, 0, options->operation, options->feather, options->feather_radius, options->feather_radius); gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display); gimp_image_flush (image); }
static GeglBuffer * gimp_fuzzy_select_tool_get_mask (GimpRegionSelectTool *region_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (region_select); GimpSelectionOptions *sel_options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpRegionSelectOptions *options = GIMP_REGION_SELECT_TOOL_GET_OPTIONS (tool); GimpImage *image = gimp_display_get_image (display); GimpDrawable *drawable = gimp_image_get_active_drawable (image); GimpPickable *pickable; gint x, y; x = region_select->x; y = region_select->y; if (! options->sample_merged) { gint off_x, off_y; gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); x -= off_x; y -= off_y; pickable = GIMP_PICKABLE (drawable); } else { pickable = GIMP_PICKABLE (image); } return gimp_pickable_contiguous_region_by_seed (pickable, sel_options->antialias, options->threshold / 255.0, options->select_transparent, options->select_criterion, options->diagonal_neighbors, x, y); }
static void gimp_selection_tool_modifier_key (GimpTool *tool, GdkModifierType key, gboolean press, GdkModifierType state, GimpDisplay *display) { GimpSelectionTool *selection_tool = GIMP_SELECTION_TOOL (tool); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GdkModifierType extend_mask; GdkModifierType modify_mask; extend_mask = gimp_get_extend_selection_mask (); modify_mask = gimp_get_modify_selection_mask (); if (key == extend_mask || key == modify_mask || key == GDK_MOD1_MASK) { GimpChannelOps button_op = options->operation; if (press) { if (key == (state & (extend_mask | modify_mask | GDK_MOD1_MASK))) { /* first modifier pressed */ selection_tool->saved_operation = options->operation; } } else { if (! (state & (extend_mask | modify_mask | GDK_MOD1_MASK))) { /* last modifier released */ button_op = selection_tool->saved_operation; } } if (state & GDK_MOD1_MASK) { /* if alt is down, pretend that neither * shift nor control are down */ button_op = selection_tool->saved_operation; } else if (state & (extend_mask | modify_mask)) { /* else get the operation from the modifier state, but only * if there is actually a modifier pressed, so we don't * override the "last modifier released" assignment above */ button_op = gimp_modifiers_to_channel_op (state); } if (button_op != options->operation) { g_object_set (options, "operation", button_op, NULL); } } }
static void gimp_selection_tool_cursor_update (GimpTool *tool, const GimpCoords *coords, GdkModifierType state, GimpDisplay *display) { GimpSelectionTool *selection_tool = GIMP_SELECTION_TOOL (tool); GimpSelectionOptions *options; GimpToolCursorType tool_cursor; GimpCursorModifier modifier; options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); tool_cursor = gimp_tool_control_get_tool_cursor (tool->control); modifier = GIMP_CURSOR_MODIFIER_NONE; switch (selection_tool->function) { case SELECTION_SELECT: switch (options->operation) { case GIMP_CHANNEL_OP_REPLACE: break; case GIMP_CHANNEL_OP_ADD: modifier = GIMP_CURSOR_MODIFIER_PLUS; break; case GIMP_CHANNEL_OP_SUBTRACT: modifier = GIMP_CURSOR_MODIFIER_MINUS; break; case GIMP_CHANNEL_OP_INTERSECT: modifier = GIMP_CURSOR_MODIFIER_INTERSECT; break; } break; case SELECTION_MOVE_MASK: modifier = GIMP_CURSOR_MODIFIER_MOVE; break; case SELECTION_MOVE: case SELECTION_MOVE_COPY: tool_cursor = GIMP_TOOL_CURSOR_MOVE; break; case SELECTION_ANCHOR: modifier = GIMP_CURSOR_MODIFIER_ANCHOR; break; } /* we don't set the bad modifier ourselves, so a subclass has set * it, always leave it there since it's more important than what we * have to say. */ if (gimp_tool_control_get_cursor_modifier (tool->control) == GIMP_CURSOR_MODIFIER_BAD) { modifier = GIMP_CURSOR_MODIFIER_BAD; } gimp_tool_set_cursor (tool, display, gimp_tool_control_get_cursor (tool->control), tool_cursor, modifier); }
static void gimp_selection_tool_oper_update (GimpTool *tool, const GimpCoords *coords, GdkModifierType state, gboolean proximity, GimpDisplay *display) { 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 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); floating_sel = gimp_image_get_floating_selection (image); extend_mask = gimp_get_extend_selection_mask (); modify_mask = gimp_get_modify_selection_mask (); if (drawable) { if (floating_sel) { if (layer == floating_sel) move_floating_sel = TRUE; } else if (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 && (state & GDK_MOD1_MASK) && (state & modify_mask) && move_layer) { /* move the selection */ selection_tool->function = SELECTION_MOVE; } else if (selection_tool->allow_move && (state & GDK_MOD1_MASK) && (state & extend_mask) && move_layer) { /* move a copy of the selection */ selection_tool->function = SELECTION_MOVE_COPY; } else if (selection_tool->allow_move && (state & GDK_MOD1_MASK) && ! selection_empty) { /* move the selection mask */ selection_tool->function = SELECTION_MOVE_MASK; } else if (selection_tool->allow_move && ! (state & (extend_mask | modify_mask)) && move_floating_sel) { /* move the selection */ selection_tool->function = SELECTION_MOVE; } else if ((state & modify_mask) || (state & extend_mask)) { /* select */ selection_tool->function = SELECTION_SELECT; } else if (floating_sel) { /* anchor the selection */ selection_tool->function = SELECTION_ANCHOR; } gimp_tool_pop_status (tool, display); if (proximity) { const gchar *status = NULL; gboolean free_status = FALSE; GdkModifierType modifiers = (extend_mask | modify_mask); if (! selection_empty) modifiers |= GDK_MOD1_MASK; switch (selection_tool->function) { case SELECTION_SELECT: switch (options->operation) { case GIMP_CHANNEL_OP_REPLACE: if (! selection_empty) { status = gimp_suggest_modifiers (_("Click-Drag to replace the " "current selection"), modifiers & ~state, NULL, NULL, NULL); free_status = TRUE; } else { status = _("Click-Drag to create a new selection"); } break; case GIMP_CHANNEL_OP_ADD: status = gimp_suggest_modifiers (_("Click-Drag to add to the " "current selection"), modifiers & ~(state | extend_mask), NULL, NULL, NULL); free_status = TRUE; break; case GIMP_CHANNEL_OP_SUBTRACT: status = gimp_suggest_modifiers (_("Click-Drag to subtract from the " "current selection"), modifiers & ~(state | modify_mask), NULL, NULL, NULL); free_status = TRUE; break; case GIMP_CHANNEL_OP_INTERSECT: status = gimp_suggest_modifiers (_("Click-Drag to intersect with " "the current selection"), modifiers & ~state, NULL, NULL, NULL); free_status = TRUE; break; } break; case SELECTION_MOVE_MASK: status = gimp_suggest_modifiers (_("Click-Drag to move the " "selection mask"), modifiers & ~state, NULL, NULL, NULL); free_status = TRUE; break; case SELECTION_MOVE: status = _("Click-Drag to move the selected pixels"); break; case SELECTION_MOVE_COPY: status = _("Click-Drag to move a copy of the selected pixels"); break; case SELECTION_ANCHOR: status = _("Click to anchor the floating selection"); break; default: g_return_if_reached (); } if (status) gimp_tool_push_status (tool, display, "%s", status); if (free_status) g_free ((gchar *) status); } }
static void gimp_selection_tool_modifier_key (GimpTool *tool, GdkModifierType key, gboolean press, GdkModifierType state, GimpDisplay *display) { GimpSelectionTool *selection_tool = GIMP_SELECTION_TOOL (tool); GimpSelectionOptions *options; options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); if (key == GDK_SHIFT_MASK || key == GDK_CONTROL_MASK || key == GDK_MOD1_MASK) { GimpChannelOps button_op = options->operation; if (press) { if (key == (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK))) { /* first modifier pressed */ selection_tool->saved_operation = options->operation; } } else { if (! (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK))) { /* last modifier released */ button_op = selection_tool->saved_operation; } } if (state & GDK_MOD1_MASK) { /* if alt is down, pretend that neither * shift nor control are down */ button_op = selection_tool->saved_operation; } else if ((state & GDK_CONTROL_MASK) && (state & GDK_SHIFT_MASK)) { button_op = GIMP_CHANNEL_OP_INTERSECT; } else if (state & GDK_SHIFT_MASK) { button_op = GIMP_CHANNEL_OP_ADD; } else if (state & GDK_CONTROL_MASK) { button_op = GIMP_CHANNEL_OP_SUBTRACT; } if (button_op != options->operation) { g_object_set (options, "operation", button_op, NULL); } } }
static gboolean gimp_rectangle_select_tool_rectangle_change_complete (GimpRectangleTool *rectangle) { GimpTool *tool; GimpRectangleSelectTool *rect_sel_tool; GimpRectangleSelectToolPrivate *priv; tool = GIMP_TOOL (rectangle); rect_sel_tool = GIMP_RECTANGLE_SELECT_TOOL (tool); priv = GIMP_RECTANGLE_SELECT_TOOL_GET_PRIVATE (rect_sel_tool); /* prevent change in selection from halting the tool */ gimp_tool_control_push_preserve (tool->control, TRUE); if (tool->display && ! gimp_tool_control_is_active (tool->control)) { GimpImage *image = gimp_display_get_image (tool->display); GimpUndoStack *undo_stack = gimp_image_get_undo_stack (image); GimpUndo *undo = gimp_undo_stack_peek (undo_stack); gint x1, y1, x2, y2; /* if we got here via button release, we have already undone the * previous operation. But if we got here by some other means, * we need to undo it now. */ if (undo && priv->undo == undo) { gimp_image_undo (image); priv->undo = NULL; } g_object_get (rectangle, "x1", &x1, "y1", &y1, "x2", &x2, "y2", &y2, NULL); if (gimp_rectangle_select_tool_select (rectangle, x1, y1, x2 - x1, y2 - y1)) { /* save the undo that we got when executing, but only if * we actually selected something */ priv->undo = gimp_undo_stack_peek (undo_stack); priv->redo = NULL; } if (! priv->use_saved_op) { GimpSelectionOptions *options; options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); /* remember the operation now in case we modify the rectangle */ priv->operation = options->operation; priv->use_saved_op = TRUE; } gimp_image_flush (image); } gimp_tool_control_pop_preserve (tool->control); gimp_rectangle_select_tool_update_option_defaults (rect_sel_tool, FALSE); return TRUE; }
static void gimp_region_select_tool_button_release (GimpTool *tool, GimpCoords *coords, guint32 time, GdkModifierType state, GimpButtonReleaseType release_type, GimpDisplay *display) { GimpRegionSelectTool *region_sel = GIMP_REGION_SELECT_TOOL (tool); GimpSelectionOptions *sel_options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpRegionSelectOptions *options = GIMP_REGION_SELECT_TOOL_GET_OPTIONS (tool); gimp_tool_pop_status (tool, display); gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool)); gimp_tool_control_halt (tool->control); if (release_type != GIMP_BUTTON_RELEASE_CANCEL) { gint off_x, off_y; if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_ANCHOR) { if (gimp_image_floating_sel (display->image)) { /* If there is a floating selection, anchor it */ floating_sel_anchor (gimp_image_floating_sel (display->image)); } else { /* Otherwise, clear the selection mask */ gimp_channel_clear (gimp_image_get_mask (display->image), NULL, TRUE); } gimp_image_flush (display->image); } else if (region_sel->region_mask) { if (options->sample_merged) { off_x = 0; off_y = 0; } else { GimpDrawable *drawable; drawable = gimp_image_get_active_drawable (display->image); gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); } gimp_channel_select_channel (gimp_image_get_mask (display->image), GIMP_REGION_SELECT_TOOL_GET_CLASS (tool)->undo_desc, region_sel->region_mask, off_x, off_y, sel_options->operation, sel_options->feather, sel_options->feather_radius, sel_options->feather_radius); gimp_image_flush (display->image); } } if (region_sel->region_mask) { g_object_unref (region_sel->region_mask); region_sel->region_mask = NULL; } if (region_sel->segs) { g_free (region_sel->segs); region_sel->segs = NULL; region_sel->num_segs = 0; } /* Restore the original threshold */ g_object_set (options, "threshold", region_sel->saved_threshold, NULL); }