[gimp] app, icons: add Paint Select tool in the playground



commit e1cdb9f54e1ee385b78190b9c5a60126ea6b29e2
Author: Thomas Manni <thomas manni free fr>
Date:   Sat Nov 7 12:59:45 2020 +0100

    app, icons: add Paint Select tool in the playground
    
    A -quick done- first step towards the addition of a smart selection tool.
    Require the gegl:paint-select workshop operation.
    Still LOT of work to do (wip):
    - fluctuations removal (GEGL side)
    - multilevels pyramid approach + banded graphcut for instant result on large
       image (GEGL ? GIMP ?)
    - Gaussian Mixtures for color models (GEGL side)
    - drawable offsets (GIMP side)
    - undo / redo (GIMP side)
    - scribbles edition mode (GIMP side)
    - dedicated icons
    - ...

 app/config/gimpguiconfig.c                         |  16 +
 app/config/gimpguiconfig.h                         |   1 +
 app/config/gimprc-blurbs.h                         |   3 +
 app/dialogs/preferences-dialog.c                   |   3 +
 app/tools/Makefile.am                              |   4 +
 app/tools/gimp-tools.c                             |   2 +
 app/tools/gimppaintselectoptions.c                 | 188 ++++++
 app/tools/gimppaintselectoptions.h                 |  57 ++
 app/tools/gimppaintselecttool.c                    | 728 +++++++++++++++++++++
 app/tools/gimppaintselecttool.h                    |  67 ++
 app/tools/meson.build                              |   2 +
 app/tools/tools-enums.c                            |  17 +
 app/tools/tools-enums.h                            |  10 +
 icons/Color/16/gimp-tool-paint-select.png          | Bin 0 -> 718 bytes
 icons/Color/24/gimp-tool-paint-select.png          | Bin 0 -> 1071 bytes
 icons/Color/24/gimp-tool-paint-select.svg          | 235 +++++++
 icons/Color/icon-list.mk                           |   4 +
 icons/Color/scalable/gimp-tool-paint-select.svg    | 263 ++++++++
 .../24/gimp-tool-paint-select-symbolic.svg         | 137 ++++
 icons/Symbolic/icon-list.mk                        |   2 +
 .../scalable/gimp-tool-paint-select-symbolic.svg   | 153 +++++
 libgimpwidgets/gimpicons.h                         |   1 +
 menus/image-menu.xml.in                            |   1 +
 23 files changed, 1894 insertions(+)
---
diff --git a/app/config/gimpguiconfig.c b/app/config/gimpguiconfig.c
index 83b3b51745..c49e6897ab 100644
--- a/app/config/gimpguiconfig.c
+++ b/app/config/gimpguiconfig.c
@@ -86,6 +86,7 @@ enum
 
   PROP_PLAYGROUND_NPD_TOOL,
   PROP_PLAYGROUND_SEAMLESS_CLONE_TOOL,
+  PROP_PLAYGROUND_PAINT_SELECT_TOOL,
 
   PROP_HIDE_DOCKS,
   PROP_SINGLE_WINDOW_MODE,
@@ -417,6 +418,15 @@ gimp_gui_config_class_init (GimpGuiConfigClass *klass)
                             GIMP_PARAM_STATIC_STRINGS |
                             GIMP_CONFIG_PARAM_RESTART);
 
