[gimp] app: port the foreground select tool to the GEGL matting ops



commit 1cd1541b2d549b6cbe4c813b45eebd9259c0bc49
Author: Miroslav Talasek <miroslav talasek seznam cz>
Date:   Wed May 8 00:00:48 2013 +0200

    app: port the foreground select tool to the GEGL matting ops
    
    This is work in progress and needs the fixed GEGL ops too.

 app/tools/gimpforegroundselectoptions.c |  429 ++++++++++++-----------
 app/tools/gimpforegroundselectoptions.h |   36 ++-
 app/tools/gimpforegroundselecttool.c    |  577 ++++++++++++++++---------------
 app/tools/gimpforegroundselecttool.h    |   19 +-
 4 files changed, 558 insertions(+), 503 deletions(-)
---
diff --git a/app/tools/gimpforegroundselectoptions.c b/app/tools/gimpforegroundselectoptions.c
index 474da98..6591bc2 100644
--- a/app/tools/gimpforegroundselectoptions.c
+++ b/app/tools/gimpforegroundselectoptions.c
@@ -26,10 +26,9 @@
 
 #include "tools-types.h"
 
-#if 0
-#include "base/siox.h"
-#endif
-
+#include "widgets/gimppropwidgets.h"
+#include "widgets/gimpspinscale.h"
+#include "widgets/gimpwidgets-constructors.h"
 #include "widgets/gimpwidgets-utils.h"
 
 #include "gimpforegroundselectoptions.h"
@@ -38,22 +37,26 @@
 #include "gimp-intl.h"
 
 
+/*
+ * for matting-global: iterations int
+ * for matting-levin:  levels int, active levels int
+ */
+
 enum
 {
   PROP_0,
-  PROP_ANTIALIAS,
-  PROP_CONTIGUOUS,
-  PROP_BACKGROUND,
+  PROP_DRAW_MODE,
   PROP_STROKE_WIDTH,
-  PROP_SMOOTHNESS,
   PROP_MASK_COLOR,
-  PROP_EXPANDED,
-  PROP_SENSITIVITY_L,
-  PROP_SENSITIVITY_A,
-  PROP_SENSITIVITY_B
+  PROP_ENGINE,
+  PROP_ITERATIONS,
+  PROP_LEVELS,
+  PROP_ACTIVE_LEVELS
 };
 
 
+
+
 static void   gimp_foreground_select_options_set_property (GObject      *object,
                                                            guint         property_id,
                                                            const GValue *value,
@@ -63,6 +66,14 @@ static void   gimp_foreground_select_options_get_property (GObject      *object,
                                                            GValue       *value,
                                                            GParamSpec   *pspec);
 
+static void   gimp_foreground_select_options_gui_reset_stroke_width (GtkWidget  *button,
+                                                                     GimpToolOptions *tool_options);
+
+
+static void   gimp_foreground_select_notify_engine (GimpToolOptions *tool_options,
+                                           GParamSpec      *pspec,
+                                           GtkWidget       *table);
+
 
 G_DEFINE_TYPE (GimpForegroundSelectOptions, gimp_foreground_select_options,
                GIMP_TYPE_SELECTION_OPTIONS)
@@ -77,40 +88,27 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
   object_class->get_property = gimp_foreground_select_options_get_property;
 
   /*  override the antialias default value from GimpSelectionOptions  */
-  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_ANTIALIAS,
-                                    "antialias",
-                                    N_("Smooth edges"),
-                                    FALSE,
-                                    GIMP_PARAM_STATIC_STRINGS);
-
-  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_CONTIGUOUS,
-                                    "contiguous",
-                                    N_("Select a single contiguous area"),
-                                    TRUE,
-                                    GIMP_PARAM_STATIC_STRINGS);
-
-  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_BACKGROUND,
-                                    "background",
-                                    N_("Paint over areas to mark color values for "
-                                       "inclusion or exclusion from selection"),
-                                    FALSE,
-                                    GIMP_PARAM_STATIC_STRINGS);
-
-  GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_STROKE_WIDTH,
-                                "stroke-width",
-                                N_("Size of the brush used for refinements"),
-                                1, 80, 18,
-                                GIMP_PARAM_STATIC_STRINGS);
-
-#if 0
-  GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SMOOTHNESS,
-                                "smoothness",
-                                N_("Smaller values give a more accurate "
-                                  "selection border but may introduce holes "
-                                  "in the selection"),
-                                0, 8, SIOX_DEFAULT_SMOOTHNESS,
-                                GIMP_PARAM_STATIC_STRINGS);
-#endif
+
+  GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_DRAW_MODE,
+                                 "draw-mode",
+                                 N_("Paint over areas to mark color values for "
+                                 "inclusion or exclusion from selection"),
+                                 GIMP_TYPE_MATTING_DRAW_MODE,
+                                 GIMP_MATTING_DRAW_MODE_FOREGROUND,
+                                 GIMP_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_ENGINE,
+                                 "engine",
+                                 N_("Matting engine to use"),
+                                 GIMP_TYPE_MATTING_ENGINE,
+                                 GIMP_MATTING_ENGINE_MATTING_GLOBAL,
+                                 GIMP_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_INSTALL_PROP_INT  (object_class, PROP_STROKE_WIDTH,
+                                 "stroke-width",
+                                 N_("Size of the brush used for refinements"),
+                                 1, 6000, 10,
+                                 GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_MASK_COLOR,
                                  "mask-color",
@@ -119,30 +117,21 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
                                  GIMP_BLUE_CHANNEL,
                                  GIMP_PARAM_STATIC_STRINGS);
 
