2006-12-09 13:33:38 -08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2005-07-28 18:48:56 -07:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
|
*
|
2005-07-30 11:56:08 -07:00
|
|
|
* GimpForegroundSelectTool
|
|
|
|
|
* Copyright (C) 2005 Sven Neumann <sven@gimp.org>
|
|
|
|
|
*
|
2009-01-17 14:28:01 -08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2005-07-28 18:48:56 -07:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 14:28:01 -08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2005-07-28 18:48:56 -07:00
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2018-07-11 14:47:19 -07:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2005-07-28 18:48:56 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2005-08-06 13:01:22 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
|
2008-10-09 13:24:04 -07:00
|
|
|
#include <gegl.h>
|
2005-07-28 18:48:56 -07:00
|
|
|
#include <gtk/gtk.h>
|
2005-07-30 11:19:54 -07:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2007-03-09 05:00:01 -08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2014-04-18 15:34:21 -07:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2013-05-07 15:00:48 -07:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
|
|
|
|
|
#include "tools-types.h"
|
|
|
|
|
|
2018-05-24 07:21:21 -07:00
|
|
|
#include "gegl/gimp-gegl-loops.h"
|
2013-06-22 13:26:46 -07:00
|
|
|
#include "gegl/gimp-gegl-mask.h"
|
|
|
|
|
|
2005-07-28 19:07:49 -07:00
|
|
|
#include "core/gimp.h"
|
2013-12-08 21:22:34 -08:00
|
|
|
#include "core/gimpchannel-select.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
#include "core/gimpdrawable-foreground-extract.h"
|
2014-04-17 01:52:32 -07:00
|
|
|
#include "core/gimperror.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
#include "core/gimpimage.h"
|
2013-05-07 15:00:48 -07:00
|
|
|
#include "core/gimplayer.h"
|
|
|
|
|
#include "core/gimplayermask.h"
|
2005-07-28 20:28:27 -07:00
|
|
|
#include "core/gimpprogress.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
#include "core/gimpscanconvert.h"
|
|
|
|
|
|
|
|
|
|
#include "widgets/gimphelp-ids.h"
|
2011-10-06 12:59:07 -07:00
|
|
|
#include "widgets/gimpwidgets-utils.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
|
|
|
|
|
#include "display/gimpdisplay.h"
|
2005-07-30 11:19:54 -07:00
|
|
|
#include "display/gimpdisplayshell.h"
|
2013-12-08 21:22:34 -08:00
|
|
|
#include "display/gimptoolgui.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
|
|
|
|
|
#include "gimpforegroundselecttool.h"
|
2005-07-31 11:29:10 -07:00
|
|
|
#include "gimpforegroundselectoptions.h"
|
2005-07-28 18:48:56 -07:00
|
|
|
#include "gimptoolcontrol.h"
|
|
|
|
|
|
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
|
2015-12-29 03:57:17 -08:00
|
|
|
#define FAR_OUTSIDE -10000
|
|
|
|
|
|
|
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
typedef struct _StrokeUndo StrokeUndo;
|
|
|
|
|
|
|
|
|
|
struct _StrokeUndo
|
2005-08-02 09:07:16 -07:00
|
|
|
{
|
2014-04-18 15:34:21 -07:00
|
|
|
GeglBuffer *saved_trimap;
|
|
|
|
|
gint trimap_x;
|
|
|
|
|
gint trimap_y;
|
|
|
|
|
GimpMattingDrawMode draw_mode;
|
|
|
|
|
gint stroke_width;
|
|
|
|
|
};
|
2005-08-02 09:07:16 -07:00
|
|
|
|
|
|
|
|
|
2008-11-01 08:17:36 -07:00
|
|
|
static void gimp_foreground_select_tool_finalize (GObject *object);
|
|
|
|
|
|
2014-04-17 01:52:32 -07:00
|
|
|
static gboolean gimp_foreground_select_tool_initialize (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display,
|
|
|
|
|
GError **error);
|
2008-11-01 08:17:36 -07:00
|
|
|
static void gimp_foreground_select_tool_control (GimpTool *tool,
|
|
|
|
|
GimpToolAction action,
|
|
|
|
|
GimpDisplay *display);
|
2014-04-18 12:52:38 -07:00
|
|
|
static void gimp_foreground_select_tool_button_press (GimpTool *tool,
|
2008-11-01 08:17:36 -07:00
|
|
|
const GimpCoords *coords,
|
2014-04-18 12:52:38 -07:00
|
|
|
guint32 time,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpButtonPressType press_type,
|
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
static void gimp_foreground_select_tool_button_release (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
guint32 time,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpButtonReleaseType release_type,
|
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
static void gimp_foreground_select_tool_motion (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
guint32 time,
|
2008-11-01 08:17:36 -07:00
|
|
|
GdkModifierType state,
|
2014-04-18 12:52:38 -07:00
|
|
|
GimpDisplay *display);
|
|
|
|
|
static gboolean gimp_foreground_select_tool_key_press (GimpTool *tool,
|
|
|
|
|
GdkEventKey *kevent,
|
2008-11-01 08:17:36 -07:00
|
|
|
GimpDisplay *display);
|
|
|
|
|
static void gimp_foreground_select_tool_modifier_key (GimpTool *tool,
|
|
|
|
|
GdkModifierType key,
|
|
|
|
|
gboolean press,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display);
|
2014-04-16 14:03:57 -07:00
|
|
|
static void gimp_foreground_select_tool_active_modifier_key
|
|
|
|
|
(GimpTool *tool,
|
|
|
|
|
GdkModifierType key,
|
|
|
|
|
gboolean press,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display);
|
2014-04-18 12:52:38 -07:00
|
|
|
static void gimp_foreground_select_tool_oper_update (GimpTool *tool,
|
2008-11-01 08:17:36 -07:00
|
|
|
const GimpCoords *coords,
|
|
|
|
|
GdkModifierType state,
|
2014-04-18 12:52:38 -07:00
|
|
|
gboolean proximity,
|
2008-11-01 08:17:36 -07:00
|
|
|
GimpDisplay *display);
|
2014-04-18 12:52:38 -07:00
|
|
|
static void gimp_foreground_select_tool_cursor_update (GimpTool *tool,
|
2008-11-01 08:17:36 -07:00
|
|
|
const GimpCoords *coords,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display);
|
2017-07-04 09:48:03 -07:00
|
|
|
static const gchar * gimp_foreground_select_tool_can_undo
|
2014-04-18 15:34:21 -07:00
|
|
|
(GimpTool *tool,
|
|
|
|
|
GimpDisplay *display);
|
2017-07-04 09:48:03 -07:00
|
|
|
static const gchar * gimp_foreground_select_tool_can_redo
|
2014-04-18 15:34:21 -07:00
|
|
|
(GimpTool *tool,
|
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
static gboolean gimp_foreground_select_tool_undo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
static gboolean gimp_foreground_select_tool_redo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display);
|
2014-04-16 14:03:57 -07:00
|
|
|
static void gimp_foreground_select_tool_options_notify (GimpTool *tool,
|
|
|
|
|
GimpToolOptions *options,
|
|
|
|
|
const GParamSpec *pspec);
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2008-11-01 08:17:36 -07:00
|
|
|
static void gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool);
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
static void gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
|
2017-06-22 16:59:37 -07:00
|
|
|
GimpDisplay *display,
|
|
|
|
|
const GimpVector2 *points,
|
|
|
|
|
gint n_points);
|
2005-07-30 11:56:08 -07:00
|
|
|
|
2014-04-18 13:06:07 -07:00
|
|
|
static void gimp_foreground_select_tool_halt (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
static void gimp_foreground_select_tool_commit (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
|
2014-04-18 18:35:31 -07:00
|
|
|
static void gimp_foreground_select_tool_set_trimap (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
static void gimp_foreground_select_tool_set_preview (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
static void gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select);
|
2005-08-02 09:07:16 -07:00
|
|
|
|
2014-04-16 16:52:21 -07:00
|
|
|
static void gimp_foreground_select_tool_stroke_paint (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
static void gimp_foreground_select_tool_cancel_paint (GimpForegroundSelectTool *fg_select);
|
2005-08-06 13:01:22 -07:00
|
|
|
|
2013-12-08 21:22:34 -08:00
|
|
|
static void gimp_foreground_select_tool_response (GimpToolGui *gui,
|
|
|
|
|
gint response_id,
|
|
|
|
|
GimpForegroundSelectTool *fg_select);
|
2014-04-18 13:37:33 -07:00
|
|
|
static void gimp_foreground_select_tool_preview_toggled(GtkToggleButton *button,
|
|
|
|
|
GimpForegroundSelectTool *fg_select);
|
2013-12-08 21:22:34 -08:00
|
|
|
|
2014-04-16 16:40:08 -07:00
|
|
|
static void gimp_foreground_select_tool_update_gui (GimpForegroundSelectTool *fg_select);
|
|
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
static StrokeUndo * gimp_foreground_select_undo_new (GeglBuffer *trimap,
|
|
|
|
|
GArray *stroke,
|
|
|
|
|
GimpMattingDrawMode draw_mode,
|
|
|
|
|
gint stroke_width);
|
|
|
|
|
static void gimp_foreground_select_undo_pop (StrokeUndo *undo,
|
|
|
|
|
GeglBuffer *trimap);
|
|
|
|
|
static void gimp_foreground_select_undo_free (StrokeUndo *undo);
|
|
|
|
|
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2005-12-13 01:13:50 -08:00
|
|
|
G_DEFINE_TYPE (GimpForegroundSelectTool, gimp_foreground_select_tool,
|
2006-05-15 02:46:31 -07:00
|
|
|
GIMP_TYPE_FREE_SELECT_TOOL)
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2005-12-13 01:13:50 -08:00
|
|
|
#define parent_class gimp_foreground_select_tool_parent_class
|
2005-07-28 18:48:56 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gimp_foreground_select_tool_register (GimpToolRegisterCallback callback,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
(* callback) (GIMP_TYPE_FOREGROUND_SELECT_TOOL,
|
2005-07-31 11:29:10 -07:00
|
|
|
GIMP_TYPE_FOREGROUND_SELECT_OPTIONS,
|
|
|
|
|
gimp_foreground_select_options_gui,
|
2015-09-08 12:18:49 -07:00
|
|
|
GIMP_CONTEXT_PROP_MASK_FOREGROUND |
|
|
|
|
|
GIMP_CONTEXT_PROP_MASK_BACKGROUND,
|
2005-07-28 18:48:56 -07:00
|
|
|
"gimp-foreground-select-tool",
|
|
|
|
|
_("Foreground Select"),
|
2006-09-18 11:00:22 -07:00
|
|
|
_("Foreground Select Tool: Select a region containing foreground objects"),
|
2005-07-29 13:26:29 -07:00
|
|
|
N_("F_oreground Select"), NULL,
|
2005-07-28 18:48:56 -07:00
|
|
|
NULL, GIMP_HELP_TOOL_FOREGROUND_SELECT,
|
2017-03-05 07:01:59 -08:00
|
|
|
GIMP_ICON_TOOL_FOREGROUND_SELECT,
|
2005-07-28 18:48:56 -07:00
|
|
|
data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_class_init (GimpForegroundSelectToolClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
|
|
|
|
|
GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
|
2005-07-30 11:56:08 -07:00
|
|
|
GimpFreeSelectToolClass *free_select_tool_class;
|
|
|
|
|
|
|
|
|
|
free_select_tool_class = GIMP_FREE_SELECT_TOOL_CLASS (klass);
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
object_class->finalize = gimp_foreground_select_tool_finalize;
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-04-17 01:52:32 -07:00
|
|
|
tool_class->initialize = gimp_foreground_select_tool_initialize;
|
2014-04-16 14:03:57 -07:00
|
|
|
tool_class->control = gimp_foreground_select_tool_control;
|
|
|
|
|
tool_class->button_press = gimp_foreground_select_tool_button_press;
|
|
|
|
|
tool_class->button_release = gimp_foreground_select_tool_button_release;
|
|
|
|
|
tool_class->motion = gimp_foreground_select_tool_motion;
|
2014-04-18 12:52:38 -07:00
|
|
|
tool_class->key_press = gimp_foreground_select_tool_key_press;
|
|
|
|
|
tool_class->modifier_key = gimp_foreground_select_tool_modifier_key;
|
|
|
|
|
tool_class->active_modifier_key = gimp_foreground_select_tool_active_modifier_key;
|
|
|
|
|
tool_class->oper_update = gimp_foreground_select_tool_oper_update;
|
|
|
|
|
tool_class->cursor_update = gimp_foreground_select_tool_cursor_update;
|
2017-07-04 09:48:03 -07:00
|
|
|
tool_class->can_undo = gimp_foreground_select_tool_can_undo;
|
|
|
|
|
tool_class->can_redo = gimp_foreground_select_tool_can_redo;
|
2014-04-18 15:34:21 -07:00
|
|
|
tool_class->undo = gimp_foreground_select_tool_undo;
|
|
|
|
|
tool_class->redo = gimp_foreground_select_tool_redo;
|
2014-04-16 14:03:57 -07:00
|
|
|
tool_class->options_notify = gimp_foreground_select_tool_options_notify;
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
draw_tool_class->draw = gimp_foreground_select_tool_draw;
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
free_select_tool_class->select = gimp_foreground_select_tool_select;
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_init (GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
|
|
|
|
|
2014-06-02 11:55:33 -07:00
|
|
|
gimp_tool_control_set_motion_mode (tool->control, GIMP_MOTION_MODE_EXACT);
|
2006-10-04 08:42:33 -07:00
|
|
|
gimp_tool_control_set_scroll_lock (tool->control, FALSE);
|
2006-06-07 00:30:40 -07:00
|
|
|
gimp_tool_control_set_preserve (tool->control, FALSE);
|
2012-09-06 14:55:35 -07:00
|
|
|
gimp_tool_control_set_dirty_mask (tool->control,
|
|
|
|
|
GIMP_DIRTY_IMAGE_SIZE |
|
|
|
|
|
GIMP_DIRTY_ACTIVE_DRAWABLE);
|
2008-08-21 01:19:54 -07:00
|
|
|
gimp_tool_control_set_precision (tool->control,
|
2019-01-31 01:37:56 -08:00
|
|
|
GIMP_CURSOR_PRECISION_SUBPIXEL);
|
2005-07-28 18:48:56 -07:00
|
|
|
gimp_tool_control_set_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_FREE_SELECT);
|
2006-06-07 00:30:40 -07:00
|
|
|
|
2014-04-19 11:09:39 -07:00
|
|
|
gimp_tool_control_set_action_size (tool->control,
|
|
|
|
|
"tools/tools-foreground-select-brush-size-set");
|
2006-11-22 12:38:36 -08:00
|
|
|
|
2014-04-18 13:37:33 -07:00
|
|
|
fg_select->state = MATTING_STATE_FREE_SELECT;
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (object);
|
|
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&fg_select->gui);
|
|
|
|
|
fg_select->preview_toggle = NULL;
|
2013-12-08 21:22:34 -08:00
|
|
|
|
2005-07-31 07:27:46 -07:00
|
|
|
if (fg_select->stroke)
|
2013-06-22 13:26:46 -07:00
|
|
|
g_warning ("%s: stroke should be NULL at this point", G_STRLOC);
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2005-07-30 11:45:03 -07:00
|
|
|
if (fg_select->mask)
|
2013-06-22 13:26:46 -07:00
|
|
|
g_warning ("%s: mask should be NULL at this point", G_STRLOC);
|
2013-05-07 15:00:48 -07:00
|
|
|
|
|
|
|
|
if (fg_select->trimap)
|
2013-06-22 13:26:46 -07:00
|
|
|
g_warning ("%s: mask should be NULL at this point", G_STRLOC);
|
2005-07-30 11:19:54 -07:00
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 01:52:32 -07:00
|
|
|
static gboolean
|
|
|
|
|
gimp_foreground_select_tool_initialize (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
|
|
|
|
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
|
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
|
|
|
|
|
|
if (! drawable)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (! gimp_item_is_visible (GIMP_ITEM (drawable)))
|
|
|
|
|
{
|
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
|
|
|
|
_("The active layer is not visible."));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tool->display = display;
|
|
|
|
|
|
2018-04-08 04:03:11 -07:00
|
|
|
/* enable double click for the FreeSelectTool, because it may have been
|
|
|
|
|
* disabled if the tool has switched to MATTING_STATE_PAINT_TRIMAP,
|
|
|
|
|
* in gimp_foreground_select_tool_set_trimap().
|
|
|
|
|
*/
|
|
|
|
|
gimp_tool_control_set_wants_double_click (tool->control, TRUE);
|
|
|
|
|
|
2014-04-17 01:52:32 -07:00
|
|
|
fg_select->state = MATTING_STATE_FREE_SELECT;
|
|
|
|
|
|
|
|
|
|
if (! fg_select->gui)
|
|
|
|
|
{
|
2014-04-18 12:38:53 -07:00
|
|
|
fg_select->gui =
|
|
|
|
|
gimp_tool_gui_new (tool->tool_info,
|
2016-01-22 14:41:45 -08:00
|
|
|
NULL,
|
2014-04-18 12:38:53 -07:00
|
|
|
_("Dialog for foreground select"),
|
2016-01-22 14:41:45 -08:00
|
|
|
NULL, NULL,
|
2014-05-01 18:01:23 -07:00
|
|
|
gtk_widget_get_screen (GTK_WIDGET (shell)),
|
|
|
|
|
gimp_widget_get_monitor (GTK_WIDGET (shell)),
|
|
|
|
|
TRUE,
|
2017-02-12 07:06:34 -08:00
|
|
|
|
|
|
|
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
|
|
|
_("_Select"), GTK_RESPONSE_APPLY,
|
|
|
|
|
|
2014-04-18 12:38:53 -07:00
|
|
|
NULL);
|
2014-04-17 01:52:32 -07:00
|
|
|
|
2014-06-08 18:08:43 -07:00
|
|
|
gimp_tool_gui_set_auto_overlay (fg_select->gui, TRUE);
|
|
|
|
|
|
2014-04-17 01:52:32 -07:00
|
|
|
g_signal_connect (fg_select->gui, "response",
|
|
|
|
|
G_CALLBACK (gimp_foreground_select_tool_response),
|
|
|
|
|
fg_select);
|
2014-04-18 13:37:33 -07:00
|
|
|
|
|
|
|
|
fg_select->preview_toggle =
|
|
|
|
|
gtk_check_button_new_with_mnemonic (_("_Preview mask"));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (gimp_tool_gui_get_vbox (fg_select->gui)),
|
|
|
|
|
fg_select->preview_toggle, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (fg_select->preview_toggle);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (fg_select->preview_toggle, "toggled",
|
|
|
|
|
G_CALLBACK (gimp_foreground_select_tool_preview_toggled),
|
|
|
|
|
fg_select);
|
2014-04-17 01:52:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_tool_gui_set_description (fg_select->gui,
|
|
|
|
|
_("Select foreground pixels"));
|
|
|
|
|
|
2014-04-18 13:15:35 -07:00
|
|
|
gimp_tool_gui_set_response_sensitive (fg_select->gui, GTK_RESPONSE_APPLY,
|
|
|
|
|
FALSE);
|
2014-04-18 13:37:33 -07:00
|
|
|
gtk_widget_set_sensitive (fg_select->preview_toggle, FALSE);
|
|
|
|
|
|
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fg_select->preview_toggle),
|
|
|
|
|
FALSE);
|
2014-04-17 01:52:32 -07:00
|
|
|
|
|
|
|
|
gimp_tool_gui_set_shell (fg_select->gui, shell);
|
|
|
|
|
gimp_tool_gui_set_viewable (fg_select->gui, GIMP_VIEWABLE (drawable));
|
|
|
|
|
|
|
|
|
|
gimp_tool_gui_show (fg_select->gui);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-30 11:19:54 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_control (GimpTool *tool,
|
|
|
|
|
GimpToolAction action,
|
2006-03-28 09:55:52 -08:00
|
|
|
GimpDisplay *display)
|
2005-07-30 11:19:54 -07:00
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
|
|
|
|
switch (action)
|
2005-07-28 18:48:56 -07:00
|
|
|
{
|
2006-05-21 14:12:01 -07:00
|
|
|
case GIMP_TOOL_ACTION_PAUSE:
|
|
|
|
|
case GIMP_TOOL_ACTION_RESUME:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GIMP_TOOL_ACTION_HALT:
|
2014-04-18 13:06:07 -07:00
|
|
|
gimp_foreground_select_tool_halt (fg_select);
|
2014-04-04 13:34:26 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GIMP_TOOL_ACTION_COMMIT:
|
2014-04-18 13:06:07 -07:00
|
|
|
gimp_foreground_select_tool_commit (fg_select);
|
2005-07-30 11:19:54 -07:00
|
|
|
break;
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
2006-03-28 09:55:52 -08:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
|
2005-07-30 11:19:54 -07:00
|
|
|
}
|
|
|
|
|
|
2005-07-30 12:21:47 -07:00
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_button_press (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
guint32 time,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpButtonPressType press_type,
|
|
|
|
|
GimpDisplay *display)
|
2005-07-30 12:21:47 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
|
2005-07-30 12:21:47 -07:00
|
|
|
|
2013-12-14 00:48:11 -08:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
|
|
|
|
|
press_type, display);
|
2013-12-14 00:48:11 -08:00
|
|
|
}
|
|
|
|
|
else
|
2005-07-30 12:21:47 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GimpVector2 point = gimp_vector2_new (coords->x, coords->y);
|
2011-03-30 12:24:04 -07:00
|
|
|
|
|
|
|
|
gimp_draw_tool_pause (draw_tool);
|
|
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (gimp_draw_tool_is_active (draw_tool) && draw_tool->display != display)
|
|
|
|
|
gimp_draw_tool_stop (draw_tool);
|
|
|
|
|
|
|
|
|
|
gimp_tool_control_activate (tool->control);
|
|
|
|
|
|
2011-03-30 12:24:04 -07:00
|
|
|
fg_select->last_coords = *coords;
|
|
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
g_return_if_fail (fg_select->stroke == NULL);
|
|
|
|
|
fg_select->stroke = g_array_new (FALSE, FALSE, sizeof (GimpVector2));
|
2013-12-14 00:48:11 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
g_array_append_val (fg_select->stroke, point);
|
2013-12-14 00:48:11 -08:00
|
|
|
|
2017-12-07 10:49:37 -08:00
|
|
|
if (! gimp_draw_tool_is_active (draw_tool))
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_start (draw_tool, display);
|
2013-12-14 00:48:11 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_resume (draw_tool);
|
2013-05-07 15:00:48 -07:00
|
|
|
}
|
2005-07-30 12:21:47 -07:00
|
|
|
}
|
|
|
|
|
|
2006-03-27 10:35:42 -08:00
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_button_release (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
guint32 time,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpButtonReleaseType release_type,
|
|
|
|
|
GimpDisplay *display)
|
2006-03-27 10:35:42 -08:00
|
|
|
{
|
2014-04-16 14:03:57 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
|
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
2006-03-27 10:35:42 -08:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
|
|
|
|
|
release_type, display);
|
2017-12-07 10:49:37 -08:00
|
|
|
|
|
|
|
|
/* see comment in gimp_foreground_select_tool_select() */
|
|
|
|
|
if (fg_select->in_double_click)
|
|
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
|
|
|
|
|
|
|
|
|
fg_select->in_double_click = FALSE;
|
|
|
|
|
}
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
2006-03-27 10:35:42 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_tool_control_halt (tool->control);
|
2006-03-27 10:35:42 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
|
|
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_cancel_paint (fg_select);
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_stroke_paint (fg_select);
|
|
|
|
|
|
|
|
|
|
if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
2014-04-18 12:52:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_motion (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
guint32 time,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display)
|
2014-04-16 14:03:57 -07:00
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
|
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
|
|
|
|
|
display);
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GimpVector2 *last = &g_array_index (fg_select->stroke,
|
|
|
|
|
GimpVector2,
|
|
|
|
|
fg_select->stroke->len - 1);
|
2006-03-27 10:35:42 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
2005-07-30 12:48:49 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
fg_select->last_coords = *coords;
|
|
|
|
|
|
|
|
|
|
if (last->x != (gint) coords->x || last->y != (gint) coords->y)
|
2005-07-30 12:48:49 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GimpVector2 point = gimp_vector2_new (coords->x, coords->y);
|
|
|
|
|
|
|
|
|
|
g_array_append_val (fg_select->stroke, point);
|
2005-07-30 12:48:49 -07:00
|
|
|
}
|
|
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
|
|
|
|
}
|
2005-07-30 12:48:49 -07:00
|
|
|
}
|
|
|
|
|
|
2005-07-30 11:19:54 -07:00
|
|
|
static gboolean
|
|
|
|
|
gimp_foreground_select_tool_key_press (GimpTool *tool,
|
|
|
|
|
GdkEventKey *kevent,
|
2006-03-28 09:55:52 -08:00
|
|
|
GimpDisplay *display)
|
2005-07-30 11:19:54 -07:00
|
|
|
{
|
2005-07-30 11:56:08 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
2014-04-16 16:59:34 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
Merged the Polygon Select Tool capabilities with the Free Select Tool.
2008-05-18 Martin Nordholts <martinn@svn.gnome.org>
Merged the Polygon Select Tool capabilities with the Free Select
Tool. Among the things still to do is improved help texts, more
suitable graphics, and cursor mangement, but the core
functionality is in place. Thanks to Alexia Death for initial
testing. It will also be neccesary to do some work to adapt the
Foreground Select Tool to the new Free Select Tool implementation.
Quick instructions on how the tool works:
o A click adds a polygonal segment, a drag adds a free-hand
segment
o Return-key commits, Escape-key cancels, Backspace-key removes
last segment
o You can grab and move segment vertices
o You can cancel both a move, and the creation of a segment
* app/tools/gimpfreeselecttool.[ch]: More or less
reimplemented. We keep a sequential array of all the points in the
polygon (including the free segments), and we have another array
with point indices that we use to represent the segments. On top
of this we have a few helper functions that tries to abstract away
the pretty raw nature of the implementation.
* app/tools/gimpforegroundselecttool.[ch]: Keep track on its own
last_coord, and adjust to the new implementation of the Free
Select Tool. Still needs some work, for example handling that the
Free Select Tool now resets GimpTool::display.
(gimp_foreground_select_tool_key_press): Pass on key event to
parent class when appropriate. (Bails out too early though...)
svn path=/trunk/; revision=25693
2008-05-18 04:39:17 -07:00
|
|
|
{
|
2014-04-16 16:59:34 -07:00
|
|
|
return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
|
2013-05-07 15:00:48 -07:00
|
|
|
}
|
2014-04-16 14:03:57 -07:00
|
|
|
else
|
2013-05-07 15:00:48 -07:00
|
|
|
{
|
2014-04-16 14:03:57 -07:00
|
|
|
if (display != tool->display)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
switch (kevent->keyval)
|
|
|
|
|
{
|
|
|
|
|
case GDK_KEY_Return:
|
|
|
|
|
case GDK_KEY_KP_Enter:
|
|
|
|
|
case GDK_KEY_ISO_Enter:
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
2014-04-18 13:37:33 -07:00
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fg_select->preview_toggle),
|
|
|
|
|
TRUE);
|
2014-04-16 14:03:57 -07:00
|
|
|
else
|
|
|
|
|
gimp_foreground_select_tool_response (fg_select->gui,
|
2014-04-18 13:15:35 -07:00
|
|
|
GTK_RESPONSE_APPLY, fg_select);
|
2013-05-07 15:00:48 -07:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
case GDK_KEY_Escape:
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
|
|
|
|
gimp_foreground_select_tool_response (fg_select->gui,
|
2014-04-18 12:38:53 -07:00
|
|
|
GTK_RESPONSE_CANCEL, fg_select);
|
2014-04-16 14:03:57 -07:00
|
|
|
else
|
2014-04-18 13:37:33 -07:00
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fg_select->preview_toggle),
|
|
|
|
|
FALSE);
|
2013-05-07 15:00:48 -07:00
|
|
|
return TRUE;
|
|
|
|
|
|
Merged the Polygon Select Tool capabilities with the Free Select Tool.
2008-05-18 Martin Nordholts <martinn@svn.gnome.org>
Merged the Polygon Select Tool capabilities with the Free Select
Tool. Among the things still to do is improved help texts, more
suitable graphics, and cursor mangement, but the core
functionality is in place. Thanks to Alexia Death for initial
testing. It will also be neccesary to do some work to adapt the
Foreground Select Tool to the new Free Select Tool implementation.
Quick instructions on how the tool works:
o A click adds a polygonal segment, a drag adds a free-hand
segment
o Return-key commits, Escape-key cancels, Backspace-key removes
last segment
o You can grab and move segment vertices
o You can cancel both a move, and the creation of a segment
* app/tools/gimpfreeselecttool.[ch]: More or less
reimplemented. We keep a sequential array of all the points in the
polygon (including the free segments), and we have another array
with point indices that we use to represent the segments. On top
of this we have a few helper functions that tries to abstract away
the pretty raw nature of the implementation.
* app/tools/gimpforegroundselecttool.[ch]: Keep track on its own
last_coord, and adjust to the new implementation of the Free
Select Tool. Still needs some work, for example handling that the
Free Select Tool now resets GimpTool::display.
(gimp_foreground_select_tool_key_press): Pass on key event to
parent class when appropriate. (Bails out too early though...)
svn path=/trunk/; revision=25693
2008-05-18 04:39:17 -07:00
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_modifier_key (GimpTool *tool,
|
|
|
|
|
GdkModifierType key,
|
|
|
|
|
gboolean press,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display)
|
2005-07-28 18:48:56 -07:00
|
|
|
{
|
2005-07-30 12:48:49 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, state,
|
|
|
|
|
display);
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
|
|
|
|
else
|
2005-07-31 07:27:46 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
#if 0
|
|
|
|
|
if (key == gimp_get_toggle_behavior_mask ())
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectOptions *options;
|
2005-07-31 09:39:55 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
|
2005-07-31 09:39:55 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
g_object_set (options,
|
|
|
|
|
"background", ! options->background,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2005-07-31 07:27:46 -07:00
|
|
|
}
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_active_modifier_key (GimpTool *tool,
|
|
|
|
|
GdkModifierType key,
|
|
|
|
|
gboolean press,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display)
|
2005-07-28 18:48:56 -07:00
|
|
|
{
|
2005-07-30 12:48:49 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->active_modifier_key (tool, key, press,
|
|
|
|
|
state, display);
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
}
|
2005-08-06 14:39:43 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_oper_update (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
gboolean proximity,
|
|
|
|
|
GimpDisplay *display)
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
GimpForegroundSelectOptions *options;
|
|
|
|
|
const gchar *status_stage = NULL;
|
|
|
|
|
const gchar *status_mode = NULL;
|
2005-07-31 07:27:46 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (fg_select);
|
2014-04-16 16:46:32 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
|
|
|
|
|
display);
|
2005-07-31 07:27:46 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
|
|
|
|
if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_SELECT)
|
2018-05-13 10:21:57 -07:00
|
|
|
{
|
|
|
|
|
if (gimp_free_select_tool_get_n_points (GIMP_FREE_SELECT_TOOL (tool)) > 2)
|
|
|
|
|
{
|
|
|
|
|
status_mode = _("Roughly outline the object to extract");
|
2018-05-13 12:50:35 -07:00
|
|
|
status_stage = _("press Enter to refine.");
|
2018-05-13 10:21:57 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
status_stage = _("Roughly outline the object to extract");
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-31 07:27:46 -07:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_pause (draw_tool);
|
2013-12-08 21:22:34 -08:00
|
|
|
|
2015-12-29 03:57:17 -08:00
|
|
|
if (proximity)
|
|
|
|
|
{
|
|
|
|
|
fg_select->last_coords = *coords;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fg_select->last_coords.x = FAR_OUTSIDE;
|
|
|
|
|
fg_select->last_coords.y = FAR_OUTSIDE;
|
|
|
|
|
}
|
2014-04-18 12:38:53 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_draw_tool_resume (draw_tool);
|
2014-04-18 12:38:53 -07:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (options->draw_mode == GIMP_MATTING_DRAW_MODE_FOREGROUND)
|
2018-05-13 10:21:57 -07:00
|
|
|
status_mode = _("Selecting foreground");
|
2014-04-18 12:52:38 -07:00
|
|
|
else if (options->draw_mode == GIMP_MATTING_DRAW_MODE_BACKGROUND)
|
2018-05-13 10:21:57 -07:00
|
|
|
status_mode = _("Selecting background");
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
2018-05-13 10:21:57 -07:00
|
|
|
status_mode = _("Selecting unknown");
|
2013-12-08 21:22:34 -08:00
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
|
|
|
|
status_stage = _("press Enter to preview.");
|
|
|
|
|
else
|
|
|
|
|
status_stage = _("press Escape to exit preview or Enter to apply.");
|
2013-12-08 21:22:34 -08:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
|
|
|
|
|
if (proximity && status_stage)
|
2013-12-08 21:22:34 -08:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
if (status_mode)
|
2018-05-13 10:21:57 -07:00
|
|
|
gimp_tool_replace_status (tool, display, "%s, %s", status_mode, status_stage);
|
2014-04-18 12:52:38 -07:00
|
|
|
else
|
|
|
|
|
gimp_tool_replace_status (tool, display, "%s", status_stage);
|
2013-12-08 21:22:34 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-28 18:48:56 -07:00
|
|
|
static void
|
2014-04-18 12:52:38 -07:00
|
|
|
gimp_foreground_select_tool_cursor_update (GimpTool *tool,
|
|
|
|
|
const GimpCoords *coords,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GimpDisplay *display)
|
2005-07-28 18:48:56 -07:00
|
|
|
{
|
2005-07-30 12:48:49 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
2005-07-31 07:27:46 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
switch (GIMP_SELECTION_TOOL (tool)->function)
|
2005-07-31 09:39:55 -07:00
|
|
|
{
|
2014-04-18 12:52:38 -07:00
|
|
|
case SELECTION_MOVE_MASK:
|
|
|
|
|
case SELECTION_MOVE:
|
|
|
|
|
case SELECTION_MOVE_COPY:
|
|
|
|
|
case SELECTION_ANCHOR:
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2005-07-31 09:39:55 -07:00
|
|
|
}
|
2005-07-31 07:27:46 -07:00
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
|
|
|
|
|
GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
|
2014-04-16 14:03:57 -07:00
|
|
|
}
|
|
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
static const gchar *
|
2017-07-04 09:48:03 -07:00
|
|
|
gimp_foreground_select_tool_can_undo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display)
|
2014-04-18 15:34:21 -07:00
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
|
|
|
|
if (fg_select->undo_stack)
|
|
|
|
|
{
|
|
|
|
|
StrokeUndo *undo = fg_select->undo_stack->data;
|
|
|
|
|
const gchar *desc;
|
|
|
|
|
|
|
|
|
|
if (gimp_enum_get_value (GIMP_TYPE_MATTING_DRAW_MODE, undo->draw_mode,
|
|
|
|
|
NULL, NULL, &desc, NULL))
|
|
|
|
|
{
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const gchar *
|
2017-07-04 09:48:03 -07:00
|
|
|
gimp_foreground_select_tool_can_redo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display)
|
2014-04-18 15:34:21 -07:00
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
|
|
|
|
|
if (fg_select->redo_stack)
|
|
|
|
|
{
|
|
|
|
|
StrokeUndo *undo = fg_select->redo_stack->data;
|
|
|
|
|
const gchar *desc;
|
|
|
|
|
|
|
|
|
|
if (gimp_enum_get_value (GIMP_TYPE_MATTING_DRAW_MODE, undo->draw_mode,
|
|
|
|
|
NULL, NULL, &desc, NULL))
|
|
|
|
|
{
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_foreground_select_tool_undo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display)
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
2017-07-09 08:22:06 -07:00
|
|
|
StrokeUndo *undo = fg_select->undo_stack->data;
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
gimp_foreground_select_undo_pop (undo, fg_select->trimap);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
fg_select->undo_stack = g_list_remove (fg_select->undo_stack, undo);
|
|
|
|
|
fg_select->redo_stack = g_list_prepend (fg_select->redo_stack, undo);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
|
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
|
|
|
|
else
|
|
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
return TRUE;
|
2014-04-18 15:34:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_foreground_select_tool_redo (GimpTool *tool,
|
|
|
|
|
GimpDisplay *display)
|
|
|
|
|
{
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
2017-07-09 08:22:06 -07:00
|
|
|
StrokeUndo *undo = fg_select->redo_stack->data;
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
gimp_foreground_select_undo_pop (undo, fg_select->trimap);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
fg_select->redo_stack = g_list_remove (fg_select->redo_stack, undo);
|
|
|
|
|
fg_select->undo_stack = g_list_prepend (fg_select->undo_stack, undo);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
|
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
|
|
|
|
else
|
|
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
2017-07-09 08:22:06 -07:00
|
|
|
return TRUE;
|
2014-04-18 15:34:21 -07:00
|
|
|
}
|
|
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_options_notify (GimpTool *tool,
|
|
|
|
|
GimpToolOptions *options,
|
|
|
|
|
const GParamSpec *pspec)
|
|
|
|
|
{
|
2014-06-03 14:05:23 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
|
|
|
|
GimpForegroundSelectOptions *fg_options;
|
|
|
|
|
|
|
|
|
|
fg_options = GIMP_FOREGROUND_SELECT_OPTIONS (options);
|
2014-04-18 17:51:00 -07:00
|
|
|
|
|
|
|
|
if (! tool->display)
|
|
|
|
|
return;
|
|
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
if (! strcmp (pspec->name, "mask-color"))
|
2005-07-31 07:27:46 -07:00
|
|
|
{
|
2014-04-18 17:51:00 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
2014-06-03 14:05:23 -07:00
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
|
|
|
|
}
|
2014-04-18 17:51:00 -07:00
|
|
|
else if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-06-03 14:05:23 -07:00
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_set_preview (fg_select);
|
|
|
|
|
}
|
2014-04-18 17:51:00 -07:00
|
|
|
}
|
|
|
|
|
else if (! strcmp (pspec->name, "engine"))
|
|
|
|
|
{
|
|
|
|
|
if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-06-03 14:05:23 -07:00
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
|
|
|
|
}
|
2014-04-18 17:51:00 -07:00
|
|
|
}
|
|
|
|
|
else if (! strcmp (pspec->name, "iterations"))
|
|
|
|
|
{
|
|
|
|
|
if (fg_options->engine == GIMP_MATTING_ENGINE_GLOBAL &&
|
|
|
|
|
fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-06-03 14:05:23 -07:00
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
|
|
|
|
}
|
2014-04-18 17:51:00 -07:00
|
|
|
}
|
|
|
|
|
else if (! strcmp (pspec->name, "levels") ||
|
|
|
|
|
! strcmp (pspec->name, "active-levels"))
|
|
|
|
|
{
|
|
|
|
|
if (fg_options->engine == GIMP_MATTING_ENGINE_LEVIN &&
|
|
|
|
|
fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-06-03 14:05:23 -07:00
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
|
|
|
|
}
|
2005-07-31 07:27:46 -07:00
|
|
|
}
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
2005-08-06 16:04:23 -07:00
|
|
|
static void
|
2013-06-22 13:26:46 -07:00
|
|
|
gimp_foreground_select_tool_get_area (GeglBuffer *mask,
|
|
|
|
|
gint *x1,
|
|
|
|
|
gint *y1,
|
|
|
|
|
gint *x2,
|
|
|
|
|
gint *y2)
|
2005-08-06 16:04:23 -07:00
|
|
|
{
|
|
|
|
|
gint width;
|
|
|
|
|
gint height;
|
|
|
|
|
|
2013-06-22 13:26:46 -07:00
|
|
|
gimp_gegl_mask_bounds (mask, x1, y1, x2, y2);
|
2005-08-06 16:04:23 -07:00
|
|
|
|
|
|
|
|
width = *x2 - *x1;
|
|
|
|
|
height = *y2 - *y1;
|
|
|
|
|
|
|
|
|
|
*x1 = MAX (*x1 - width / 2, 0);
|
|
|
|
|
*y1 = MAX (*y1 - height / 2, 0);
|
2008-11-02 16:09:01 -08:00
|
|
|
*x2 = MIN (*x2 + width / 2, gimp_item_get_width (GIMP_ITEM (mask)));
|
|
|
|
|
*y2 = MIN (*y2 + height / 2, gimp_item_get_height (GIMP_ITEM (mask)));
|
2005-08-06 16:04:23 -07:00
|
|
|
}
|
|
|
|
|
|
2005-07-28 18:48:56 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool)
|
|
|
|
|
{
|
2014-06-03 14:05:23 -07:00
|
|
|
GimpTool *tool = GIMP_TOOL (draw_tool);
|
|
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
|
2005-08-06 14:39:43 -07:00
|
|
|
GimpForegroundSelectOptions *options;
|
|
|
|
|
|
2014-06-03 14:05:23 -07:00
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
|
2005-07-31 07:27:46 -07:00
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->state == MATTING_STATE_FREE_SELECT)
|
2005-07-31 11:29:10 -07:00
|
|
|
{
|
2014-04-16 14:03:57 -07:00
|
|
|
GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
|
|
|
|
|
return;
|
2005-07-31 11:29:10 -07:00
|
|
|
}
|
2014-04-16 14:03:57 -07:00
|
|
|
else
|
2005-08-06 14:39:43 -07:00
|
|
|
{
|
2014-04-16 14:03:57 -07:00
|
|
|
gint x = fg_select->last_coords.x;
|
|
|
|
|
gint y = fg_select->last_coords.y;
|
2014-08-15 17:38:55 -07:00
|
|
|
gdouble radius = options->stroke_width / 2.0f;
|
2005-08-06 16:04:23 -07:00
|
|
|
|
2014-04-16 14:03:57 -07:00
|
|
|
if (fg_select->stroke)
|
|
|
|
|
{
|
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
|
|
|
|
|
|
|
|
|
|
gimp_draw_tool_add_pen (draw_tool,
|
|
|
|
|
(const GimpVector2 *) fg_select->stroke->data,
|
|
|
|
|
fg_select->stroke->len,
|
|
|
|
|
GIMP_CONTEXT (options),
|
|
|
|
|
GIMP_ACTIVE_COLOR_FOREGROUND,
|
|
|
|
|
options->stroke_width * shell->scale_y);
|
|
|
|
|
}
|
2005-08-06 16:04:23 -07:00
|
|
|
|
|
|
|
|
/* warn if the user is drawing outside of the working area */
|
2005-08-07 16:13:53 -07:00
|
|
|
if (FALSE)
|
|
|
|
|
{
|
|
|
|
|
gint x1, y1;
|
|
|
|
|
gint x2, y2;
|
|
|
|
|
|
|
|
|
|
gimp_foreground_select_tool_get_area (fg_select->mask,
|
|
|
|
|
&x1, &y1, &x2, &y2);
|
|
|
|
|
|
|
|
|
|
if (x < x1 + radius || x > x2 - radius ||
|
|
|
|
|
y < y1 + radius || y > y2 - radius)
|
|
|
|
|
{
|
2010-09-25 10:02:22 -07:00
|
|
|
gimp_draw_tool_add_rectangle (draw_tool, FALSE,
|
|
|
|
|
x1, y1,
|
|
|
|
|
x2 - x1, y2 - y1);
|
2005-08-07 16:13:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
2005-08-06 14:39:43 -07:00
|
|
|
|
2015-12-29 03:57:17 -08:00
|
|
|
if (x > FAR_OUTSIDE && y > FAR_OUTSIDE)
|
|
|
|
|
gimp_draw_tool_add_arc (draw_tool, FALSE,
|
|
|
|
|
x - radius, y - radius,
|
|
|
|
|
2 * radius, 2 * radius,
|
|
|
|
|
0.0, 2.0 * G_PI);
|
2005-08-06 14:39:43 -07:00
|
|
|
}
|
2005-07-28 18:48:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
|
2017-06-22 16:59:37 -07:00
|
|
|
GimpDisplay *display,
|
|
|
|
|
const GimpVector2 *points,
|
|
|
|
|
gint n_points)
|
2005-07-28 18:48:56 -07:00
|
|
|
{
|
2014-06-03 14:05:23 -07:00
|
|
|
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel);
|
|
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
|
|
|
|
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
|
2005-08-06 16:04:23 -07:00
|
|
|
|
2017-06-22 16:59:37 -07:00
|
|
|
if (drawable && fg_select->state == MATTING_STATE_FREE_SELECT)
|
2005-08-07 16:59:33 -07:00
|
|
|
{
|
2017-06-22 16:59:37 -07:00
|
|
|
GimpScanConvert *scan_convert = gimp_scan_convert_new ();
|
2005-08-05 17:51:22 -07:00
|
|
|
|
2017-06-22 16:59:37 -07:00
|
|
|
gimp_scan_convert_add_polyline (scan_convert, n_points, points, TRUE);
|
2005-07-28 18:48:56 -07:00
|
|
|
|
2014-06-03 14:05:23 -07:00
|
|
|
fg_select->trimap =
|
|
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
|
gimp_image_get_width (image),
|
|
|
|
|
gimp_image_get_height (image)),
|
|
|
|
|
gimp_image_get_mask_format (image));
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2013-06-22 13:26:46 -07:00
|
|
|
gimp_scan_convert_render_value (scan_convert, fg_select->trimap,
|
2014-04-12 12:31:38 -07:00
|
|
|
0, 0, 0.5);
|
2013-05-07 15:00:48 -07:00
|
|
|
gimp_scan_convert_free (scan_convert);
|
2005-08-07 16:59:33 -07:00
|
|
|
|
2017-12-07 10:49:37 -08:00
|
|
|
if (! gimp_tool_control_is_active (GIMP_TOOL (fg_select)->control))
|
|
|
|
|
{
|
|
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* if the tool is active we got here by double click
|
|
|
|
|
* detected in the parent class. We can't switch to trimap
|
|
|
|
|
* mode in the middle of a click. Set a flag and let
|
|
|
|
|
* button_release() forward the release to the parent class
|
|
|
|
|
* so it can conclude its operation
|
|
|
|
|
*/
|
|
|
|
|
fg_select->in_double_click = TRUE;
|
|
|
|
|
}
|
2005-08-07 16:59:33 -07:00
|
|
|
}
|
2013-05-07 15:00:48 -07:00
|
|
|
}
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2014-04-18 13:06:07 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_halt (GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
|
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&fg_select->trimap);
|
|
|
|
|
g_clear_object (&fg_select->mask);
|
2014-04-18 13:06:07 -07:00
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
if (fg_select->undo_stack)
|
|
|
|
|
{
|
|
|
|
|
g_list_free_full (fg_select->undo_stack,
|
|
|
|
|
(GDestroyNotify) gimp_foreground_select_undo_free);
|
|
|
|
|
fg_select->undo_stack = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fg_select->redo_stack)
|
|
|
|
|
{
|
|
|
|
|
g_list_free_full (fg_select->redo_stack,
|
|
|
|
|
(GDestroyNotify) gimp_foreground_select_undo_free);
|
|
|
|
|
fg_select->redo_stack = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 13:06:07 -07:00
|
|
|
if (tool->display)
|
|
|
|
|
gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
|
2016-02-05 12:19:17 -08:00
|
|
|
NULL, 0, 0, NULL, FALSE);
|
2014-04-18 13:06:07 -07:00
|
|
|
|
|
|
|
|
gimp_tool_control_set_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_FREE_SELECT);
|
|
|
|
|
gimp_tool_control_set_toggle_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_FREE_SELECT);
|
|
|
|
|
|
|
|
|
|
gimp_tool_control_set_toggled (tool->control, FALSE);
|
|
|
|
|
|
2019-01-31 01:37:56 -08:00
|
|
|
/* set precision to SUBPIXEL, because it may have been changed to
|
|
|
|
|
* PIXEL_CENTER if the tool has switched to MATTING_STATE_PAINT_TRIMAP,
|
|
|
|
|
* in gimp_foreground_select_tool_set_trimap().
|
|
|
|
|
*/
|
|
|
|
|
gimp_tool_control_set_precision (tool->control,
|
|
|
|
|
GIMP_CURSOR_PRECISION_SUBPIXEL);
|
|
|
|
|
|
2014-04-18 13:06:07 -07:00
|
|
|
fg_select->state = MATTING_STATE_FREE_SELECT;
|
|
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
/* update the undo actions / menu items */
|
|
|
|
|
if (tool->display)
|
|
|
|
|
gimp_image_flush (gimp_display_get_image (tool->display));
|
|
|
|
|
|
2014-04-18 13:06:07 -07:00
|
|
|
tool->display = NULL;
|
|
|
|
|
tool->drawable = NULL;
|
|
|
|
|
|
|
|
|
|
if (fg_select->gui)
|
|
|
|
|
gimp_tool_gui_hide (fg_select->gui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_commit (GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
|
|
|
|
GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (fg_select);
|
|
|
|
|
|
|
|
|
|
if (tool->display && fg_select->state != MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
|
|
|
|
GimpImage *image = gimp_display_get_image (tool->display);
|
|
|
|
|
|
|
|
|
|
if (fg_select->state != MATTING_STATE_PREVIEW_MASK)
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
2014-04-18 13:06:07 -07:00
|
|
|
|
|
|
|
|
gimp_channel_select_buffer (gimp_image_get_mask (image),
|
|
|
|
|
C_("command", "Foreground Select"),
|
|
|
|
|
fg_select->mask,
|
|
|
|
|
0, /* x offset */
|
|
|
|
|
0, /* y offset */
|
|
|
|
|
options->operation,
|
|
|
|
|
options->feather,
|
|
|
|
|
options->feather_radius,
|
|
|
|
|
options->feather_radius);
|
|
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
static void
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_set_trimap (GimpForegroundSelectTool *fg_select)
|
2013-05-07 15:00:48 -07:00
|
|
|
{
|
|
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
|
|
|
|
GimpForegroundSelectOptions *options;
|
|
|
|
|
GimpRGB color;
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
g_return_if_fail (fg_select->trimap != NULL);
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
|
2005-10-17 11:23:31 -07:00
|
|
|
|
2018-06-14 16:45:04 -07:00
|
|
|
gimp_free_select_tool_halt (GIMP_FREE_SELECT_TOOL (fg_select));
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
gimp_foreground_select_options_get_mask_color (options, &color);
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
|
2016-02-05 12:19:17 -08:00
|
|
|
fg_select->trimap, 0, 0, &color, TRUE);
|
2013-05-07 15:00:48 -07:00
|
|
|
|
|
|
|
|
gimp_tool_control_set_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_PAINTBRUSH);
|
|
|
|
|
gimp_tool_control_set_toggle_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_PAINTBRUSH);
|
2005-08-07 16:59:33 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
gimp_tool_control_set_toggled (tool->control, FALSE);
|
2005-07-30 11:19:54 -07:00
|
|
|
|
2018-04-08 04:03:11 -07:00
|
|
|
/* disable double click in paint trimap state */
|
|
|
|
|
gimp_tool_control_set_wants_double_click (tool->control, FALSE);
|
|
|
|
|
|
2019-01-31 01:37:56 -08:00
|
|
|
/* set precision to PIXEL_CENTER in paint trimap state */
|
|
|
|
|
gimp_tool_control_set_precision (tool->control,
|
|
|
|
|
GIMP_CURSOR_PRECISION_PIXEL_CENTER);
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
fg_select->state = MATTING_STATE_PAINT_TRIMAP;
|
2014-04-18 12:38:53 -07:00
|
|
|
|
|
|
|
|
gimp_foreground_select_tool_update_gui (fg_select);
|
2005-07-30 11:19:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_set_preview (GimpForegroundSelectTool *fg_select)
|
2005-07-30 11:19:54 -07:00
|
|
|
{
|
2013-05-07 15:00:48 -07:00
|
|
|
|
2006-03-17 05:27:08 -08:00
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
|
|
|
|
GimpForegroundSelectOptions *options;
|
2013-05-07 15:00:48 -07:00
|
|
|
GimpRGB color;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (fg_select->mask != NULL);
|
2005-07-31 11:29:10 -07:00
|
|
|
|
2006-09-05 11:25:31 -07:00
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
gimp_foreground_select_options_get_mask_color (options, &color);
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
|
2016-02-05 12:19:17 -08:00
|
|
|
fg_select->mask, 0, 0, &color, TRUE);
|
2013-05-07 15:00:48 -07:00
|
|
|
|
|
|
|
|
gimp_tool_control_set_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_PAINTBRUSH);
|
|
|
|
|
gimp_tool_control_set_toggle_tool_cursor (tool->control,
|
|
|
|
|
GIMP_TOOL_CURSOR_PAINTBRUSH);
|
|
|
|
|
|
|
|
|
|
gimp_tool_control_set_toggled (tool->control, FALSE);
|
|
|
|
|
|
|
|
|
|
fg_select->state = MATTING_STATE_PREVIEW_MASK;
|
2014-04-18 12:38:53 -07:00
|
|
|
|
|
|
|
|
gimp_foreground_select_tool_update_gui (fg_select);
|
2013-05-07 15:00:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select)
|
2013-05-07 15:00:48 -07:00
|
|
|
{
|
|
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
2014-06-03 14:05:23 -07:00
|
|
|
GimpForegroundSelectOptions *options;
|
2014-04-18 18:35:31 -07:00
|
|
|
GimpImage *image = gimp_display_get_image (tool->display);
|
2013-05-07 15:00:48 -07:00
|
|
|
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
|
2014-06-03 14:05:23 -07:00
|
|
|
|
|
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
|
2013-05-07 15:00:48 -07:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&fg_select->mask);
|
2005-07-31 11:29:10 -07:00
|
|
|
|
2014-06-03 14:05:23 -07:00
|
|
|
fg_select->mask = gimp_drawable_foreground_extract (drawable,
|
|
|
|
|
options->engine,
|
|
|
|
|
options->iterations,
|
|
|
|
|
options->levels,
|
|
|
|
|
options->active_levels,
|
|
|
|
|
fg_select->trimap,
|
|
|
|
|
GIMP_PROGRESS (fg_select));
|
2013-05-07 15:00:48 -07:00
|
|
|
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_set_preview (fg_select);
|
2005-07-30 11:19:54 -07:00
|
|
|
}
|
|
|
|
|
|
2005-07-31 07:27:46 -07:00
|
|
|
static void
|
2014-04-16 16:52:21 -07:00
|
|
|
gimp_foreground_select_tool_stroke_paint (GimpForegroundSelectTool *fg_select)
|
2005-07-31 07:27:46 -07:00
|
|
|
{
|
2014-04-16 16:52:21 -07:00
|
|
|
GimpForegroundSelectOptions *options;
|
|
|
|
|
GimpScanConvert *scan_convert;
|
2014-04-18 15:34:21 -07:00
|
|
|
StrokeUndo *undo;
|
2014-04-16 16:52:21 -07:00
|
|
|
gint width;
|
|
|
|
|
gdouble opacity;
|
|
|
|
|
|
|
|
|
|
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (fg_select);
|
2013-05-07 15:00:48 -07:00
|
|
|
|
|
|
|
|
g_return_if_fail (fg_select->stroke != NULL);
|
|
|
|
|
|
2014-04-18 15:34:21 -07:00
|
|
|
width = ROUND ((gdouble) options->stroke_width);
|
|
|
|
|
|
|
|
|
|
if (fg_select->redo_stack)
|
|
|
|
|
{
|
|
|
|
|
g_list_free_full (fg_select->redo_stack,
|
|
|
|
|
(GDestroyNotify) gimp_foreground_select_undo_free);
|
|
|
|
|
fg_select->redo_stack = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
undo = gimp_foreground_select_undo_new (fg_select->trimap,
|
|
|
|
|
fg_select->stroke,
|
|
|
|
|
options->draw_mode, width);
|
2016-06-25 02:12:13 -07:00
|
|
|
if (! undo)
|
|
|
|
|
{
|
|
|
|
|
g_array_free (fg_select->stroke, TRUE);
|
|
|
|
|
fg_select->stroke = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
fg_select->undo_stack = g_list_prepend (fg_select->undo_stack, undo);
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
scan_convert = gimp_scan_convert_new ();
|
2005-07-31 07:27:46 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
if (fg_select->stroke->len == 1)
|
2005-08-06 06:50:02 -07:00
|
|
|
{
|
|
|
|
|
GimpVector2 points[2];
|
|
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
points[0] = points[1] = ((GimpVector2 *) fg_select->stroke->data)[0];
|
2005-08-06 06:50:02 -07:00
|
|
|
|
|
|
|
|
points[1].x += 0.01;
|
|
|
|
|
points[1].y += 0.01;
|
|
|
|
|
|
|
|
|
|
gimp_scan_convert_add_polyline (scan_convert, 2, points, FALSE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gimp_scan_convert_add_polyline (scan_convert,
|
2013-05-07 15:00:48 -07:00
|
|
|
fg_select->stroke->len,
|
|
|
|
|
(GimpVector2 *) fg_select->stroke->data,
|
2005-08-06 06:50:02 -07:00
|
|
|
FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-31 07:27:46 -07:00
|
|
|
gimp_scan_convert_stroke (scan_convert,
|
2013-05-07 15:00:48 -07:00
|
|
|
width,
|
2005-08-07 17:33:51 -07:00
|
|
|
GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0,
|
2005-07-31 07:27:46 -07:00
|
|
|
0.0, NULL);
|
|
|
|
|
|
2013-12-08 21:22:34 -08:00
|
|
|
if (options->draw_mode == GIMP_MATTING_DRAW_MODE_FOREGROUND)
|
|
|
|
|
opacity = 1.0;
|
|
|
|
|
else if (options->draw_mode == GIMP_MATTING_DRAW_MODE_BACKGROUND)
|
|
|
|
|
opacity = 0.0;
|
|
|
|
|
else
|
|
|
|
|
opacity = 0.5;
|
|
|
|
|
|
2013-06-22 13:26:46 -07:00
|
|
|
gimp_scan_convert_compose_value (scan_convert, fg_select->trimap,
|
2013-05-07 15:00:48 -07:00
|
|
|
0, 0,
|
2013-12-08 21:22:34 -08:00
|
|
|
opacity);
|
2005-08-02 09:07:16 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
gimp_scan_convert_free (scan_convert);
|
2005-07-31 07:27:46 -07:00
|
|
|
|
2013-05-07 15:00:48 -07:00
|
|
|
g_array_free (fg_select->stroke, TRUE);
|
2005-08-02 09:07:16 -07:00
|
|
|
fg_select->stroke = NULL;
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
/* update the undo actions / menu items */
|
|
|
|
|
gimp_image_flush (gimp_display_get_image (GIMP_TOOL (fg_select)->display));
|
2005-08-06 13:01:22 -07:00
|
|
|
}
|
2014-04-16 16:52:21 -07:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_cancel_paint (GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (fg_select->stroke != NULL);
|
|
|
|
|
|
|
|
|
|
g_array_free (fg_select->stroke, TRUE);
|
|
|
|
|
fg_select->stroke = NULL;
|
|
|
|
|
}
|
2014-04-18 12:52:38 -07:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_response (GimpToolGui *gui,
|
|
|
|
|
gint response_id,
|
|
|
|
|
GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
2014-04-18 13:37:33 -07:00
|
|
|
GimpTool *tool = GIMP_TOOL (fg_select);
|
2014-04-18 12:52:38 -07:00
|
|
|
|
|
|
|
|
switch (response_id)
|
|
|
|
|
{
|
2014-04-18 13:15:35 -07:00
|
|
|
case GTK_RESPONSE_APPLY:
|
2014-04-18 13:37:33 -07:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, tool->display);
|
2017-12-07 10:49:37 -08:00
|
|
|
break;
|
2014-04-18 12:52:38 -07:00
|
|
|
|
|
|
|
|
default:
|
2014-04-18 13:37:33 -07:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
2014-04-18 12:52:38 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 13:37:33 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_preview_toggled (GtkToggleButton *button,
|
|
|
|
|
GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
if (fg_select->state != MATTING_STATE_FREE_SELECT)
|
|
|
|
|
{
|
|
|
|
|
if (gtk_toggle_button_get_active (button))
|
|
|
|
|
{
|
|
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_preview (fg_select);
|
2014-04-18 13:37:33 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
2014-04-18 18:35:31 -07:00
|
|
|
gimp_foreground_select_tool_set_trimap (fg_select);
|
2014-04-18 13:37:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 12:52:38 -07:00
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_tool_update_gui (GimpForegroundSelectTool *fg_select)
|
|
|
|
|
{
|
|
|
|
|
if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_gui_set_description (fg_select->gui, _("Paint mask"));
|
|
|
|
|
}
|
|
|
|
|
else if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_gui_set_description (fg_select->gui, _("Preview"));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 13:15:35 -07:00
|
|
|
gimp_tool_gui_set_response_sensitive (fg_select->gui, GTK_RESPONSE_APPLY,
|
|
|
|
|
TRUE);
|
2014-04-18 13:37:33 -07:00
|
|
|
gtk_widget_set_sensitive (fg_select->preview_toggle, TRUE);
|
2014-04-18 12:52:38 -07:00
|
|
|
}
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
static StrokeUndo *
|
|
|
|
|
gimp_foreground_select_undo_new (GeglBuffer *trimap,
|
|
|
|
|
GArray *stroke,
|
|
|
|
|
GimpMattingDrawMode draw_mode,
|
|
|
|
|
gint stroke_width)
|
|
|
|
|
|
|
|
|
|
{
|
2016-06-25 02:12:13 -07:00
|
|
|
StrokeUndo *undo;
|
2014-04-18 15:34:21 -07:00
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
|
gint width, height;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
x1 = G_MAXINT;
|
|
|
|
|
y1 = G_MAXINT;
|
|
|
|
|
x2 = G_MININT;
|
|
|
|
|
y2 = G_MININT;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < stroke->len; i++)
|
|
|
|
|
{
|
|
|
|
|
GimpVector2 *point = &g_array_index (stroke, GimpVector2, i);
|
|
|
|
|
|
|
|
|
|
x1 = MIN (x1, floor (point->x));
|
|
|
|
|
y1 = MIN (y1, floor (point->y));
|
|
|
|
|
x2 = MAX (x2, ceil (point->x));
|
|
|
|
|
y2 = MAX (y2, ceil (point->y));
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-25 02:12:13 -07:00
|
|
|
x1 -= (stroke_width + 1) / 2;
|
|
|
|
|
y1 -= (stroke_width + 1) / 2;
|
|
|
|
|
x2 += (stroke_width + 1) / 2;
|
|
|
|
|
y2 += (stroke_width + 1) / 2;
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
x1 = MAX (x1, 0);
|
|
|
|
|
y1 = MAX (y1, 0);
|
|
|
|
|
x2 = MIN (x2, gegl_buffer_get_width (trimap));
|
|
|
|
|
y2 = MIN (y2, gegl_buffer_get_height (trimap));
|
|
|
|
|
|
|
|
|
|
width = x2 - x1;
|
|
|
|
|
height = y2 - y1;
|
|
|
|
|
|
2016-06-25 02:12:13 -07:00
|
|
|
if (width <= 0 || height <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
undo = g_slice_new0 (StrokeUndo);
|
2014-04-18 15:34:21 -07:00
|
|
|
undo->saved_trimap = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
|
gegl_buffer_get_format (trimap));
|
|
|
|
|
|
2018-05-24 07:21:21 -07:00
|
|
|
gimp_gegl_buffer_copy (
|
|
|
|
|
trimap, GEGL_RECTANGLE (x1, y1, width, height),
|
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
undo->saved_trimap, GEGL_RECTANGLE (0, 0, width, height));
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
undo->trimap_x = x1;
|
|
|
|
|
undo->trimap_y = y1;
|
|
|
|
|
|
|
|
|
|
undo->draw_mode = draw_mode;
|
|
|
|
|
undo->stroke_width = stroke_width;
|
|
|
|
|
|
|
|
|
|
return undo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_undo_pop (StrokeUndo *undo,
|
|
|
|
|
GeglBuffer *trimap)
|
|
|
|
|
{
|
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
|
gint width, height;
|
|
|
|
|
|
|
|
|
|
buffer = gegl_buffer_dup (undo->saved_trimap);
|
|
|
|
|
|
|
|
|
|
width = gegl_buffer_get_width (buffer);
|
|
|
|
|
height = gegl_buffer_get_height (buffer);
|
|
|
|
|
|
2018-05-24 07:21:21 -07:00
|
|
|
gimp_gegl_buffer_copy (trimap,
|
|
|
|
|
GEGL_RECTANGLE (undo->trimap_x, undo->trimap_y,
|
|
|
|
|
width, height),
|
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
undo->saved_trimap,
|
|
|
|
|
GEGL_RECTANGLE (0, 0, width, height));
|
|
|
|
|
|
|
|
|
|
gimp_gegl_buffer_copy (buffer,
|
|
|
|
|
GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
trimap,
|
|
|
|
|
GEGL_RECTANGLE (undo->trimap_x, undo->trimap_y,
|
|
|
|
|
width, height));
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
g_object_unref (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_foreground_select_undo_free (StrokeUndo *undo)
|
|
|
|
|
{
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&undo->saved_trimap);
|
2014-04-18 15:34:21 -07:00
|
|
|
|
|
|
|
|
g_slice_free (StrokeUndo, undo);
|
|
|
|
|
}
|