+  GIMP_CONFIG_PROP_BOOLEAN (object_class,
+                            PROP_PLAYGROUND_PAINT_SELECT_TOOL,
+                            "playground-paint-select-tool",
+                            "Playground Paint Select tool",
+                            PLAYGROUND_PAINT_SELECT_TOOL_BLURB,
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS |
+                            GIMP_CONFIG_PARAM_RESTART);
+
   g_object_class_install_property (object_class, PROP_HIDE_DOCKS,
                                    g_param_spec_boolean ("hide-docks",
                                                          NULL,
@@ -683,6 +693,9 @@ gimp_gui_config_set_property (GObject      *object,
     case PROP_PLAYGROUND_SEAMLESS_CLONE_TOOL:
       gui_config->playground_seamless_clone_tool = g_value_get_boolean (value);
       break;
+    case PROP_PLAYGROUND_PAINT_SELECT_TOOL:
+      gui_config->playground_paint_select_tool = g_value_get_boolean (value);
+      break;
 
     case PROP_HIDE_DOCKS:
       gui_config->hide_docks = g_value_get_boolean (value);
@@ -846,6 +859,9 @@ gimp_gui_config_get_property (GObject    *object,
     case PROP_PLAYGROUND_SEAMLESS_CLONE_TOOL:
       g_value_set_boolean (value, gui_config->playground_seamless_clone_tool);
       break;
+    case PROP_PLAYGROUND_PAINT_SELECT_TOOL:
+      g_value_set_boolean (value, gui_config->playground_paint_select_tool);
+      break;
 
     case PROP_HIDE_DOCKS:
       g_value_set_boolean (value, gui_config->hide_docks);
diff --git a/app/config/gimpguiconfig.h b/app/config/gimpguiconfig.h
index ac1c6b59df..ce0997443c 100644
--- a/app/config/gimpguiconfig.h
+++ b/app/config/gimpguiconfig.h
@@ -82,6 +82,7 @@ struct _GimpGuiConfig
   /* experimental playground */
   gboolean             playground_npd_tool;
   gboolean             playground_seamless_clone_tool;
+  gboolean             playground_paint_select_tool;
 
   /* saved in sessionrc */
   gboolean             hide_docks;
diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h
index 507b59234b..daa5b0fe9f 100644
--- a/app/config/gimprc-blurbs.h
+++ b/app/config/gimprc-blurbs.h
@@ -478,6 +478,9 @@ _("Enable the MyPaint Brush tool.")
 #define PLAYGROUND_SEAMLESS_CLONE_TOOL_BLURB \
 _("Enable the Seamless Clone tool.")
 
+#define PLAYGROUND_PAINT_SELECT_TOOL_BLURB \
+_("Enable the Paint Select tool.")
+
 #define SPACE_BAR_ACTION_BLURB \
 _("What to do when the space bar is pressed in the image window.")
 
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index 2aafa0a26c..8187be7825 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -1648,6 +1648,9 @@ prefs_dialog_new (Gimp       *gimp,
       button = prefs_check_button_add (object, "playground-seamless-clone-tool",
                                        _("_Seamless Clone tool"),
                                        GTK_BOX (vbox2));
+      button = prefs_check_button_add (object, "playground-paint-select-tool",
+                                       _("_Paint Select tool"),
+                                       GTK_BOX (vbox2));
     }
 
 
diff --git a/app/tools/Makefile.am b/app/tools/Makefile.am
index bbe45841cd..a9e7221c9e 100644
--- a/app/tools/Makefile.am
+++ b/app/tools/Makefile.am
@@ -152,6 +152,10 @@ libapptools_a_sources = \
        gimppaintbrushtool.h            \
        gimppaintoptions-gui.c          \
        gimppaintoptions-gui.h          \
+       gimppaintselectoptions.c        \
+       gimppaintselectoptions.h        \
+       gimppaintselecttool.c           \
+       gimppaintselecttool.h           \
        gimppainttool.c                 \
        gimppainttool.h                 \
        gimppainttool-paint.c           \
diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c
index 94d22a81ee..067af787ee 100644
--- a/app/tools/gimp-tools.c
+++ b/app/tools/gimp-tools.c
@@ -75,6 +75,7 @@
 #include "gimpnpointdeformationtool.h"
 #include "gimpoffsettool.h"
 #include "gimppaintbrushtool.h"
+#include "gimppaintselecttool.h"
 #include "gimppenciltool.h"
 #include "gimpperspectiveclonetool.h"
 #include "gimpperspectivetool.h"
@@ -140,6 +141,7 @@ gimp_tools_init (Gimp *gimp)
     gimp_by_color_select_tool_register,
     gimp_iscissors_tool_register,
     gimp_foreground_select_tool_register,
+    gimp_paint_select_tool_register,
 
     /*  path tool */
 
diff --git a/app/tools/gimppaintselectoptions.c b/app/tools/gimppaintselectoptions.c
new file mode 100644
index 0000000000..9c707036a4
--- /dev/null
+++ b/app/tools/gimppaintselectoptions.c
@@ -0,0 +1,188 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (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
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpconfig/gimpconfig.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "tools-types.h"
+
+#include "widgets/gimppropwidgets.h"
+#include "widgets/gimpspinscale.h"
+#include "widgets/gimpwidgets-constructors.h"
+#include "widgets/gimpwidgets-utils.h"
+
+#include "core/gimptooloptions.h"
+#include "gimppaintselectoptions.h"
+#include "gimptooloptions-gui.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_MODE,
+  PROP_STROKE_WIDTH,
+};
+
+
+static void   gimp_paint_select_options_set_property      (GObject      *object,
+                                                           guint         property_id,
+                                                           const GValue *value,
+                                                           GParamSpec   *pspec);
+static void   gimp_paint_select_options_get_property      (GObject      *object,
+                                                           guint         property_id,
+                                                           GValue       *value,
+                                                           GParamSpec   *pspec);
+
+
+G_DEFINE_TYPE (GimpPaintSelectOptions, gimp_paint_select_options,
+               GIMP_TYPE_TOOL_OPTIONS)
+
+
+static void
+gimp_paint_select_options_class_init (GimpPaintSelectOptionsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (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_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_PROP_INT  (object_class, PROP_STROKE_WIDTH,
+                         "stroke-width",
+                         _("Stroke width"),
+                         _("Size of the brush used for refinements"),
+                         1, 6000, 50,
+                         GIMP_PARAM_STATIC_STRINGS);
+}
+
+static void
+gimp_paint_select_options_init (GimpPaintSelectOptions *options)
+{
+}
+
+static void
+gimp_paint_select_options_set_property (GObject      *object,
+                                        guint         property_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_OPTIONS (object);
+
+  switch (property_id)
+    {
+    case PROP_MODE:
+      options->mode = g_value_get_enum (value);
+      break;
+
+    case PROP_STROKE_WIDTH:
+      options->stroke_width = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_paint_select_options_get_property (GObject    *object,
+                                        guint       property_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_OPTIONS (object);
+
+  switch (property_id)
+    {
+    case PROP_MODE:
+      g_value_set_enum (value, options->mode);
+      break;
+
+    case PROP_STROKE_WIDTH:
+      g_value_set_int (value, options->stroke_width);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_paint_select_options_reset_stroke_width (GtkWidget       *button,
+                                              GimpToolOptions *tool_options)
+{
+  g_object_set (tool_options, "stroke-width", 10, NULL);
+}
+
+GtkWidget *
+gimp_paint_select_options_gui (GimpToolOptions *tool_options)
+{
+  GObject   *config = G_OBJECT (tool_options);
+  GtkWidget *vbox   = gimp_tool_options_gui (tool_options);
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkWidget *frame;
+  GtkWidget *scale;
+
+  frame = gimp_prop_enum_radio_frame_new (config, "mode", NULL,
+                                          0, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  /* stroke width */
+  scale = gimp_prop_spin_scale_new (config, "stroke-width", NULL,
+                                    1.0, 10.0, 2);
+  gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 1.0, 1000.0);
+  gimp_spin_scale_set_gamma (GIMP_SPIN_SCALE (scale), 1.7);
+  gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
+
+  button = gimp_icon_button_new (GIMP_ICON_RESET, NULL);
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  gtk_image_set_from_icon_name (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (button))),
+                                GIMP_ICON_RESET, GTK_ICON_SIZE_MENU);
+  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (gimp_paint_select_options_reset_stroke_width),
+                    tool_options);
+
+  gimp_help_set_help_data (button,
+                           _("Reset stroke width native size"), NULL);
+
+  return vbox;
+}
diff --git a/app/tools/gimppaintselectoptions.h b/app/tools/gimppaintselectoptions.h
new file mode 100644
index 0000000000..7c5cb201b6
--- /dev/null
+++ b/app/tools/gimppaintselectoptions.h
@@ -0,0 +1,57 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (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
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __GIMP_PAINT_SELECT_OPTIONS_H__
+#define __GIMP_PAINT_SELECT_OPTIONS_H__
+
+
+#include "core/gimptooloptions.h"
+
+
+#define GIMP_TYPE_PAINT_SELECT_OPTIONS            (gimp_paint_select_options_get_type ())
+#define GIMP_PAINT_SELECT_OPTIONS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_PAINT_SELECT_OPTIONS, GimpPaintSelectOptions))
+#define GIMP_PAINT_SELECT_OPTIONS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
GIMP_TYPE_PAINT_SELECT_OPTIONS, GimpPaintSelectOptionsClass))
+#define GIMP_IS_PAINT_SELECT_OPTIONS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_PAINT_SELECT_OPTIONS))
+#define GIMP_IS_PAINT_SELECT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GIMP_TYPE_PAINT_SELECT_OPTIONS))
+#define GIMP_PAINT_SELECT_OPTIONS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GIMP_TYPE_PAINT_SELECT_OPTIONS, GimpPaintSelectOptionsClass))
+
+
+typedef struct _GimpPaintSelectOptions      GimpPaintSelectOptions;
+typedef struct _GimpPaintSelectOptionsClass GimpPaintSelectOptionsClass;
+
+struct _GimpPaintSelectOptions
+{
+  GimpToolOptions        parent_instance;
+
+  GimpPaintSelectMode    mode;
+  gint                   stroke_width;
+};
+
+struct _GimpPaintSelectOptionsClass
+{
+  GimpToolOptionsClass  parent_class;
+};
+
+
+GType       gimp_paint_select_options_get_type       (void) G_GNUC_CONST;
+
+GtkWidget * gimp_paint_select_options_gui            (GimpToolOptions             *tool_options);
+
+
+
+#endif /* __GIMP_PAINT_SELECT_OPTIONS_H__ */
\ No newline at end of file
diff --git a/app/tools/gimppaintselecttool.c b/app/tools/gimppaintselecttool.c
new file mode 100644
index 0000000000..e154563bb5
--- /dev/null
+++ b/app/tools/gimppaintselecttool.c
@@ -0,0 +1,728 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * GimpPaintSelectTool
+ * Copyright (C) 2020  Thomas Manni <thomas manni free fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (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
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <math.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+
+#include "libgimpmath/gimpmath.h"
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "tools-types.h"
+
+#include "config/gimpguiconfig.h"
+
+#include "gegl/gimp-gegl-loops.h"
+#include "gegl/gimp-gegl-mask.h"
+#include "gegl/gimp-gegl-utils.h"
+
+#include "core/gimp.h"
+#include "core/gimpchannel-select.h"
+#include "core/gimperror.h"
+#include "core/gimpimage.h"
+#include "core/gimplayer.h"
+#include "core/gimplayermask.h"
+#include "core/gimpprogress.h"
+#include "core/gimpscanconvert.h"
+
+#include "widgets/gimphelp-ids.h"
+#include "widgets/gimpwidgets-utils.h"
+
+#include "display/gimpdisplay.h"
+#include "display/gimpdisplayshell.h"
+#include "display/gimptoolgui.h"
+
+#include "core/gimptooloptions.h"
+#include "gimppaintselecttool.h"
+#include "gimppaintselectoptions.h"
+#include "gimptoolcontrol.h"
+
+#include "gimp-intl.h"
+
+#include "config/gimpguiconfig.h" /* playground */
+
+
+static gboolean  gimp_paint_select_tool_initialize       (GimpTool         *tool,
+                                                          GimpDisplay      *display,
+                                                          GError          **error);
+  static void   gimp_paint_select_tool_control           (GimpTool         *tool,
+                                                          GimpToolAction    action,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_button_press        (GimpTool         *tool,
+                                                          const GimpCoords *coords,
+                                                          guint32           time,
+                                                          GdkModifierType   state,
+                                                          GimpButtonPressType press_type,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_button_release      (GimpTool         *tool,
+                                                          const GimpCoords *coords,
+                                                          guint32           time,
+                                                          GdkModifierType   state,
+                                                          GimpButtonReleaseType release_type,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_motion             (GimpTool         *tool,
+                                                          const GimpCoords *coords,
+                                                          guint32           time,
+                                                          GdkModifierType   state,
+                                                          GimpDisplay      *display);
+static gboolean  gimp_paint_select_tool_key_press       (GimpTool         *tool,
+                                                          GdkEventKey      *kevent,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_modifier_key       (GimpTool         *tool,
+                                                          GdkModifierType   key,
+                                                          gboolean          press,
+                                                          GdkModifierType   state,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_oper_update        (GimpTool         *tool,
+                                                          const GimpCoords *coords,
+                                                          GdkModifierType   state,
+                                                          gboolean          proximity,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_options_notify     (GimpTool         *tool,
+                                                          GimpToolOptions  *options,
+                                                          const GParamSpec *pspec);
+static void   gimp_paint_select_tool_cursor_update       (GimpTool         *tool,
+                                                          const GimpCoords *coords,
+                                                          GdkModifierType   state,
+                                                          GimpDisplay      *display);
+static void   gimp_paint_select_tool_draw                (GimpDrawTool     *draw_tool);
+
+static void   gimp_paint_select_tool_halt                 (GimpPaintSelectTool *ps_tool);
+static void   gimp_paint_select_tool_update_image_mask   (GimpPaintSelectTool *ps_tool);
+static void   gimp_paint_select_tool_init_buffers        (GimpPaintSelectTool  *ps_tool,
+                                                          GimpImage            *image,
+                                                          GimpDrawable         *drawable);
+static void   gimp_paint_select_tool_init_scribble       (GimpPaintSelectTool  *ps_tool);
+static void   gimp_paint_select_tool_create_graph        (GimpPaintSelectTool  *ps_tool);
+static gboolean gimp_paint_select_tool_paint_scribble    (GimpPaintSelectTool  *ps_tool);
+
+static gfloat euclidean_distance                         (gint                  x1,
+                                                          gint                  y1,
+                                                          gint                  x2,
+                                                          gint                  y2);
+
+
+G_DEFINE_TYPE (GimpPaintSelectTool, gimp_paint_select_tool,
+               GIMP_TYPE_DRAW_TOOL)
+
+#define parent_class gimp_paint_select_tool_parent_class
+
+
+void
+gimp_paint_select_tool_register (GimpToolRegisterCallback  callback,
+                                 gpointer                  data)
+{
+  if (gegl_has_operation ("gegl:paint-select") &&
+      GIMP_GUI_CONFIG (GIMP (data)->config)->playground_paint_select_tool)
+    (* callback) (GIMP_TYPE_PAINT_SELECT_TOOL,
+                  GIMP_TYPE_PAINT_SELECT_OPTIONS,
+                  gimp_paint_select_options_gui,
+                  0,
+                  "gimp-paint-select-tool",
+                  _("Paint Select"),
+                  _("Paint Select Tool: Scult selection by painting"),
+                  N_("P_aint Select"), NULL,
+                  NULL, GIMP_HELP_TOOL_FOREGROUND_SELECT,
+                  GIMP_ICON_TOOL_PAINT_SELECT,
+                  data);
+}
+
+static void
+gimp_paint_select_tool_class_init (GimpPaintSelectToolClass *klass)
+{
+  GimpToolClass              *tool_class      = GIMP_TOOL_CLASS (klass);
+  GimpDrawToolClass          *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
+
+  tool_class->button_press           = gimp_paint_select_tool_button_press;
+  tool_class->button_release         = gimp_paint_select_tool_button_release;
+  tool_class->control                = gimp_paint_select_tool_control;
+  tool_class->cursor_update          = gimp_paint_select_tool_cursor_update;
+  tool_class->initialize             = gimp_paint_select_tool_initialize;
+  tool_class->key_press              = gimp_paint_select_tool_key_press;
+  tool_class->modifier_key           = gimp_paint_select_tool_modifier_key;
+  tool_class->motion                 = gimp_paint_select_tool_motion;
+  tool_class->oper_update            = gimp_paint_select_tool_oper_update;
+  tool_class->options_notify         = gimp_paint_select_tool_options_notify;
+
+  draw_tool_class->draw              = gimp_paint_select_tool_draw;
+}
+
+static void
+gimp_paint_select_tool_init (GimpPaintSelectTool *ps_tool)
+{
+  GimpTool *tool = GIMP_TOOL (ps_tool);
+
+  gimp_tool_control_set_motion_mode (tool->control, GIMP_MOTION_MODE_EXACT);
+  gimp_tool_control_set_scroll_lock (tool->control, FALSE);
+  gimp_tool_control_set_preserve    (tool->control, FALSE);
+  gimp_tool_control_set_dirty_mask  (tool->control,
+                                     GIMP_DIRTY_IMAGE           |
+                                     GIMP_DIRTY_ACTIVE_DRAWABLE);
+  gimp_tool_control_set_dirty_action (tool->control,
+                                      GIMP_TOOL_ACTION_HALT);
+  gimp_tool_control_set_precision   (tool->control,
+                                     GIMP_CURSOR_PRECISION_SUBPIXEL);
+  gimp_tool_control_set_tool_cursor (tool->control,
+                                     GIMP_TOOL_CURSOR_PAINTBRUSH);
+  gimp_tool_control_set_cursor_modifier (tool->control,
+                                         GIMP_CURSOR_MODIFIER_PLUS);
+  gimp_tool_control_set_action_size (tool->control,
+                                     "tools/tools-paint-select-brush-size-set");
+  ps_tool->result_mask = NULL;
+  ps_tool->image_mask  = NULL;
+  ps_tool->trimap      = NULL;
+  ps_tool->drawable    = NULL;
+  ps_tool->scribble    = NULL;
+  ps_tool->graph       = NULL;
+  ps_tool->ps_node     = NULL;
+  ps_tool->render_node = NULL;
+}
+
+static void
+gimp_paint_select_tool_button_press (GimpTool            *tool,
+                                     const GimpCoords    *coords,
+                                     guint32              time,
+                                     GdkModifierType      state,
+                                     GimpButtonPressType  press_type,
+                                     GimpDisplay         *display)
+{
+  GimpPaintSelectTool  *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);
+  GimpDrawTool         *draw_tool = GIMP_DRAW_TOOL (tool);
+
+  if (gimp_draw_tool_is_active (draw_tool) && draw_tool->display != display)
+        gimp_draw_tool_stop (draw_tool);
+
+  gimp_draw_tool_pause (draw_tool);
+  gimp_tool_control_activate (tool->control);
+
+  ps_tool->last_pos.x = coords->x;
+  ps_tool->last_pos.y = coords->y;
+
+  if (gimp_paint_select_tool_paint_scribble (ps_tool))
+    {
+      if (tool->display)
+        {
+          GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
+          GimpImage *image = gimp_display_get_image (tool->display);
+          GimpChannelOps op;
+          gint x_offset = ps_tool->last_pos.x - options->stroke_width / 2;
+          gint y_offset = ps_tool->last_pos.y - options->stroke_width / 2;
+
+          if (options->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"),
+                                      ps_tool->scribble,
+                                      x_offset,
+                                      y_offset,
+                                      op,
+                                      FALSE,
+                                      0,
+                                      0);
+          gimp_image_flush (image);
+        }
+    }
+
+  if (! gimp_draw_tool_is_active (draw_tool))
+        gimp_draw_tool_start (draw_tool, display);
+
+  gimp_draw_tool_resume (draw_tool);
+}
+
+static void
+gimp_paint_select_tool_button_release (GimpTool              *tool,
+                                       const GimpCoords      *coords,
+                                       guint32                time,
+                                       GdkModifierType        state,
+                                       GimpButtonReleaseType  release_type,
+                                       GimpDisplay           *display)
+{
+  GimpDrawTool  *draw_tool = GIMP_DRAW_TOOL (tool);
+  gimp_draw_tool_stop (draw_tool);
+  gimp_tool_control_halt (tool->control);
+}
+
+static void
+gimp_paint_select_tool_control (GimpTool       *tool,
+                                GimpToolAction  action,
+                                GimpDisplay    *display)
+{
+  GimpPaintSelectTool *paint_select = GIMP_PAINT_SELECT_TOOL (tool);
+
+  switch (action)
+    {
+    case GIMP_TOOL_ACTION_PAUSE:
+      break;
+
+    case GIMP_TOOL_ACTION_RESUME:
+      break;
+
+    case GIMP_TOOL_ACTION_HALT:
+      gimp_paint_select_tool_halt (paint_select);
+      break;
+
+    case GIMP_TOOL_ACTION_COMMIT:
+      break;
+    }
+
+  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
+}
+
+static void
+gimp_paint_select_tool_cursor_update (GimpTool         *tool,
+                                      const GimpCoords *coords,
+                                      GdkModifierType   state,
+                                      GimpDisplay      *display)
+{
+  GimpPaintSelectOptions    *options  = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (tool);
+  GimpCursorModifier  modifier        = GIMP_CURSOR_MODIFIER_NONE;
+
+  if (options->mode == GIMP_PAINT_SELECT_MODE_ADD)
+    {
+      modifier = GIMP_CURSOR_MODIFIER_PLUS;
+    }
+  else
+    {
+      modifier = GIMP_CURSOR_MODIFIER_MINUS;
+    }
+
+  gimp_tool_control_set_cursor_modifier (tool->control, modifier);
+
+  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
+}
+
+static gboolean
+gimp_paint_select_tool_initialize (GimpTool     *tool,
+                                   GimpDisplay  *display,
+                                   GError      **error)
+{
+  GimpPaintSelectTool *ps_tool    = GIMP_PAINT_SELECT_TOOL (tool);
+  GimpGuiConfig       *config     = GIMP_GUI_CONFIG (display->gimp->config);
+  GimpImage           *image      = gimp_display_get_image (display);
+  GList               *drawables  = gimp_image_get_selected_drawables (image);
+  GimpDrawable        *drawable;
+
+  if (g_list_length (drawables) != 1)
+    {
+      if (g_list_length (drawables) > 1)
+        g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                             _("Cannot select from multiple layers."));
+      else
+        g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("No selected drawables."));
+
+      g_list_free (drawables);
+      return FALSE;
+    }
+
+  drawable = drawables->data;
+  g_list_free (drawables);
+
+  if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
+      ! config->edit_non_visible)
+    {
+      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                           _("The active layer is not visible."));
+      return FALSE;
+    }
+
+  tool->display = display;
+
+  gimp_paint_select_tool_init_buffers (ps_tool, image, drawable);
+  gimp_paint_select_tool_create_graph (ps_tool);
+
+  return TRUE;
+}
+
+static gboolean
+gimp_paint_select_tool_key_press (GimpTool    *tool,
+                                  GdkEventKey *kevent,
+                                  GimpDisplay *display)
+{
+  return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
+}
+
+static void
+gimp_paint_select_tool_modifier_key (GimpTool        *tool,
+                                          GdkModifierType  key,
+                                          gboolean         press,
+                                          GdkModifierType  state,
+                                          GimpDisplay     *display)
+{
+}
+
+static void
+gimp_paint_select_tool_motion (GimpTool         *tool,
+                               const GimpCoords *coords,
+                               guint32           time,
+                               GdkModifierType   state,
+                               GimpDisplay      *display)
+{
+  GimpPaintSelectTool *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);
+  GimpDrawTool        *draw_tool = GIMP_DRAW_TOOL (tool);
+
+  static guint32 last_time = 0;
+
+  GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state, display);
+
+  /* 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;
+
+  if (state & GDK_BUTTON1_MASK)
+    {
+      gfloat distance = euclidean_distance (coords->x,
+                                            coords->y,
+                                            ps_tool->last_pos.x,
+                                            ps_tool->last_pos.y);
+
+      if (distance >= 2.f)
+        {
+          gimp_draw_tool_pause (draw_tool);
+          gimp_tool_control_halt (tool->control);
+          ps_tool->last_pos.x = coords->x;
+          ps_tool->last_pos.y = coords->y;
+
+          if (gimp_paint_select_tool_paint_scribble (ps_tool))
+            {
+              GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
+              GTimer *timer = g_timer_new ();
+
+              if (options->mode == GIMP_PAINT_SELECT_MODE_ADD)
+                {
+                  gegl_node_set (ps_tool->ps_node, "mode", 0, NULL);
+                }
+              else
+                {
+                  gegl_node_set (ps_tool->ps_node, "mode", 1, NULL);
+                }
+
+              g_timer_start (timer);
+              gegl_node_process (ps_tool->render_node);
+              g_timer_stop (timer);
+              g_printerr ("processing graph takes %.3f s\n", g_timer_elapsed (timer, NULL));
+              g_timer_destroy (timer);
+
+              gimp_paint_select_tool_update_image_mask (ps_tool);
+            }
+
+          gimp_tool_control_activate (tool->control);
+          gimp_draw_tool_resume (draw_tool);
+        }
+    }
+}
+
+static void
+gimp_paint_select_tool_oper_update (GimpTool         *tool,
+                                    const GimpCoords *coords,
+                                    GdkModifierType   state,
+                                    gboolean          proximity,
+                                    GimpDisplay      *display)
+{
+  GimpPaintSelectTool *ps = GIMP_PAINT_SELECT_TOOL (tool);
+  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
+
+  if (proximity)
+    {
+      gimp_draw_tool_pause (draw_tool);
+
+      if (! tool->display || display == tool->display)
+        {
+          ps->last_pos.x = coords->x;
+          ps->last_pos.y = coords->y;
+        }
+
+      if (! gimp_draw_tool_is_active (draw_tool))
+        gimp_draw_tool_start (draw_tool, display);
+
+      gimp_draw_tool_resume (draw_tool);
+    }
+  else if (gimp_draw_tool_is_active (draw_tool))
+    {
+      gimp_draw_tool_stop (draw_tool);
+    }
+}
+
+static void
+gimp_paint_select_tool_draw (GimpDrawTool *draw_tool)
+{
+  GimpPaintSelectTool    *paint_select = GIMP_PAINT_SELECT_TOOL (draw_tool);
+  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (paint_select);
+  gint size = options->stroke_width;
+
+  gimp_draw_tool_add_arc (draw_tool,
+                          FALSE,
+                          paint_select->last_pos.x - (size / 2.0),
+                          paint_select->last_pos.y - (size / 2.0),
+                          size, size,
+                          0.0, (2.0 * G_PI));
+}
+
+static void
+gimp_paint_select_tool_options_notify (GimpTool         *tool,
+                                       GimpToolOptions  *options,
+                                       const GParamSpec *pspec)
+{
+  GimpPaintSelectTool  *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);
+
+  if (! tool->display)
+    return;
+
+  if (! strcmp (pspec->name, "stroke-width") && ps_tool->scribble)
+    {
+      g_object_unref (ps_tool->scribble);
+      ps_tool->scribble = NULL;
+    }
+}
+
+static void
+gimp_paint_select_tool_halt (GimpPaintSelectTool *ps_tool)
+{
+  GimpTool     *tool = GIMP_TOOL (ps_tool);
+
+  g_clear_object (&ps_tool->trimap);
+  g_clear_object (&ps_tool->result_mask);
+  g_clear_object (&ps_tool->graph);
+  g_clear_object (&ps_tool->scribble);
+
+  ps_tool->drawable = NULL;
+  ps_tool->render_node = NULL;
+  ps_tool->ps_node = NULL;
+
+  ps_tool->image_mask = NULL;
+
+  if (tool->display)
+    gimp_image_flush (gimp_display_get_image (tool->display));
+
+  tool->display   = NULL;
+  g_list_free (tool->drawables);
+  tool->drawables = NULL;
+}
+
+static void
+gimp_paint_select_tool_update_image_mask (GimpPaintSelectTool *ps_tool)
+{
+  GimpTool  *tool = GIMP_TOOL (ps_tool);
+
+  if (tool->display)
+    {
+      GimpImage *image = gimp_display_get_image (tool->display);
+
+      gimp_channel_select_buffer (gimp_image_get_mask (image),
+                                  C_("command", "Paint Select"),
+                                  ps_tool->result_mask,
+                                  0, /* x offset */
+                                  0, /* y offset */
+                                  GIMP_CHANNEL_OP_REPLACE,
+                                  FALSE,
+                                  0,
+                                  0);
+      gimp_image_flush (image);
+    }
+
+  g_clear_object (&ps_tool->result_mask);
+}
+
+static void
+gimp_paint_select_tool_init_buffers (GimpPaintSelectTool  *ps_tool,
+                                     GimpImage            *image,
+                                     GimpDrawable         *drawable)
+{
+  GimpChannel  *channel;
+  GeglColor    *grey = gegl_color_new ("#888");
+
+  g_return_if_fail (ps_tool->result_mask == NULL);
+  g_return_if_fail (ps_tool->trimap == NULL);
+  g_return_if_fail (ps_tool->drawable == NULL);
+
+  ps_tool->drawable = gimp_drawable_get_buffer (drawable);
+
+  channel = gimp_image_get_mask (image);
+  ps_tool->image_mask = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
+  ps_tool->trimap = gegl_buffer_new (gegl_buffer_get_extent (ps_tool->image_mask),
+                                     babl_format ("Y float"));
+  gegl_buffer_set_color (ps_tool->trimap, NULL, grey);
+
+  g_object_unref (grey);
+}
+
+static void
+gimp_paint_select_tool_init_scribble (GimpPaintSelectTool  *ps_tool)
+{
+  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
+
+  GimpScanConvert  *scan_convert;
+  GimpVector2       points[2];
+  gint              size   = options->stroke_width;
+  gint              radius = size / 2;
+  GeglRectangle     square = {0, 0, size, size};
+
+  if (ps_tool->scribble)
+    g_object_unref (ps_tool->scribble);
+
+  ps_tool->scribble = gegl_buffer_linear_new (&square, babl_format ("Y float"));
+
+  points[0].x = points[1].x = radius;
+  points[0].y = points[1].y = radius;
+  points[1].x += 0.01;
+  points[1].y += 0.01;
+
+  scan_convert = gimp_scan_convert_new ();
+  gimp_scan_convert_add_polyline (scan_convert, 2, points, FALSE);
+  gimp_scan_convert_stroke (scan_convert, size,
+                            GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0,
+                            0.0, NULL);
+  gimp_scan_convert_compose (scan_convert, ps_tool->scribble, 0, 0);
+  gimp_scan_convert_free (scan_convert);
+}
+
+static gboolean
+gimp_paint_select_tool_paint_scribble (GimpPaintSelectTool  *ps_tool)
+{
+  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
+
+  gint  size   = options->stroke_width;
+  gint  radius = size / 2;
+  GeglRectangle  square = {0, 0, size, size};
+
+  GeglBufferIterator  *iter;
+  gfloat scribble_value;
+  gboolean overlap = FALSE;
+
+  if (! ps_tool->scribble)
+    {
+      gimp_paint_select_tool_init_scribble (ps_tool);
+    }
+
+  /* add the scribble to the trimap buffer and check the image mask to see if
+     an optimization should be triggered.
+   */
+
+  if (options->mode == GIMP_PAINT_SELECT_MODE_ADD)
+    {
+      scribble_value = 1.f;
+    }
+  else
+    {
+      scribble_value = 0.f;
+    }
+
+  iter = gegl_buffer_iterator_new (ps_tool->scribble, NULL, 0,
+                                   babl_format ("Y float"),
+                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);
+
+  square = *gegl_buffer_get_extent (ps_tool->scribble);
+  square.x = ps_tool->last_pos.x - radius;
+  square.y = ps_tool->last_pos.y - radius;
+
+  gegl_buffer_iterator_add (iter, ps_tool->trimap, &square, 0,
+                            babl_format ("Y float"),
+                            GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
+
+  gegl_buffer_iterator_add (iter, ps_tool->image_mask, &square, 0,
+                            babl_format ("Y float"),
+                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+  while (gegl_buffer_iterator_next (iter))
+    {
+      gfloat  *scribble_pix = iter->items[0].data;
+      gfloat  *trimap_pix   = iter->items[1].data;
+      gfloat  *mask_pix     = iter->items[2].data;
+      gint     n_pixels     = iter->length;
+
+      while (n_pixels--)
+        {
+          if (*scribble_pix)
+            {
+              *trimap_pix = scribble_value;
+
+              if (*mask_pix != scribble_value)
+                overlap = TRUE;
+            }
+
+          scribble_pix++;
+          trimap_pix++;
+          mask_pix++;
+        }
+    }
+
+  return overlap;
+}
+
+static void
+gimp_paint_select_tool_create_graph (GimpPaintSelectTool  *ps_tool)
+{
+  GimpTool    *tool = GIMP_TOOL (ps_tool);
+  GimpImage   *image = gimp_display_get_image (tool->display);
+  GimpChannel *channel = gimp_image_get_mask (image);
+  GeglNode  *t;         /* trimap */
+  GeglNode  *m;         /* mask   */
+  GeglNode  *d;         /* drawable */
+
+  ps_tool->graph = gegl_node_new ();
+
+  m = gegl_node_new_child (ps_tool->graph,
+                           "operation", "gegl:buffer-source",
+                           "buffer", gimp_drawable_get_buffer (GIMP_DRAWABLE(channel)),
+                           NULL);
+  d = gegl_node_new_child (ps_tool->graph,
+                           "operation", "gegl:buffer-source",
+                           "buffer", ps_tool->drawable,
+                           NULL);
+
+  t = gegl_node_new_child (ps_tool->graph,
+                           "operation", "gegl:buffer-source",
+                           "buffer", ps_tool->trimap,
+                           NULL);
+
+  ps_tool->ps_node = gegl_node_new_child (ps_tool->graph,
+                            "operation", "gegl:paint-select",
+                            NULL);
+
+  ps_tool->render_node = gegl_node_new_child (ps_tool->graph,
+                                            "operation", "gegl:buffer-sink",
+                                             "buffer",  &ps_tool->result_mask,
+                                             NULL);
+
+  gegl_node_link_many (m, ps_tool->ps_node, ps_tool->render_node, NULL);
+  gegl_node_connect_to (d, "output", ps_tool->ps_node, "aux");
+  gegl_node_connect_to (t, "output", ps_tool->ps_node, "aux2");
+}
+
+static gfloat
+euclidean_distance (gint  x1,
+                    gint  y1,
+                    gint  x2,
+                    gint  y2)
+{
+  return sqrtf ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
+}
diff --git a/app/tools/gimppaintselecttool.h b/app/tools/gimppaintselecttool.h
new file mode 100644
index 0000000000..ccd7cce52d
--- /dev/null
+++ b/app/tools/gimppaintselecttool.h
@@ -0,0 +1,67 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (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
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_PAINT_SELECT_TOOL_H__
+#define __GIMP_PAINT_SELECT_TOOL_H__
+
+
+#include "gimpdrawtool.h"
+
+
+#define GIMP_TYPE_PAINT_SELECT_TOOL            (gimp_paint_select_tool_get_type ())
+#define GIMP_PAINT_SELECT_TOOL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_PAINT_SELECT_TOOL, GimpPaintSelectTool))
+#define GIMP_PAINT_SELECT_TOOL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
GIMP_TYPE_PAINT_SELECT_TOOL, GimpPaintSelectToolClass))
+#define GIMP_IS_PAINT_SELECT_TOOL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_PAINT_SELECT_TOOL))
+#define GIMP_IS_PAINT_SELECT_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GIMP_TYPE_PAINT_SELECT_TOOL))
+#define GIMP_PAINT_SELECT_TOOL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GIMP_TYPE_PAINT_SELECT_TOOL, GimpPaintSelectToolClass))
+
+#define GIMP_PAINT_SELECT_TOOL_GET_OPTIONS(t)  (GIMP_PAINT_SELECT_OPTIONS (gimp_tool_get_options (GIMP_TOOL 
(t))))
+
+
+typedef struct _GimpPaintSelectTool      GimpPaintSelectTool;
+typedef struct _GimpPaintSelectToolClass GimpPaintSelectToolClass;
+
+struct _GimpPaintSelectTool
+{
+  GimpDrawTool           parent_instance;
+
+  GeglBuffer            *trimap;
+  GeglBuffer            *image_mask;
+  GeglBuffer            *result_mask;
+  GeglBuffer            *drawable;
+  GeglBuffer            *scribble;
+
+  GeglNode              *graph;
+  GeglNode              *ps_node;
+  GeglNode              *render_node;
+
+  GimpVector2            last_pos;
+};
+
+struct _GimpPaintSelectToolClass
+{
+  GimpDrawToolClass  parent_class;
+};
+
+
+void    gimp_paint_select_tool_register (GimpToolRegisterCallback  callback,
+                                         gpointer                  data);
+
+GType   gimp_paint_select_tool_get_type (void) G_GNUC_CONST;
+
+
+#endif  /*  __GIMP_PAINT_SELECT_TOOL_H__  */
diff --git a/app/tools/meson.build b/app/tools/meson.build
index 0c08b97c42..9627bb924e 100644
--- a/app/tools/meson.build
+++ b/app/tools/meson.build
@@ -84,6 +84,8 @@ libapptools_sources = [
   'gimpoperationtool.c',
   'gimppaintbrushtool.c',
   'gimppaintoptions-gui.c',
+  'gimppaintselectoptions.c',
+  'gimppaintselecttool.c',
   'gimppainttool-paint.c',
   'gimppainttool.c',
   'gimppenciltool.c',
diff --git a/app/tools/tools-enums.c b/app/tools/tools-enums.c
index 5e637e97e0..ee695858b8 100644
--- a/app/tools/tools-enums.c
+++ b/app/tools/tools-enums.c
@@ -337,6 +337,23 @@ 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 }
+};
+
 
 /* Generated data ends here */
 