-  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_EXPANDED,
-                                    "expanded", NULL,
-                                    FALSE,
-                                    0);
-
-#if 0
-  GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_L,
-                                   "sensitivity-l",
-                                   N_("Sensitivity for brightness component"),
-                                   0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_L,
-                                   GIMP_PARAM_STATIC_STRINGS);
-
-  GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_A,
-                                   "sensitivity-a",
-                                   N_("Sensitivity for red/green component"),
-                                   0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_A,
-                                   GIMP_PARAM_STATIC_STRINGS);
-
-  GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_B,
-                                   "sensitivity-b",
-                                   N_("Sensitivity for yellow/blue component"),
-                                   0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_B,
-                                   GIMP_PARAM_STATIC_STRINGS);
-#endif
+  GIMP_CONFIG_INSTALL_PROP_INT  (object_class, PROP_LEVELS,
+                                 "levels",
+                                 N_("Parameter for matting-levin"),
+                                 1, 10, 2,
+                                 GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_INT  (object_class, PROP_ACTIVE_LEVELS,
+                                 "active-levels",
+                                 N_("Parameter for matting-levin"),
+                                 1, 10, 2,
+                                 GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_INT  (object_class, PROP_ITERATIONS,
+                                 "iterations",
+                                 N_("Parameter for matting-global"),
+                                 1, 10, 2,
+                                 GIMP_PARAM_STATIC_STRINGS);
 }
 
 static void
@@ -159,51 +148,39 @@ gimp_foreground_select_options_set_property (GObject      *object,
   GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (object);
 
   switch (property_id)
-    {
-    case PROP_ANTIALIAS:
-      GIMP_SELECTION_OPTIONS (object)->antialias = g_value_get_boolean (value);
+  {
+    case PROP_DRAW_MODE:
+      options->draw_mode = g_value_get_enum (value);
       break;
 
-    case PROP_CONTIGUOUS:
-      options->contiguous = g_value_get_boolean (value);
-      break;
-
-    case PROP_BACKGROUND:
-      options->background = g_value_get_boolean (value);
+    case PROP_ENGINE:
+      options->engine = g_value_get_enum (value);
       break;
 
     case PROP_STROKE_WIDTH:
       options->stroke_width = g_value_get_int (value);
       break;
 
-    case PROP_SMOOTHNESS:
-      options->smoothness = g_value_get_int (value);
-      break;
-
     case PROP_MASK_COLOR:
       options->mask_color = g_value_get_enum (value);
       break;
 
-    case PROP_EXPANDED:
-      options->expanded = g_value_get_boolean (value);
-      break;
-
-    case PROP_SENSITIVITY_L:
-      options->sensitivity[0] = g_value_get_double (value);
+    case PROP_LEVELS:
+      options->levels = g_value_get_int (value);
       break;
 
-    case PROP_SENSITIVITY_A:
-      options->sensitivity[1] = g_value_get_double (value);
+    case PROP_ACTIVE_LEVELS:
+      options->active_levels = g_value_get_int (value);
       break;
 
-    case PROP_SENSITIVITY_B:
-      options->sensitivity[2] = g_value_get_double (value);
+    case PROP_ITERATIONS:
+      options->iterations = g_value_get_int (value);
       break;
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
-    }
+  }
 }
 
 static void
@@ -215,51 +192,40 @@ gimp_foreground_select_options_get_property (GObject    *object,
   GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (object);
 
   switch (property_id)
-    {
-    case PROP_ANTIALIAS:
-      g_value_set_boolean (value, GIMP_SELECTION_OPTIONS (object)->antialias);
-      break;
+  {
 
-    case PROP_CONTIGUOUS:
-      g_value_set_boolean (value, options->contiguous);
+    case PROP_DRAW_MODE:
+      g_value_set_enum (value, options->draw_mode);
       break;
 
-    case PROP_BACKGROUND:
-      g_value_set_boolean (value, options->background);
+    case PROP_ENGINE:
+      g_value_set_enum (value, options->engine);
       break;
 
     case PROP_STROKE_WIDTH:
       g_value_set_int (value, options->stroke_width);
       break;
 
-    case PROP_SMOOTHNESS:
-      g_value_set_int (value, options->smoothness);
-      break;
-
     case PROP_MASK_COLOR:
       g_value_set_enum (value, options->mask_color);
       break;
 
-    case PROP_EXPANDED:
-      g_value_set_boolean (value, options->expanded);
+    case PROP_LEVELS:
+      g_value_set_int (value, options->levels);
       break;
 
-    case PROP_SENSITIVITY_L:
-      g_value_set_double (value, options->sensitivity[0]);
+    case PROP_ACTIVE_LEVELS:
+      g_value_set_int (value, options->active_levels);
       break;
 
-    case PROP_SENSITIVITY_A:
-      g_value_set_double (value, options->sensitivity[1]);
-      break;
-
-    case PROP_SENSITIVITY_B:
-      g_value_set_double (value, options->sensitivity[2]);
+    case PROP_ITERATIONS:
+      g_value_set_int (value, options->iterations);
       break;
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
-    }
+  }
 }
 
 GtkWidget *
@@ -271,114 +237,173 @@ gimp_foreground_select_options_gui (GimpToolOptions *tool_options)
   GtkWidget       *button;
   GtkWidget       *frame;
   GtkWidget       *scale;
-  GtkWidget       *label;
-  GtkWidget       *menu;
-  GtkWidget       *inner_frame;
+  GtkWidget       *combo;
   GtkWidget       *table;
-  gchar           *title;
   gint             row = 0;
-  GdkModifierType  toggle_mask;
+  GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (config);
 
-  toggle_mask = gimp_get_toggle_behavior_mask ();
+  frame = gimp_prop_enum_radio_frame_new (config, "draw-mode", _("Draw Mode"),
+                                          0,0);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
 
-  gtk_widget_set_sensitive (GIMP_SELECTION_OPTIONS (tool_options)->antialias_toggle,
-                            FALSE);
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
 
-  /*  single / multiple objects  */
-  button = gimp_prop_check_button_new (config, "contiguous", _("Contiguous"));
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  /* stroke width */
+  scale = gimp_prop_spin_scale_new (config, "stroke-width",
+                                    _("Stroke width"),
+                                    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);
+  gtk_widget_show (scale);
+
+  button = gimp_stock_button_new (GIMP_STOCK_RESET, NULL);
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  gtk_image_set_from_stock (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (button))),
+                            GIMP_STOCK_RESET, GTK_ICON_SIZE_MENU);
+  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
   gtk_widget_show (button);
 
-  /*  foreground / background  */
-  title = g_strdup_printf (_("Interactive refinement  (%s)"),
-                           gimp_get_mod_string (toggle_mask));
+  g_signal_connect (button, "clicked",
+                        G_CALLBACK (gimp_foreground_select_options_gui_reset_stroke_width),
+                        tool_options);
 
-  frame = gimp_prop_boolean_radio_frame_new (config, "background", title,
-                                             _("Mark background"),
-                                             _("Mark foreground"));
-  g_free (title);
+  gimp_help_set_help_data (button,
+                           _("Reset stroke width native size"), NULL);
 
+  /*  mask color */
+  frame = gimp_frame_new (_("Preview color:"));
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
   gtk_widget_show (frame);
 
-  /*  stroke width  */
-  inner_frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_box_pack_start (GTK_BOX (gtk_bin_get_child (GTK_BIN (frame))),
-                      inner_frame, FALSE, FALSE, 2);
-  gtk_widget_show (inner_frame);
+  combo = gimp_prop_enum_combo_box_new (config, "mask-color",
+                                        GIMP_RED_CHANNEL, GIMP_GRAY_CHANNEL);
+  gtk_container_add (GTK_CONTAINER (frame), combo);
+  gtk_widget_show (combo);
 
-  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
-  gtk_box_pack_start (GTK_BOX (inner_frame), hbox, FALSE, FALSE, 0);
-  gtk_widget_show (hbox);
+  /* engine */
+  frame = gimp_frame_new (_("Engine:"));
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
 