diff --git a/app/tools/tools-enums.h b/app/tools/tools-enums.h
index f994bc15bd..a7dc3167b6 100644
--- a/app/tools/tools-enums.h
+++ b/app/tools/tools-enums.h
@@ -166,6 +166,16 @@ 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
  */
diff --git a/icons/Color/16/gimp-tool-paint-select.png b/icons/Color/16/gimp-tool-paint-select.png
new file mode 100644
index 0000000000..867996bac4
Binary files /dev/null and b/icons/Color/16/gimp-tool-paint-select.png differ
diff --git a/icons/Color/24/gimp-tool-paint-select.png b/icons/Color/24/gimp-tool-paint-select.png
new file mode 100644
index 0000000000..bb47ff6ff7
Binary files /dev/null and b/icons/Color/24/gimp-tool-paint-select.png differ
diff --git a/icons/Color/24/gimp-tool-paint-select.svg b/icons/Color/24/gimp-tool-paint-select.svg
new file mode 100644
index 0000000000..1d2a5dc0b4
--- /dev/null
+++ b/icons/Color/24/gimp-tool-paint-select.svg
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="24"
+   height="24"
+   viewBox="0 0 24 24"
+   id="svg30571"
+   version="1.1"
+   inkscape:version="0.91+devel r"
+   sodipodi:docname="gimp-tool-blur-24.svg"
+   inkscape:export-filename="/home/klaus/Bilder/icons/Symbolic/hicolor/24x24/apps/gimp-channel.png"
+   inkscape:export-xdpi="98.181816"
+   inkscape:export-ydpi="98.181816">
+  <defs
+     id="defs30573">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6951"
+       id="linearGradient2979-31"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.87935,-0.07437292,0.07703828,0.848926,-18.417151,-18.747073)"
+       x1="28.058632"
+       y1="18.867767"
+       x2="33.436985"
+       y2="23.742767" />
+    <linearGradient
+       id="linearGradient6951">
+      <stop
+         style="stop-color:#6e3d09;stop-opacity:1;"
+         offset="0"
+         id="stop6953" />
+      <stop
+         id="stop6959"
+         offset="0.24242425"
+         style="stop-color:#ea8113;stop-opacity:1;" />
+      <stop
+         style="stop-color:#5c3307;stop-opacity:1;"
+         offset="0.62121212"
+         id="stop6961" />
+      <stop
+         style="stop-color:#e07c12;stop-opacity:1;"
+         offset="1"
+         id="stop6955" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6939"
+       id="linearGradient2975-75"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.356127,-0.219769,0.227645,1.309208,-32.05138,-32.311441)"
+       x1="19.394735"
+       y1="30.001331"
+       x2="23.109331"
+       y2="33.438831" />
+    <linearGradient
+       id="linearGradient6939">
+      <stop
+         style="stop-color:#bdbdbd;stop-opacity:1;"
+         offset="0"
+         id="stop6941" />
+      <stop
+         id="stop6947"
+         offset="0.33333334"
+         style="stop-color:#e2e2e2;stop-opacity:1;" />
+      <stop
+         style="stop-color:#a3a3a3;stop-opacity:1;"
+         offset="0.66666669"
+         id="stop6949" />
+      <stop
+         style="stop-color:#dddddd;stop-opacity:1;"
+         offset="1"
+         id="stop6943" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6963"
+       id="radialGradient2971"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.584317,0,0,0.549734,-12.035061,-8.383133)"
+       cx="15.415101"
+       cy="35.356506"
+       fx="15.415101"
+       fy="35.356506"
+       r="7.5791559" />
+    <linearGradient
+       id="linearGradient6963">
+      <stop
+         style="stop-color:#696969;stop-opacity:1;"
+         offset="0"
+         id="stop6965" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop6967" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="-5.416016"
+     inkscape:cy="14.628924"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     units="px"
+     inkscape:snap-page="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-center="true"
+     inkscape:snap-text-baseline="true"
+     showborder="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4369" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata30576">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Klaus Staedtler</dc:title>
+          </cc:Agent>
+        </dc:creator>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1028.3622)">
+    <g
+       id="g4733">
+      <g
+         transform="matrix(0.72842778,0,0,0.75240082,10.103955,1039.3154)"
+         id="g4288">
+        <g
+           id="g891-37"
+           transform="matrix(0.186703,0,0,0.186703,-51.137271,27.041497)" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient2979-31);fill-opacity:1;fill-rule:nonzero;stroke:#673907;stroke-width:1.00000048;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="m 1.880007,0.390614 6.166172,4.218273 c 5.776248,-6.5301 9.110705,-17.663007 
9.110705,-17.663007 0.283343,-1.07141 -0.778668,-1.32072 -1.382605,-0.563567 0,0 -8.9019,7.384103 
-13.894272,14.008301 z"
+           id="path6937-9"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="ccssc"
+           inkscape:connector-curvature="0" />
+        <path
+           sodipodi:nodetypes="ccsc"
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           id="path7220-3"
+           d="m 2.906028,0.727447 4.203637,3.360672 c 6.3456,-7.19205 8.687017,-16.297389 
8.687017,-16.297389 0,0 -7.406194,5.641032 -12.890654,12.936717 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.33333333;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           inkscape:connector-curvature="0" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient2975-75);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1.0000006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="M -2.531061,9.502156 0.955458,11.54026 7.987449,4.840791 C 7.03845,2.891301 3.875427,0.350218 
1.332688,0.762284 Z"
+           id="path6935-1"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient2971);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="m -12.498089,17.325227 c 12.009594,0.0849 14.031177,-0.03171 14.694027,-4.850339 
0.542698,-3.94517 -6.498481,-5.648707 -8.88957,-1.235576 -1.930787,3.563572 -5.804457,6.085915 
-5.804457,6.085915 z"
+           id="path6933-9"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="cssc"
+           inkscape:connector-curvature="0" />
+        <ellipse
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.52777782;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           id="path6971-5"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           cx="-3.2496638"
+           cy="11.638556"
+           rx="1.5320324"
+           ry="1.4790274" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1.00000107;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="M 2.832601,2.79379 -0.089332,8.294237"
+           id="path6985-0"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           inkscape:connector-curvature="0" />
+      </g>
+      <rect
+         ry="1.8554795"
+         rx="2.5547137"
+         y="1028.3622"
+         x="0"
+         height="24"
+         width="24"
+         id="rect4297"
+         
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.30000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 />
+    </g>
+  </g>
+</svg>
diff --git a/icons/Color/icon-list.mk b/icons/Color/icon-list.mk
index 6c9d2a0739..e4b8d43e2f 100644
--- a/icons/Color/icon-list.mk
+++ b/icons/Color/icon-list.mk
@@ -311,6 +311,7 @@ scalable_images = \
        scalable/gimp-tool-offset.svg                           \
        scalable/gimp-tool-options.svg                          \
        scalable/gimp-tool-paintbrush.svg                       \
+       scalable/gimp-tool-paint-select.svg             \
        scalable/gimp-tool-path.svg                             \
        scalable/gimp-tool-pencil.svg                           \
        scalable/gimp-tool-perspective-clone.svg                \
@@ -491,6 +492,7 @@ vector24_images = \
        24/gimp-tool-offset.svg                                 \
        24/gimp-tool-options.svg                                \
        24/gimp-tool-paintbrush.svg                             \
+       24/gimp-tool-paint-select.svg                   \
        24/gimp-tool-path.svg                                   \
        24/gimp-tool-pencil.svg                                 \
        24/gimp-tool-perspective.svg                            \
@@ -791,6 +793,7 @@ icons16_images = \
        16/gimp-tool-offset.png                                 \
        16/gimp-tool-options.png                                \
        16/gimp-tool-paintbrush.png                             \
+       16/gimp-tool-paint-select.png                   \
        16/gimp-tool-path.png                                   \
        16/gimp-tool-pencil.png                                 \
        16/gimp-tool-perspective-clone.png                      \
@@ -1006,6 +1009,7 @@ icons24_images = \
        24/gimp-tool-n-point-deformation.png                    \
        24/gimp-tool-offset.png                                 \
        24/gimp-tool-paintbrush.png                             \
+       24/gimp-tool-paint-select.png                   \
        24/gimp-tool-path.png                                   \
        24/gimp-tool-pencil.png                                 \
        24/gimp-tool-perspective-clone.png                      \