-  label = gtk_label_new (_("Small brush"));
-  gimp_label_set_attributes (GTK_LABEL (label),
-                             PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-                             PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
-                             -1);
-  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-  gtk_widget_show (label);
+  combo = gimp_prop_enum_combo_box_new (config, "engine", 0, 0);
+  gtk_container_add (GTK_CONTAINER (frame), combo);
+  gtk_widget_show (combo);
 
-  label = gtk_label_new (_("Large brush"));
-  gimp_label_set_attributes (GTK_LABEL (label),
-                             PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-                             PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
-                             -1);
-  gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-  gtk_widget_show (label);
 
-  scale = gimp_prop_hscale_new (config, "stroke-width", 1.0, 5.0, 0);
-  gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
-  gtk_box_pack_start (GTK_BOX (inner_frame), scale, FALSE, FALSE, 0);
-  gtk_widget_show (scale);
+  /*  parameters  */
 
-  /*  smoothness  */
-  table = gtk_table_new (2, 3, FALSE);
-  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+  table = gtk_table_new (3, 3, FALSE);
   gtk_table_set_col_spacings (GTK_TABLE (table), 2);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
   gtk_widget_show (table);
 
-#if 0
-  scale = gimp_prop_hscale_new (config, "smoothness", 0.1, 1.0, 0);
-  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT);
-  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
-                             _("Smoothing:"), 0.0, 0.5, scale, 2, FALSE);
-#endif
+  options->dynamic_widgets.levels = (GObject *)
+    gimp_prop_scale_entry_new (config, "levels",
+                               GTK_TABLE (table), 0, row++,
+                               "Levels", 1, 1, 0, FALSE, 0, 0);
 
-  /*  mask color */
-  menu = gimp_prop_enum_combo_box_new (config, "mask-color",
-                                       GIMP_RED_CHANNEL, GIMP_BLUE_CHANNEL);
-  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
-                             _("Preview color:"), 0.0, 0.5, menu, 2, FALSE);
-
-#if 0
-  /*  granularity  */
-  frame = gimp_prop_expander_new (config, "expanded", _("Color Sensitivity"));
-  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
-  gtk_widget_show (frame);
+  options->dynamic_widgets.active_levels = (GObject *)
+    gimp_prop_scale_entry_new (config, "active-levels",
+                               GTK_TABLE (table), 0, row++,
+                               "Act. Levels", 1, 1, 0, FALSE, 0, 0);
 
-  inner_frame = gimp_frame_new ("<expander>");
-  gtk_container_add (GTK_CONTAINER (frame), inner_frame);
-  gtk_widget_show (inner_frame);
+  options->dynamic_widgets.iterations = (GObject *)
+    gimp_prop_scale_entry_new (config, "iterations",
+                               GTK_TABLE (table), 0, row++,
+                               "Iterations", 1, 1, 0, FALSE, 0, 0);
 
-  table = gtk_table_new (3, 3, FALSE);
-  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
-  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
-  gtk_container_add (GTK_CONTAINER (inner_frame), table);
-  gtk_widget_show (table);
+  g_signal_connect_object (config, "notify::engine",
+                           G_CALLBACK (gimp_foreground_select_notify_engine),
+                           NULL, 0);
+  gimp_foreground_select_notify_engine (tool_options, NULL, NULL);
 
-  gimp_prop_opacity_entry_new (config, "sensitivity-l",
-                               GTK_TABLE (table), 0, row++, "L");
+  return vbox;
+}
 
-  gimp_prop_opacity_entry_new (config, "sensitivity-a",
-                               GTK_TABLE (table), 0, row++, "a");
+static void
+gimp_foreground_select_options_gui_reset_stroke_width (GtkWidget       *button,
+                                                       GimpToolOptions *tool_options)
+{
+  g_object_set (tool_options, "stroke-width", 10, NULL);
+}
+
+static void
+gimp_foreground_select_show_scale (GObject *object)
+{
+  GtkWidget *spin;
+  GtkWidget *label;
+  GtkWidget *scale;
 
-  gimp_prop_opacity_entry_new (config, "sensitivity-b",
-                               GTK_TABLE (table), 0, row++, "b");
-#endif
+  label = g_object_get_data (object, "label");
+  spin = g_object_get_data (object, "spinbutton");
+  scale = g_object_get_data (object, "scale");
 
-  return vbox;
+  gtk_widget_show (label);
+  gtk_widget_show (spin);
+  gtk_widget_show (scale);
+}
+
+static void
+gimp_foreground_select_hide_scale (GObject *object)
+{
+  GtkWidget *spin;
+  GtkWidget *label;
+  GtkWidget *scale;
+
+  label = g_object_get_data (object, "label");
+  spin = g_object_get_data (object, "spinbutton");
+  scale = g_object_get_data (object, "scale");
+
+  gtk_widget_hide (label);
+  gtk_widget_hide (spin);
+  gtk_widget_hide (scale);
+}
+
+static void
+gimp_foreground_select_notify_engine (GimpToolOptions *tool_options,
+                                      GParamSpec      *pspec,
+                                      GtkWidget       *widget)
+{
+  GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (tool_options);
+
+  switch (options->engine)
+    {
+    case GIMP_MATTING_ENGINE_MATTING_GLOBAL:
+      gimp_foreground_select_show_scale (options->dynamic_widgets.iterations);
+      gimp_foreground_select_hide_scale (options->dynamic_widgets.levels);
+      gimp_foreground_select_hide_scale (options->dynamic_widgets.active_levels);
+      break;
+
+    case GIMP_MATTING_ENGINE_MATTING_LEVIN:
+      gimp_foreground_select_hide_scale (options->dynamic_widgets.iterations);
+      gimp_foreground_select_show_scale (options->dynamic_widgets.levels);
+      gimp_foreground_select_show_scale (options->dynamic_widgets.active_levels);
+      break;
+    }
+}
+
+gdouble
+gimp_foreground_select_options_get_opacity (GimpForegroundSelectOptions *options)
+{
+  g_return_val_if_fail (GIMP_IS_FOREGROUND_SELECT_OPTIONS (options), 0.0);
+
+  switch (options->draw_mode)
+    {
+    case GIMP_MATTING_DRAW_MODE_FOREGROUND:
+      return 1.0;
+
+    case GIMP_MATTING_DRAW_MODE_BACKGROUND:
+      return 0.0;
+
+    case GIMP_MATTING_DRAW_MODE_UNKNOWN:
+    default:
+      return 0.5;
+  }
 }
 
 void