diff --git a/icons/Color/scalable/gimp-tool-paint-select.svg b/icons/Color/scalable/gimp-tool-paint-select.svg
new file mode 100644
index 0000000000..eee38bc7a9
--- /dev/null
+++ b/icons/Color/scalable/gimp-tool-paint-select.svg
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   inkscape:export-ydpi="90.000000"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-filename="/home/jimmac/src/cvs/gnome/gimp/themes/Default/images/stock-layers-16.png"
+   width="16"
+   height="16"
+   id="svg11300"
+   sodipodi:version="0.32"
+   inkscape:version="0.91+devel r"
+   sodipodi:docname="gimp-tool-paintbrush.svg"
+   version="1.0"
+   viewBox="0 0 16 16">
+  <sodipodi:namedview
+     inkscape:cy="7.1741021"
+     inkscape:cx="1.3590445"
+     inkscape:zoom="16.269075"
+     inkscape:window-height="752"
+     inkscape:window-width="1440"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.17254902"
+     bordercolor="#666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:showpageshadow="false"
+     showborder="true"
+     inkscape:window-x="480"
+     inkscape:window-y="290"
+     inkscape:current-layer="layer1"
+     width="16px"
+     height="16px"
+     showgrid="true"
+     inkscape:window-maximized="0"
+     inkscape:document-units="px">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4056" />
+  </sodipodi:namedview>
+  <defs
+     id="defs3">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6951"
+       id="linearGradient2979-31"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.87935,-0.07437292,0.07703828,0.848926,-18.417151,-18.747073)"
+       x1="28.058632"
+       y1="18.867767"
+       x2="33.436985"
+       y2="23.742767" />
+    <linearGradient
+       id="linearGradient6951">
+      <stop
+         style="stop-color:#6e3d09;stop-opacity:1;"
+         offset="0"
+         id="stop6953" />
+      <stop
+         id="stop6959"
+         offset="0.24242425"
+         style="stop-color:#ea8113;stop-opacity:1;" />
+      <stop
+         style="stop-color:#5c3307;stop-opacity:1;"
+         offset="0.62121212"
+         id="stop6961" />
+      <stop
+         style="stop-color:#e07c12;stop-opacity:1;"
+         offset="1"
+         id="stop6955" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6939"
+       id="linearGradient2975-75"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.356127,-0.219769,0.227645,1.309208,-32.05138,-32.311441)"
+       x1="19.394735"
+       y1="30.001331"
+       x2="23.109331"
+       y2="33.438831" />
+    <linearGradient
+       id="linearGradient6939">
+      <stop
+         style="stop-color:#bdbdbd;stop-opacity:1;"
+         offset="0"
+         id="stop6941" />
+      <stop
+         id="stop6947"
+         offset="0.33333334"
+         style="stop-color:#e2e2e2;stop-opacity:1;" />
+      <stop
+         style="stop-color:#a3a3a3;stop-opacity:1;"
+         offset="0.66666669"
+         id="stop6949" />
+      <stop
+         style="stop-color:#dddddd;stop-opacity:1;"
+         offset="1"
+         id="stop6943" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6963"
+       id="radialGradient2971"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.584317,0,0,0.549734,-12.035061,-8.383133)"
+       cx="15.415101"
+       cy="35.356506"
+       fx="15.415101"
+       fy="35.356506"
+       r="7.5791559" />
+    <linearGradient
+       id="linearGradient6963">
+      <stop
+         style="stop-color:#696969;stop-opacity:1;"
+         offset="0"
+         id="stop6965" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop6967" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     stroke="#ef2929"
+     fill="#eeeeec"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="0.25490196"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="-14.198652"
+     inkscape:cy="-5.1663457"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="872"
+     inkscape:window-height="659"
+     inkscape:window-x="403"
+     inkscape:window-y="296"
+     width="32px"
+     height="32px"
+     id="namedview73" />
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/"; />
+        <dc:title />
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/";>
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction"; />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution"; />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice"; />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution"; />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks"; />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike"; />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       id="g11310">
+      <g
+         transform="matrix(0.4966552,0,0,0.50160171,6.7072409,7.3021503)"
+         id="g4288">
+        <g
+           id="g891-37"
+           transform="matrix(0.186703,0,0,0.186703,-51.137271,27.041497)" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient2979-31);fill-opacity:1;fill-rule:nonzero;stroke:#673907;stroke-width:1.00000048;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="m 1.880007,0.390614 6.166172,4.218273 c 5.776248,-6.5301 9.110705,-17.663007 
9.110705,-17.663007 0.283343,-1.07141 -0.778668,-1.32072 -1.382605,-0.563567 0,0 -8.9019,7.384103 
-13.894272,14.008301 z"
+           id="path6937-9"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="ccssc"
+           inkscape:connector-curvature="0" />
+        <path
+           sodipodi:nodetypes="ccsc"
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           id="path7220-3"
+           d="m 2.906028,0.727447 4.203637,3.360672 c 6.3456,-7.19205 8.687017,-16.297389 
8.687017,-16.297389 0,0 -7.406194,5.641032 -12.890654,12.936717 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.33333333;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           inkscape:connector-curvature="0" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient2975-75);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1.0000006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="M -2.531061,9.502156 0.955458,11.54026 7.987449,4.840791 C 7.03845,2.891301 3.875427,0.350218 
1.332688,0.762284 Z"
+           id="path6935-1"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="ccccc"
+           inkscape:connector-curvature="0" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient2971);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="m -12.498089,17.325227 c 12.009594,0.0849 14.031177,-0.03171 14.694027,-4.850339 
0.542698,-3.94517 -6.498481,-5.648707 -8.88957,-1.235576 -1.930787,3.563572 -5.804457,6.085915 
-5.804457,6.085915 z"
+           id="path6933-9"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           sodipodi:nodetypes="cssc"
+           inkscape:connector-curvature="0" />
+        <ellipse
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.52777782;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           id="path6971-5"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           cx="-3.2496638"
+           cy="11.638556"
+           rx="1.5320324"
+           ry="1.4790274" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1.00000107;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+           d="M 2.832601,2.79379 -0.089332,8.294237"
+           id="path6985-0"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true"
+           inkscape:connector-curvature="0" />
+      </g>
+      <rect
+         ry="1.2369863"
+         rx="1.7031425"
+         y="0"
+         x="0"
+         height="16"
+         width="16"
+         id="rect4297"
+         
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 />
+    </g>
+  </g>
+</svg>
diff --git a/icons/Symbolic/24/gimp-tool-paint-select-symbolic.svg 
b/icons/Symbolic/24/gimp-tool-paint-select-symbolic.svg
new file mode 100644
index 0000000000..20f177ec89
--- /dev/null
+++ b/icons/Symbolic/24/gimp-tool-paint-select-symbolic.svg
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb";
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="24"
+   height="24"
+   viewBox="0 0 24 24"
+   id="svg30571"
+   version="1.1"
+   inkscape:version="0.91+devel r"
+   sodipodi:docname="gimp-tool-paintbrush-24.svg"
+   inkscape:export-filename="/home/klaus/Bilder/icons/Symbolic/hicolor/24x24/apps/gimp-channel.png"
+   inkscape:export-xdpi="98.181816"
+   inkscape:export-ydpi="98.181816">
+  <defs
+     id="defs30573">
+    <linearGradient
+       id="linearGradient19282-4"
+       osb:paint="solid"
+       gradientTransform="matrix(0.34682586,0,0,0.30620888,-482.61525,330.965)">
+      <stop
+         style="stop-color:#bebebe;stop-opacity:1;"
+         offset="0"
+         id="stop19284-0" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19282-4"
+       id="linearGradient10384"
+       x1="-28.5"
+       y1="25.737938"
+       x2="-20.499094"
+       y2="25.737938"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19282-4"
+       id="linearGradient10378"
+       x1="67.260277"
+       y1="183.23083"
+       x2="76.514008"
+       y2="183.23083"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.5129026,0,0,1.5338414,-92.758245,756.44128)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="-7.400391"
+     inkscape:cy="14.628924"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     units="px"
+     inkscape:snap-page="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-center="true"
+     inkscape:snap-text-baseline="true"
+     showborder="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4369" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata30576">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Klaus Staedtler</dc:title>
+          </cc:Agent>
+        </dc:creator>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1028.3622)">
+    <g
+       id="g9134">
+      <g
+         style="fill:#bebebe;fill-opacity:1;stroke:none"
+         transform="matrix(1.3748443,0,0,1.4226056,40.183063,1011.7472)"
+         id="g9272">
+        <path
+           style="fill:url(#linearGradient10384);fill-opacity:1;stroke:none"
+           sodipodi:nodetypes="cssac"
+           id="path9274"
+           d="m -28.5,27.5711 c 3.111145,0.0011 2.79359,-3.323359 4.304166,-4.248979 1.750479,-1.072622 
3.284496,0.256475 3.590759,1.350292 0.386445,1.380184 -0.337829,2.508685 -1.300323,3.118949 
-1.846361,1.170674 -6.300039,0.898712 -6.594602,-0.220262 z"
+           inkscape:connector-curvature="0" />
+      </g>
+      <path
+         inkscape:connector-curvature="0"
+         id="path9264"
+         d="m 22.852515,1030.0121 c 0.466524,-1.0212 -0.247692,-1.4129 -1.108083,-0.5471 -6.049703,6.0877 
-7.086286,5.9984 -12.744432,13.8972 1.518274,0.057 2.823067,1.0638 3.5,2.5 6.698265,-7.3202 7.451812,-11.1222 
10.352515,-15.8501 z"
+         style="fill:url(#linearGradient10378);fill-opacity:1;stroke:none;stroke-width:1.52333605"
+         sodipodi:nodetypes="csccc" />
+    </g>
+  </g>
+</svg>
diff --git a/icons/Symbolic/icon-list.mk b/icons/Symbolic/icon-list.mk
index 463aade8bf..a3bb090f90 100644
--- a/icons/Symbolic/icon-list.mk
+++ b/icons/Symbolic/icon-list.mk
@@ -311,6 +311,7 @@ scalable_images = \
        scalable/gimp-tool-offset-symbolic.svg                          \
        scalable/gimp-tool-options-symbolic.svg                         \
        scalable/gimp-tool-paintbrush-symbolic.svg                      \