@@ -391,15 +416,19 @@ gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *opti
   switch (options->mask_color)
     {
     case GIMP_RED_CHANNEL:
-      gimp_rgba_set (color, 1, 0, 0, 0.5);
+      gimp_rgba_set (color, 1, 0, 0, 0.7);
       break;
 
     case GIMP_GREEN_CHANNEL:
-      gimp_rgba_set (color, 0, 1, 0, 0.5);
+      gimp_rgba_set (color, 0, 1, 0, 0.7);
       break;
 
     case GIMP_BLUE_CHANNEL:
-      gimp_rgba_set (color, 0, 0, 1, 0.5);
+      gimp_rgba_set (color, 0, 0, 1, 0.7);
+      break;
+
+    case GIMP_GRAY_CHANNEL:
+      gimp_rgba_set (color, 1, 1, 1, 0.7);
       break;
 
     default:
diff --git a/app/tools/gimpforegroundselectoptions.h b/app/tools/gimpforegroundselectoptions.h
index 5423898..1e3f619 100644
--- a/app/tools/gimpforegroundselectoptions.h
+++ b/app/tools/gimpforegroundselectoptions.h
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #ifndef __GIMP_FOREGROUND_SELECT_OPTIONS_H__
 #define __GIMP_FOREGROUND_SELECT_OPTIONS_H__
 
@@ -30,20 +31,35 @@
 #define GIMP_FOREGROUND_SELECT_OPTIONS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GIMP_TYPE_FOREGROUND_SELECT_OPTIONS, GimpForegroundSelectOptionsClass))
 
 
-typedef struct _GimpForegroundSelectOptions  GimpForegroundSelectOptions;
-typedef GimpSelectionOptionsClass  GimpForegroundSelectOptionsClass;
+typedef struct _GimpForegroundSelectOptions      GimpForegroundSelectOptions;
+typedef struct _GimpForegroundSelectOptionsClass GimpForegroundSelectOptionsClass;
+
+typedef struct _GimpMattingDynamicWidgets  GimpMattingDynamicWidgets;
+
+struct _GimpMattingDynamicWidgets
+{
+  GObject *levels;
+  GObject *active_levels;
+  GObject *iterations;
+};
 
 struct _GimpForegroundSelectOptions
 {
   GimpSelectionOptions  parent_instance;
 
-  gboolean              contiguous;
-  gboolean              background;
-  gint                  stroke_width;
-  gint                  smoothness;
-  GimpChannelType       mask_color;
-  gboolean              expanded;
-  gdouble               sensitivity[3];
+  GimpMattingDrawMode       draw_mode;
+  gint                      stroke_width;
+  GimpChannelType           mask_color;
+  GimpMattingEngine         engine;
+  gint                      levels;
+  gint                      active_levels;
+  gint                      iterations;
+  GimpMattingDynamicWidgets dynamic_widgets;
+};
+
+struct _GimpForegroundSelectOptionsClass
+{
+  GimpSelectionOptionsClass  parent_class;
 };
 
 
@@ -53,6 +69,8 @@ GtkWidget * gimp_foreground_select_options_gui            (GimpToolOptions
 
 void        gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *options,
                                                            GimpRGB                     *color);
+gdouble     gimp_foreground_select_options_get_opacity    (GimpForegroundSelectOptions *options);
 
 
 #endif /* __GIMP_FOREGROUND_SELECT_OPTIONS_H__ */
+
diff --git a/app/tools/gimpforegroundselecttool.c b/app/tools/gimpforegroundselecttool.c
index 2d1792e..01d836f 100644
--- a/app/tools/gimpforegroundselecttool.c
+++ b/app/tools/gimpforegroundselecttool.c
@@ -27,16 +27,18 @@
 #include <gdk/gdkkeysyms.h>
 
 #include "libgimpmath/gimpmath.h"
+#include "libgimpcolor/gimpcolor.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
 #include "tools-types.h"
 
 #include "core/gimp.h"
-#include "core/gimpchannel.h"
 #include "core/gimpchannel-combine.h"
 #include "core/gimpchannel-select.h"
 #include "core/gimpdrawable-foreground-extract.h"
 #include "core/gimpimage.h"
+#include "core/gimplayer.h"
+#include "core/gimplayermask.h"
 #include "core/gimpprogress.h"
 #include "core/gimpscanconvert.h"
 
@@ -105,25 +107,28 @@ static void   gimp_foreground_select_tool_motion         (GimpTool         *tool
 
 static void   gimp_foreground_select_tool_draw           (GimpDrawTool     *draw_tool);
 
-static void   gimp_foreground_select_tool_select   (GimpFreeSelectTool *free_sel,
-                                                    GimpDisplay        *display);
+static void   gimp_foreground_select_tool_select         (GimpFreeSelectTool *free_sel,
+                                                          GimpDisplay        *display);
 
-static void   gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select,
-                                                    GimpDisplay              *display,
-                                                    GimpChannel              *mask);
-static void   gimp_foreground_select_tool_apply    (GimpForegroundSelectTool *fg_select,
-                                                    GimpDisplay              *display);
+static void   gimp_foreground_select_tool_set_trimap     (GimpForegroundSelectTool *fg_select,
+                                                          GimpDisplay              *display);
+static void   gimp_foreground_select_tool_set_preview    (GimpForegroundSelectTool *fg_select,
+                                                          GimpDisplay              *display);
+static void   gimp_foreground_select_tool_drop_masks     (GimpForegroundSelectTool *fg_select,
+                                                          GimpDisplay              *display);
 
-static void   gimp_foreground_select_tool_stroke   (GimpChannel              *mask,
-                                                    FgSelectStroke           *stroke);
+static void   gimp_foreground_select_tool_apply          (GimpForegroundSelectTool *fg_select,
+                                                          GimpDisplay              *display);
+static void   gimp_foreground_select_tool_preview        (GimpForegroundSelectTool *fg_select,
+                                                          GimpDisplay              *display);
 
-static void   gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool    *fg_select,
-                                                       GimpDisplay                 *display,
-                                                       GimpForegroundSelectOptions *options);
+static void   gimp_foreground_select_options_notify      (GimpForegroundSelectOptions *options,
+                                                          GParamSpec                  *pspec,
+                                                          GimpForegroundSelectTool    *fg_select);
 
-static void   gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options,
-                                                     GParamSpec                  *pspec,
-                                                     GimpForegroundSelectTool    *fg_select);
+static void   gimp_foreground_select_tool_stroke_paint   (GimpForegroundSelectTool    *fg_select,
+                                                          GimpDisplay                 *display,
+                                                          GimpForegroundSelectOptions *options);
 
 
 G_DEFINE_TYPE (GimpForegroundSelectTool, gimp_foreground_select_tool,
@@ -194,10 +199,10 @@ gimp_foreground_select_tool_init (GimpForegroundSelectTool *fg_select)
   gimp_tool_control_set_action_value_2 (tool->control,
                                         "tools/tools-foreground-select-brush-size-set");
 
-  fg_select->idle_id = 0;
   fg_select->stroke  = NULL;
-  fg_select->strokes = NULL;
   fg_select->mask    = NULL;
+  fg_select->trimap  = NULL;
+  fg_select->state   = MATTING_STATE_FREE_SELECT;
 }
 
 static void
@@ -218,18 +223,13 @@ gimp_foreground_select_tool_finalize (GObject *object)
   GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (object);
 
   if (fg_select->stroke)
-    g_warning ("%s: stroke should be NULL at this point", G_STRLOC);
-
-  if (fg_select->strokes)
-    g_warning ("%s: strokes should be NULL at this point", G_STRLOC);
-
-#if 0
-  if (fg_select->state)
-    g_warning ("%s: state should be NULL at this point", G_STRLOC);
-#endif
+      g_warning ("%s: stroke should be NULL at this point", G_STRLOC);
 
   if (fg_select->mask)
-    g_warning ("%s: mask should be NULL at this point", G_STRLOC);
+      g_warning ("%s: mask should be NULL at this point", G_STRLOC);
+
+  if (fg_select->trimap)
+      g_warning ("%s: mask should be NULL at this point", G_STRLOC);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -249,29 +249,7 @@ gimp_foreground_select_tool_control (GimpTool       *tool,
 
     case GIMP_TOOL_ACTION_HALT:
       {
-        GList *list;
-
-        gimp_foreground_select_tool_set_mask (fg_select, display, NULL);
-
-        for (list = fg_select->strokes; list; list = list->next)
-          {
-            FgSelectStroke *stroke = list->data;
-
-            g_free (stroke->points);
-            g_slice_free (FgSelectStroke, stroke);
-          }
-
-        g_list_free (fg_select->strokes);
-        fg_select->strokes = NULL;
-
-#if 0
-        if (fg_select->state)
-          {
-            gimp_drawable_foreground_extract_siox_done (fg_select->state);
-            fg_select->state = NULL;
-          }
-#endif
-
+        gimp_foreground_select_tool_drop_masks (fg_select, display);
         tool->display = NULL;
       }
       break;
@@ -293,7 +271,7 @@ gimp_foreground_select_tool_oper_update (GimpTool         *tool,
   GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
                                                display);
 
-  if (fg_select->mask && display == tool->display)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP && display == tool->display)
     {
       GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
 
@@ -302,17 +280,17 @@ gimp_foreground_select_tool_oper_update (GimpTool         *tool,
       fg_select->last_coords = *coords;
 
       gimp_draw_tool_resume (draw_tool);
-
-      if (fg_select->strokes)
-        status = _("Add more strokes or press Enter to accept the selection");
-      else
-        status = _("Mark foreground by painting on the object to extract");
+      status = _("Paint trimap, (background, foreground and unknown) or press Enter to preview");
     }
-  else
+  else if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
       if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_SELECT)
         status = _("Roughly outline the object to extract");
     }
+  else
+    {
+      status = _("Press escape for return to trimap or Enter to apply");
+    }
 
   if (proximity && status)
     gimp_tool_replace_status (tool, display, "%s", status);
@@ -325,6 +303,7 @@ gimp_foreground_select_tool_modifier_key (GimpTool        *tool,
                                           GdkModifierType  state,
                                           GimpDisplay     *display)
 {
+#if 0
   if (key == gimp_get_toggle_behavior_mask ())
     {
       GimpForegroundSelectOptions *options;
@@ -335,6 +314,7 @@ gimp_foreground_select_tool_modifier_key (GimpTool        *tool,
                     "background", ! options->background,
                     NULL);
     }
+#endif
 }
 
 static void