+       scalable/gimp-tool-paint-select-symbolic.svg            \
        scalable/gimp-tool-path-symbolic.svg                            \
        scalable/gimp-tool-pencil-symbolic.svg                          \
        scalable/gimp-tool-perspective-clone-symbolic.svg               \
@@ -491,6 +492,7 @@ vector24_images = \
        24/gimp-tool-offset-symbolic.svg                                \
        24/gimp-tool-options-symbolic.svg                               \
        24/gimp-tool-paintbrush-symbolic.svg                            \
+       24/gimp-tool-paint-select-symbolic.svg                  \
        24/gimp-tool-path-symbolic.svg                                  \
        24/gimp-tool-pencil-symbolic.svg                                        \
        24/gimp-tool-perspective-symbolic.svg                           \
diff --git a/icons/Symbolic/scalable/gimp-tool-paint-select-symbolic.svg 
b/icons/Symbolic/scalable/gimp-tool-paint-select-symbolic.svg
new file mode 100644
index 0000000000..efc55b029d
--- /dev/null
+++ b/icons/Symbolic/scalable/gimp-tool-paint-select-symbolic.svg
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb";
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   viewBox="0 0 16.000001 15.999992"
+   id="svg7384"
+   height="15.999992"
+   width="16.000002"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="gimp-tool-paintbrush.svg">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="640"
+     inkscape:window-height="480"
+     id="namedview1509"
+     showgrid="false"
+     inkscape:zoom="14.750007"
+     inkscape:cx="-155.21063"
+     inkscape:cy="-46.369966"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg7384" />
+  <metadata
+     id="metadata90">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Barbara Muraus, Jakub Steiner, Klaus Staedtler</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <dc:description>Images originally created as the &quot;Art Libre&quot; icon set. Extended and 
adopted for GIMP</dc:description>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs7386">
+    <linearGradient
+       osb:paint="solid"
+       id="linearGradient8074">
+      <stop
+         id="stop8072"
+         offset="0"
+         style="stop-color:#be00be;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       osb:paint="solid"
+       id="linearGradient7561">
+      <stop
+         id="stop7558"
+         offset="0"
+         style="stop-color:#a5a5a5;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       osb:paint="solid"
+       id="linearGradient7548">
+      <stop
+         id="stop7546"
+         offset="0"
+         style="stop-color:#ebebeb;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       osb:paint="solid"
+       id="linearGradient7542">
+      <stop
+         id="stop7538"
+         offset="0"
+         style="stop-color:#c9c9c9;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="matrix(0,-735328.32,170712.69,0,2464326300,577972450)"
+       osb:paint="solid"
+       id="linearGradient19282">
+      <stop
+         id="stop19284"
+         offset="0"
+         style="stop-color:#b4b4b4;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="matrix(0.34682586,0,0,0.30620888,-93.351872,584.01677)"
+       osb:paint="solid"
+       id="linearGradient19282-4">
+      <stop
+         id="stop19284-0"
+         offset="0"
+         style="stop-color:#bebebe;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(224.21083,191.51971)"
+       gradientUnits="userSpaceOnUse"
+       y2="183.23083"
+       x2="76.514008"
+       y1="183.23083"
+       x1="67.260277"
+       id="linearGradient10378"
+       xlink:href="#linearGradient19282-4" />
+    <linearGradient
+       gradientTransform="translate(256.35128,214.76037)"
+       gradientUnits="userSpaceOnUse"
+       y2="25.737938"
+       x2="-20.499094"
+       y1="25.737938"
+       x1="-28.5"
+       id="linearGradient10384"
+       xlink:href="#linearGradient19282-4" />
+  </defs>
+  <g
+     transform="translate(66.422852,-256.0432)"
+     style="display:inline"
+     id="tools">
+    <g
+       transform="translate(-127.42305,79.021454)"
+       id="gimp-tool-paintbrush"
+       style="display:inline">
+      <g
+         id="g9272"
+         transform="matrix(0.8746234,0,0,0.89178327,86.926967,167.56161)"
+         style="fill:#bebebe;fill-opacity:1;stroke:none">
+        <path
+           d="m -28.5,27.5711 c 3.111145,0.0011 2.79359,-3.323359 4.304166,-4.248979 1.750479,-1.072622 
3.284496,0.256475 3.590759,1.350292 0.386445,1.380184 -0.337829,2.508685 -1.300323,3.118949 
-1.846361,1.170674 -6.300039,0.898712 -6.594602,-0.220262 z"
+           id="path9274"
+           style="fill:url(#linearGradient10384);fill-opacity:1;stroke:none"
+           inkscape:connector-curvature="0" />
+      </g>
+      <path
+         style="fill:url(#linearGradient10378);fill-opacity:1;stroke:none"
+         d="m 76.416523,178.35668 c 0.308363,-0.6658 -0.16372,-0.92113 -0.732422,-0.35668 -3.998739,3.96884 
-4.683901,4 -8.423828,9.14967 1.00355,0.0377 1.86506,0.68644 2.3125,1.62279 4.427427,-4.77246 
4.92644,-7.33336 6.84375,-10.41578 z"
+         id="path9264"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
diff --git a/libgimpwidgets/gimpicons.h b/libgimpwidgets/gimpicons.h
index e47fb7acc5..92415965fe 100644
--- a/libgimpwidgets/gimpicons.h
+++ b/libgimpwidgets/gimpicons.h
@@ -374,6 +374,7 @@ G_BEGIN_DECLS
 #define GIMP_ICON_TOOL_N_POINT_DEFORMATION  "gimp-tool-n-point-deformation"
 #define GIMP_ICON_TOOL_OFFSET               "gimp-tool-offset"
 #define GIMP_ICON_TOOL_PAINTBRUSH           "gimp-tool-paintbrush"
+#define GIMP_ICON_TOOL_PAINT_SELECT         "gimp-tool-paint-select"
 #define GIMP_ICON_TOOL_PATH                 "gimp-tool-path"
 #define GIMP_ICON_TOOL_PENCIL               "gimp-tool-pencil"
 #define GIMP_ICON_TOOL_PERSPECTIVE          "gimp-tool-perspective"
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index e0e320b1cb..6f61854b81 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -643,6 +643,7 @@
         <menuitem action="tools-fuzzy-select" />
         <menuitem action="tools-by-color-select" />
         <menuitem action="tools-iscissors" />
+        <menuitem action="tools-paint-select" />
       </menu>
       <menu action="tools-paint-menu" name="Paint Tools">
         <menuitem action="tools-bucket-fill" />


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]