@@ -345,14 +325,8 @@ gimp_foreground_select_tool_cursor_update (GimpTool         *tool,
 {
   GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
 
-  if (fg_select->mask)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
-      GimpForegroundSelectOptions *options;
-
-      options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
-
-      gimp_tool_control_set_toggled (tool->control, options->background);
-
       switch (GIMP_SELECTION_TOOL (tool)->function)
         {
         case SELECTION_MOVE_MASK:
@@ -378,17 +352,14 @@ gimp_foreground_select_tool_key_press (GimpTool    *tool,
   if (display != tool->display)
     return FALSE;
 
-#if 0
-  if (fg_select->state)
-#endif
-  if (fg_select->mask) /* dunno if that's the right condition */
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
       switch (kevent->keyval)
         {
         case GDK_KEY_Return:
         case GDK_KEY_KP_Enter:
         case GDK_KEY_ISO_Enter:
-          gimp_foreground_select_tool_apply (fg_select, display);
+          gimp_foreground_select_tool_preview (fg_select, display);
           return TRUE;
 
         case GDK_KEY_Escape:
@@ -399,6 +370,24 @@ gimp_foreground_select_tool_key_press (GimpTool    *tool,
           return FALSE;
         }
     }
+  else if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
+    {
+      switch (kevent->keyval)
+        {
+        case GDK_KEY_Return:
+        case GDK_KEY_KP_Enter:
+        case GDK_KEY_ISO_Enter:
+          gimp_foreground_select_tool_apply (fg_select, display);
+          return TRUE;
+
+        case GDK_KEY_Escape:
+          gimp_foreground_select_tool_set_trimap (fg_select, display);
+          return TRUE;
+
+        default:
+          return FALSE;
+        }
+    }
   else
     {
       return GIMP_TOOL_CLASS (parent_class)->key_press (tool,
@@ -418,7 +407,7 @@ gimp_foreground_select_tool_button_press (GimpTool            *tool,
   GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
   GimpDrawTool             *draw_tool = GIMP_DRAW_TOOL (tool);
 
-  if (fg_select->mask)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
       GimpVector2 point = gimp_vector2_new (coords->x, coords->y);
 
@@ -436,12 +425,12 @@ gimp_foreground_select_tool_button_press (GimpTool            *tool,
 
       g_array_append_val (fg_select->stroke, point);
 
-      if (! gimp_draw_tool_is_active (draw_tool))
+      if (!gimp_draw_tool_is_active (draw_tool))
         gimp_draw_tool_start (draw_tool, display);
 
       gimp_draw_tool_resume (draw_tool);
     }
-  else
+  else if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
       GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
                                                     press_type, display);
@@ -458,7 +447,7 @@ gimp_foreground_select_tool_button_release (GimpTool              *tool,
 {
   GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
 
-  if (fg_select->mask)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
       GimpForegroundSelectOptions *options;
 
@@ -468,13 +457,15 @@ gimp_foreground_select_tool_button_release (GimpTool              *tool,
 
       gimp_tool_control_halt (tool->control);
 
-      gimp_foreground_select_tool_push_stroke (fg_select, display, options);
+      gimp_foreground_select_tool_stroke_paint (fg_select, display, options);
+
+      gimp_foreground_select_tool_set_trimap (fg_select, display);
 
       gimp_free_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), display);
 
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
     }
-  else
+  else if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
       GIMP_TOOL_CLASS (parent_class)->button_release (tool,
                                                       coords, time, state,
@@ -492,7 +483,7 @@ gimp_foreground_select_tool_motion (GimpTool         *tool,
 {
   GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
 
-  if (fg_select->mask)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
       GimpVector2 *last = &g_array_index (fg_select->stroke,
                                           GimpVector2,
@@ -511,7 +502,7 @@ gimp_foreground_select_tool_motion (GimpTool         *tool,
 
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
     }
-  else
+  else if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
       GIMP_TOOL_CLASS (parent_class)->motion (tool,
                                               coords, time, state, display);
@@ -550,24 +541,23 @@ gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool)
 
   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),
-                              (options->background ?
-                               GIMP_ACTIVE_COLOR_BACKGROUND :
-                               GIMP_ACTIVE_COLOR_FOREGROUND),
-                              options->stroke_width);
+                              GIMP_ACTIVE_COLOR_FOREGROUND,
+                              options->stroke_width * shell->scale_y);
     }
 
-  if (fg_select->mask)
+  if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
     {
-      GimpDisplayShell   *shell = gimp_display_get_shell (draw_tool->display);
-      gint                x     = fg_select->last_coords.x;
-      gint                y     = fg_select->last_coords.y;
-      gdouble             radius;
+      gint    x = fg_select->last_coords.x;
+      gint    y = fg_select->last_coords.y;
+      gdouble radius;
 
-      radius = (options->stroke_width / shell->scale_y) / 2;
+      radius = options->stroke_width / 2;
 
       /*  warn if the user is drawing outside of the working area  */
       if (FALSE)
@@ -592,7 +582,7 @@ gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool)
                               2 * radius, 2 * radius,
                               0.0, 2.0 * G_PI);
     }
-  else
+  else if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
       GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
     }
@@ -602,110 +592,111 @@ static void
 gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
                                     GimpDisplay        *display)
 {
-  GimpForegroundSelectTool    *fg_select;
-  GimpForegroundSelectOptions *options;
-  GimpImage                   *image = gimp_display_get_image (display);
-  GimpDrawable                *drawable;
-  GimpScanConvert             *scan_convert;
-  GimpChannel                 *mask;
-  const GimpVector2           *points;
-  gint                         n_points;
+  GimpForegroundSelectTool *fg_select;
+  GimpImage                *image = gimp_display_get_image (display);
+  GimpDrawable             *drawable;
+  GimpScanConvert          *scan_convert;
+  const GimpVector2        *points;
+  gint                      n_points;
 
   drawable  = gimp_image_get_active_drawable (image);
   fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel);
-  options   = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (free_sel);
-
-  if (fg_select->idle_id)
-    {
-      g_source_remove (fg_select->idle_id);
-      fg_select->idle_id = 0;
-    }
 
   if (! drawable)
     return;
 
-  scan_convert = gimp_scan_convert_new ();
-
-  gimp_free_select_tool_get_points (free_sel,
-                                    &points,
-                                    &n_points);
-
-  gimp_scan_convert_add_polyline (scan_convert,
-                                  n_points,
-                                  points,
-                                  TRUE);
-
-  mask = gimp_channel_new (image,
-                           gimp_image_get_width (image),
-                           gimp_image_get_height (image),
-                           "foreground-extraction", NULL);
-
-  gimp_scan_convert_render_value (scan_convert,
-                                  gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
-                                  0, 0, 0.5);
-  gimp_scan_convert_free (scan_convert);
-
-  if (fg_select->strokes)
+  if (fg_select->state == MATTING_STATE_FREE_SELECT)
     {
-      GList *list;
+      scan_convert = gimp_scan_convert_new ();
 
-      gimp_set_busy (image->gimp);
+      gimp_free_select_tool_get_points (free_sel,
+                                        &points,
+                                        &n_points);
 
-      /*  apply foreground and background markers  */
-      for (list = fg_select->strokes; list; list = list->next)
-        gimp_foreground_select_tool_stroke (mask, list->data);
+      gimp_scan_convert_add_polyline (scan_convert,
+                                      n_points,
+                                      points,
+                                      TRUE);
 
-#if 0
-      if (fg_select->state)
-        gimp_drawable_foreground_extract_siox (GIMP_DRAWABLE (mask),
-                                               fg_select->state,
-                                               fg_select->refinement,
-                                               options->smoothness,
-                                               options->sensitivity,
-                                               ! options->contiguous,
-                                               GIMP_PROGRESS (fg_select));
-#endif
+      fg_select->trimap  = gimp_channel_new (image,
+                                             gimp_image_get_width  (image),
+                                             gimp_image_get_height (image),
+                                             "foreground-extraction",NULL);
 
-      fg_select->refinement = SIOX_REFINEMENT_NO_CHANGE;
+      gimp_scan_convert_render_value (scan_convert,
+                                      gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap)),
+                                      0, 0, 1.0);
+      gimp_scan_convert_free (scan_convert);
 
-      gimp_unset_busy (image->gimp);
+      gimp_foreground_select_tool_set_trimap (fg_select, display);
     }
-  else
-    {
-      gint x1, y1;
-      gint x2, y2;
+}
 
-      g_object_set (options, "background", FALSE, NULL);
+static void
+gimp_foreground_select_tool_set_trimap (GimpForegroundSelectTool *fg_select,
+                                        GimpDisplay              *display)
+{
+  GimpTool                    *tool = GIMP_TOOL (fg_select);
+  GimpForegroundSelectOptions *options;
+  GimpRGB                      color;
 
-      gimp_foreground_select_tool_get_area (mask, &x1, &y1, &x2, &y2);
+  g_return_if_fail (fg_select->trimap != NULL);
 
-#if 0
-      if (fg_select->state)
-        g_warning ("state should be NULL here");
+  options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
 
-      fg_select->state =
-        gimp_drawable_foreground_extract_siox_init (drawable,
-                                                    x1, y1, x2 - x1, y2 - y1);
-#endif
-    }
+  gimp_foreground_select_options_get_mask_color (options, &color);
+  gimp_display_shell_set_mask (gimp_display_get_shell (display),
+                               GIMP_DRAWABLE (fg_select->trimap), &color);
+
+  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_foreground_select_tool_set_mask (fg_select, display, mask);
+  gimp_tool_control_set_toggled (tool->control, FALSE);
 
-  g_object_unref (mask);
+  fg_select->state = MATTING_STATE_PAINT_TRIMAP;
 }
 
 static void
-gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select,
-                                      GimpDisplay              *display,
-                                      GimpChannel              *mask)
+gimp_foreground_select_tool_set_preview (GimpForegroundSelectTool *fg_select,
+                                         GimpDisplay              *display)
 {
+
   GimpTool                    *tool = GIMP_TOOL (fg_select);
   GimpForegroundSelectOptions *options;
+  GimpRGB                      color;
+
+  g_return_if_fail (fg_select->mask != NULL);
 
   options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
 
-  if (fg_select->mask == mask)
-    return;
+  gimp_foreground_select_options_get_mask_color (options, &color);
+  gimp_rgb_set_alpha (&color, 1.0);
+  gimp_display_shell_set_mask (gimp_display_get_shell (display),
+                               GIMP_DRAWABLE (fg_select->mask), &color);
+
+  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;
+}
+
+static void
+gimp_foreground_select_tool_drop_masks (GimpForegroundSelectTool *fg_select,
+                                        GimpDisplay              *display)
+{
+  GimpTool *tool = GIMP_TOOL (fg_select);
+
+  if (fg_select->trimap)
+    {
+      g_object_unref (fg_select->trimap);
+      fg_select->trimap = NULL;
+    }
 
   if (fg_select->mask)
     {
@@ -713,59 +704,136 @@ gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select,
       fg_select->mask = NULL;
     }
 
-  if (mask)
-    {
-      GimpRGB color;
-
-      fg_select->mask = g_object_ref (mask);
-
-      gimp_foreground_select_options_get_mask_color (options, &color);
-      gimp_display_shell_set_mask (gimp_display_get_shell (display),
-                                   GIMP_DRAWABLE (mask), &color);
-    }
-  else
+  if (GIMP_IS_DISPLAY (display))
     {
       gimp_display_shell_set_mask (gimp_display_get_shell (display),
                                    NULL, NULL);
     }
 
-  if (mask)
+  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);
+  fg_select->state = MATTING_STATE_FREE_SELECT;
+}
+
+static void
+gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select,
+                                     GimpDisplay              *display)
+{
+  GimpTool                    *tool     = GIMP_TOOL (fg_select);
+  GimpForegroundSelectOptions *options  = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
+  GimpImage                   *image    = gimp_display_get_image (display);
+  GimpDrawable                *drawable = gimp_image_get_active_drawable (image);
+  GeglBuffer                  *trimap_buffer;
+  GeglBuffer                  *drawable_buffer;
+  GeglNode                    *gegl;
+  GeglNode                    *matting_node;
+  GeglNode                    *input_image;
+  GeglNode                    *input_trimap;
+  GeglNode                    *output_mask;
+  GeglBuffer                  *buffer;
+  GimpProgress                *progress;
+  GeglProcessor               *processor;
+  gdouble                     value;
+
+  if (fg_select->mask)
     {
-      gimp_tool_control_set_tool_cursor        (tool->control,
-                                                GIMP_TOOL_CURSOR_PAINTBRUSH);
-      gimp_tool_control_set_toggle_tool_cursor (tool->control,
-                                                GIMP_TOOL_CURSOR_ERASER);
+      g_object_unref (fg_select->mask);
+      fg_select->mask = NULL;
+    }
 
-      gimp_tool_control_set_toggled (tool->control, options->background);
+  progress = gimp_progress_start (GIMP_PROGRESS (fg_select),
+                                  _("Computing alpha of unknown pixels"),
+                                  FALSE);
+
+  trimap_buffer   = gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap));
+  drawable_buffer = gimp_drawable_get_buffer (drawable);
+
+  gegl = gegl_node_new ();
+
+  input_trimap = gegl_node_new_child (gegl,
+                                      "operation", "gegl:buffer-source",
+                                      "buffer",    trimap_buffer,
+                                      NULL);
+  input_image = gegl_node_new_child (gegl,
+                                     "operation", "gegl:buffer-source",
+                                     "buffer",    drawable_buffer,
+                                     NULL);
+  output_mask = gegl_node_new_child (gegl,
+                                     "operation", "gegl:buffer-sink",
+                                     "buffer",    &buffer,
+                                     "format",    NULL,
+                                     NULL);
+
+  if (options->engine == GIMP_MATTING_ENGINE_MATTING_GLOBAL)
+    {
+      matting_node = gegl_node_new_child (gegl,
+                                          "operation",  "gegl:matting-global",
+                                          "iterations", options->iterations,
+                                          NULL);
     }
   else
     {
-      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);
+      matting_node = gegl_node_new_child (gegl,
+                                          "operation",     "gegl:matting-levin",
+                                          "levels",        options->levels,
+                                          "active_levels", options->active_levels,
+                                          NULL);
+    }
 
-      gimp_tool_control_set_toggled (tool->control, FALSE);
+  gegl_node_connect_to (input_image,  "output",
+                        matting_node, "input");
+  gegl_node_connect_to (input_trimap, "output",
+                        matting_node, "aux");
+  gegl_node_connect_to (matting_node, "output",
+                        output_mask,  "input");
+
+  processor = gegl_node_new_processor (output_mask, NULL);
+
+  while (gegl_processor_work (processor, &value))
+    {
+      if (progress)
+        gimp_progress_set_value (progress, value);
     }
+
+  if (progress)
+    gimp_progress_end (progress);
+
+  g_object_unref (processor);
+
+  fg_select->mask = gimp_channel_new_from_buffer (buffer, image,
+                                                  "preview-mask", NULL);
+
+  gimp_foreground_select_tool_set_preview (fg_select, display);
+
+  g_object_unref (gegl);
+
+  if (buffer)
+    g_object_unref (buffer);
 }
 
 static void
 gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
                                    GimpDisplay              *display)
 {
-  GimpTool             *tool    = GIMP_TOOL (fg_select);
-  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
-  GimpImage            *image   = gimp_display_get_image (display);
+  GimpTool      *tool    = GIMP_TOOL (fg_select);
+  GimpImage     *image   = gimp_display_get_image (display);
+  GimpLayer     *layer   = gimp_image_get_active_layer (image);
+  GeglBuffer    *buffer;
+  GimpLayerMask *layer_mask;
+  GimpRGB        color   = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
 
   g_return_if_fail (fg_select->mask != NULL);
 
-  gimp_channel_select_channel (gimp_image_get_mask (image),
-                               C_("command", "Foreground Select"),
-                               fg_select->mask, 0, 0,
-                               options->operation,
-                               options->feather,
-                               options->feather_radius,
-                               options->feather_radius);
+  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->mask));
+
+  layer_mask = gimp_layer_mask_new_from_buffer (buffer, image,
+                                                "mask", &color);
+
+  gimp_layer_add_mask (layer, layer_mask, TRUE, NULL);
 
   gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
 
@@ -773,16 +841,22 @@ gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
 }
 
 static void
-gimp_foreground_select_tool_stroke (GimpChannel    *mask,
-                                    FgSelectStroke *stroke)
+gimp_foreground_select_tool_stroke_paint (GimpForegroundSelectTool    *fg_select,
+                                          GimpDisplay                 *display,
+                                          GimpForegroundSelectOptions *options)
 {
-  GimpScanConvert *scan_convert = gimp_scan_convert_new ();
+  GimpScanConvert *scan_convert;
+  gint             width;
+
+  g_return_if_fail (fg_select->stroke != NULL);
+
+  scan_convert = gimp_scan_convert_new ();
 
-  if (stroke->num_points == 1)
+  if (fg_select->stroke->len == 1)
     {
       GimpVector2 points[2];
 
-      points[0] = points[1] = stroke->points[0];
+      points[0] = points[1] = ((GimpVector2 *) fg_select->stroke->data)[0];
 
       points[1].x += 0.01;
       points[1].y += 0.01;
@@ -792,111 +866,50 @@ gimp_foreground_select_tool_stroke (GimpChannel    *mask,
   else
     {
       gimp_scan_convert_add_polyline (scan_convert,
-                                      stroke->num_points, stroke->points,
+                                      fg_select->stroke->len,
+                                      (GimpVector2 *) fg_select->stroke->data,
                                       FALSE);
     }
 
+  width = ROUND ((gdouble) options->stroke_width);
+
   gimp_scan_convert_stroke (scan_convert,
-                            stroke->width,
+                            width,
                             GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0,
                             0.0, NULL);
-  gimp_scan_convert_compose_value (scan_convert,
-                                   gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
-                                   0, 0, stroke->background ? 0.0 : 1.0);
-  gimp_scan_convert_free (scan_convert);
-}
 
-static void
-gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool    *fg_select,
-                                         GimpDisplay                 *display,
-                                         GimpForegroundSelectOptions *options)
-{
-  GimpDisplayShell *shell = gimp_display_get_shell (display);
-  FgSelectStroke   *stroke;
-
-  g_return_if_fail (fg_select->stroke != NULL);
-
-  stroke = g_slice_new (FgSelectStroke);
+  gimp_scan_convert_compose_value (scan_convert,
+                                   gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap)),
+                                   0, 0,
+                                   gimp_foreground_select_options_get_opacity (options));
 
-  stroke->background = options->background;
-  stroke->width      = ROUND ((gdouble) options->stroke_width / shell->scale_y);
-  stroke->num_points = fg_select->stroke->len;
-  stroke->points     = (GimpVector2 *) g_array_free (fg_select->stroke, FALSE);
+  gimp_scan_convert_free (scan_convert);
 
+  g_array_free (fg_select->stroke, TRUE);
   fg_select->stroke = NULL;
 
-  fg_select->strokes = g_list_append (fg_select->strokes, stroke);
-
-  fg_select->refinement |= (stroke->background ?
-                            SIOX_REFINEMENT_ADD_BACKGROUND :
-                            SIOX_REFINEMENT_ADD_FOREGROUND);
-}
-
-static gboolean
-gimp_foreground_select_tool_idle_select (GimpForegroundSelectTool *fg_select)
-{
-  GimpTool *tool = GIMP_TOOL (fg_select);
-
-  fg_select->idle_id = 0;
-
-  if (tool->display)
-    gimp_free_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), tool->display);
-
-  return FALSE;
 }
 
-/* To compress close notify signals, the process is delayed by */
-#define MINIMUM_DELAY 300
-
 static void
 gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options,
                                        GParamSpec                  *pspec,
                                        GimpForegroundSelectTool    *fg_select)
 {
-  SioxRefinementType refinement = 0;
-
-  if (! fg_select->mask)
-    return;
-
-#if 0
-  if (strcmp (pspec->name, "smoothness") == 0)
-    {
-      refinement = SIOX_REFINEMENT_CHANGE_SMOOTHNESS;
-    }
-  else if (strcmp (pspec->name, "contiguous") == 0)
-    {
-      refinement = SIOX_REFINEMENT_CHANGE_MULTIBLOB;
-    }
-  else if (g_str_has_prefix (pspec->name, "sensitivity"))
-    {
-      refinement = SIOX_REFINEMENT_CHANGE_SENSITIVITY;
-    }
-#endif
-
-  if (refinement && fg_select->strokes)
-    {
-      fg_select->refinement |= refinement;
-
-      if (fg_select->idle_id)
-        g_source_remove (fg_select->idle_id);
-
-      fg_select->idle_id = 
-        g_timeout_add_full (G_PRIORITY_LOW, MINIMUM_DELAY,
-                            (GSourceFunc) gimp_foreground_select_tool_idle_select,
-                            fg_select, NULL);
-    }
-
   if (g_str_has_prefix (pspec->name, "mask-color"))
     {
       GimpTool *tool = GIMP_TOOL (fg_select);
 
-      if (tool->display && fg_select->mask)
+      if (tool->display)
         {
-          GimpRGB color;
+          if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
+            {
+              gimp_foreground_select_tool_set_trimap (fg_select, tool->display);
+            }
 
-          gimp_foreground_select_options_get_mask_color (options, &color);
-          gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
-                                       GIMP_DRAWABLE (fg_select->mask), &color);
+          if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
+            {
+              gimp_foreground_select_tool_set_preview (fg_select, tool->display);
+            }
         }
     }
 }
diff --git a/app/tools/gimpforegroundselecttool.h b/app/tools/gimpforegroundselecttool.h
index 2903724..f2e2982 100644
--- a/app/tools/gimpforegroundselecttool.h
+++ b/app/tools/gimpforegroundselecttool.h
@@ -22,13 +22,12 @@
 #include "gimpfreeselecttool.h"
 
 
-typedef enum  /*< pdb-skip, skip >*/
+typedef enum
 {
-  SIOX_REFINEMENT_NO_CHANGE          = 0,
-  SIOX_REFINEMENT_ADD_FOREGROUND     = (1 << 0),
-  SIOX_REFINEMENT_ADD_BACKGROUND     = (1 << 1),
-  SIOX_REFINEMENT_RECALCULATE        = 0xFF
-} SioxRefinementType;
+  MATTING_STATE_FREE_SELECT = 0,
+  MATTING_STATE_PAINT_TRIMAP,
+  MATTING_STATE_PREVIEW_MASK,
+} MattingState;
 
 
 #define GIMP_TYPE_FOREGROUND_SELECT_TOOL            (gimp_foreground_select_tool_get_type ())
@@ -49,14 +48,10 @@ struct _GimpForegroundSelectTool
   GimpFreeSelectTool  parent_instance;
 
   GimpCoords          last_coords;
-  guint               idle_id;
   GArray             *stroke;
-  GList              *strokes;
+  GimpChannel        *trimap;
   GimpChannel        *mask;
-#if 0
-  SioxState          *state;
-#endif
-  SioxRefinementType  refinement;
+  MattingState        state;
 };
 
 struct _GimpForegroundSelectToolClass


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