[gimp] app: rework the Align tool interaction taking multi-item selection into account.



commit 4eaf6c16b9f7b3ee610847b2ad6d601aa024b56e
Author: Jehan <jehan girinstud io>
Date:   Thu Oct 13 17:47:01 2022 +0200

    app: rework the Align tool interaction taking multi-item selection into account.
    
    The old interaction was quite horrible. I don't think I ever really got a good
    use of it. It was so hard to understand what you were picking and so on.
    
    Now that we can multi-select items, let's just use this as the base of what we
    want to align or distribute. Clicking on canvas will now mostly be used to pick
    an item as reference. From now on, only the reference object will get on-canvas
    handle, making it very obvious how your alignment or distribution will work.
    
    I leave only an alternative picking method (with Alt or Shift-Alt pick) to add
    guides to objects to align or distributes, as these don't have a selection
    dockable.
    
    I'm also improving the selection of stacked layers by looping through them
    (similar as the layer selection on canvas feature) so that we can select even
    background layers which have a lot of layers showing above.
    
    I am planning to improve this tool even further, but this is a first step to
    make it actually usable within the new multi-item interaction logic.

 app/core/core-enums.c        |  10 +-
 app/core/core-enums.h        |   9 +-
 app/tools/gimpalignoptions.c | 482 +++++++++++++++++++++++++++++++++++++---
 app/tools/gimpalignoptions.h |  30 ++-
 app/tools/gimpaligntool.c    | 514 +++++++++++++++++--------------------------
 app/tools/gimpaligntool.h    |  19 +-
 6 files changed, 698 insertions(+), 366 deletions(-)
---
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index 235cd8c2ae..a50782242e 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -14,23 +14,17 @@ gimp_align_reference_type_get_type (void)
 {
   static const GEnumValue values[] =
   {
-    { GIMP_ALIGN_REFERENCE_FIRST, "GIMP_ALIGN_REFERENCE_FIRST", "first" },
     { GIMP_ALIGN_REFERENCE_IMAGE, "GIMP_ALIGN_REFERENCE_IMAGE", "image" },
     { GIMP_ALIGN_REFERENCE_SELECTION, "GIMP_ALIGN_REFERENCE_SELECTION", "selection" },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_LAYER, "GIMP_ALIGN_REFERENCE_ACTIVE_LAYER", "active-layer" },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_CHANNEL, "GIMP_ALIGN_REFERENCE_ACTIVE_CHANNEL", "active-channel" },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_PATH, "GIMP_ALIGN_REFERENCE_ACTIVE_PATH", "active-path" },
+    { GIMP_ALIGN_REFERENCE_PICK, "GIMP_ALIGN_REFERENCE_PICK", "pick" },
     { 0, NULL, NULL }
   };
 
   static const GimpEnumDesc descs[] =
   {
-    { GIMP_ALIGN_REFERENCE_FIRST, NC_("align-reference-type", "First item"), NULL },
     { GIMP_ALIGN_REFERENCE_IMAGE, NC_("align-reference-type", "Image"), NULL },
     { GIMP_ALIGN_REFERENCE_SELECTION, NC_("align-reference-type", "Selection"), NULL },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_LAYER, NC_("align-reference-type", "Active layer"), NULL },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_CHANNEL, NC_("align-reference-type", "Active channel"), NULL },
-    { GIMP_ALIGN_REFERENCE_ACTIVE_PATH, NC_("align-reference-type", "Active path"), NULL },
+    { GIMP_ALIGN_REFERENCE_PICK, NC_("align-reference-type", "Picked reference object"), NULL },
     { 0, NULL, NULL }
   };
 
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index cc6d64b179..350b6e26ff 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -42,12 +42,9 @@ GType gimp_align_reference_type_get_type (void) G_GNUC_CONST;
 
 typedef enum  /*< pdb-skip >*/
 {
-  GIMP_ALIGN_REFERENCE_FIRST,          /*< desc="First item"     >*/
-  GIMP_ALIGN_REFERENCE_IMAGE,          /*< desc="Image"          >*/
-  GIMP_ALIGN_REFERENCE_SELECTION,      /*< desc="Selection"      >*/
-  GIMP_ALIGN_REFERENCE_ACTIVE_LAYER,   /*< desc="Active layer"   >*/
-  GIMP_ALIGN_REFERENCE_ACTIVE_CHANNEL, /*< desc="Active channel" >*/
-  GIMP_ALIGN_REFERENCE_ACTIVE_PATH     /*< desc="Active path"    >*/
+  GIMP_ALIGN_REFERENCE_IMAGE,          /*< desc="Image"                   >*/
+  GIMP_ALIGN_REFERENCE_SELECTION,      /*< desc="Selection"               >*/
+  GIMP_ALIGN_REFERENCE_PICK,           /*< desc="Picked reference object" >*/
 } GimpAlignReferenceType;
 
 
diff --git a/app/tools/gimpalignoptions.c b/app/tools/gimpalignoptions.c
index 4787c4a27a..4d641c10b5 100644
--- a/app/tools/gimpalignoptions.c
+++ b/app/tools/gimpalignoptions.c
@@ -26,6 +26,16 @@
 
 #include "tools-types.h"
 
+#include "core/gimp.h"
+#include "core/gimpguide.h"
+#include "core/gimpimage.h"
+#include "core/gimplayer.h"
+#include "core/gimpchannel.h"
+
+#include "vectors/gimpvectors.h"
+
+#include "widgets/gimpwidgets-utils.h"
+
 #include "gimpalignoptions.h"
 #include "gimptooloptions-gui.h"
 
@@ -43,21 +53,50 @@ enum
   PROP_0,
   PROP_ALIGN_REFERENCE,
   PROP_OFFSET_X,
-  PROP_OFFSET_Y
+  PROP_OFFSET_Y,
+  PROP_ALIGN_LAYERS,
+  PROP_ALIGN_VECTORS,
+};
+
+struct _GimpAlignOptionsPrivate
+{
+  gboolean   align_layers;
+  gboolean   align_vectors;
+
+  GList     *selected_guides;
+  GObject   *reference;
+
+  GtkWidget *selected_guides_label;
+  GtkWidget *reference_combo;
+  GtkWidget *reference_box;
+  GtkWidget *reference_label;
+  GtkWidget *button[ALIGN_OPTIONS_N_BUTTONS];
 };
 
 
-static void   gimp_align_options_set_property (GObject      *object,
-                                               guint         property_id,
-                                               const GValue *value,
-                                               GParamSpec   *pspec);
-static void   gimp_align_options_get_property (GObject      *object,
-                                               guint         property_id,
-                                               GValue       *value,
-                                               GParamSpec   *pspec);
+static void   gimp_align_options_finalize               (GObject           *object);
+static void   gimp_align_options_set_property           (GObject           *object,
+                                                         guint              property_id,
+                                                         const GValue      *value,
+                                                         GParamSpec        *pspec);
+static void   gimp_align_options_get_property           (GObject           *object,
+                                                         guint              property_id,
+                                                         GValue            *value,
+                                                         GParamSpec        *pspec);
 
+static void   gimp_align_options_image_changed          (GimpContext      *context,
+                                                         GimpImage        *image,
+                                                         GimpAlignOptions *options);
 
-G_DEFINE_TYPE (GimpAlignOptions, gimp_align_options, GIMP_TYPE_TOOL_OPTIONS)
+static void   gimp_align_options_update_area            (GimpAlignOptions *options);
+static void   gimp_align_options_guide_removed          (GimpImage        *image,
+                                                         GimpGuide        *guide,
+                                                         GimpAlignOptions *options);
+static void   gimp_align_options_reference_removed      (GObject          *object,
+                                                         GimpAlignOptions *options);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpAlignOptions, gimp_align_options, GIMP_TYPE_TOOL_OPTIONS)
 
 #define parent_class gimp_selection_options_parent_class
 
@@ -69,6 +108,7 @@ gimp_align_options_class_init (GimpAlignOptionsClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->finalize      = gimp_align_options_finalize;
   object_class->set_property  = gimp_align_options_set_property;
   object_class->get_property  = gimp_align_options_get_property;
 
@@ -89,7 +129,7 @@ gimp_align_options_class_init (GimpAlignOptionsClass *klass)
                          _("Relative to"),
                          _("Reference image object a layer will be aligned on"),
                          GIMP_TYPE_ALIGN_REFERENCE_TYPE,
-                         GIMP_ALIGN_REFERENCE_FIRST,
+                         GIMP_ALIGN_REFERENCE_IMAGE,
                          GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET_X,
@@ -105,11 +145,37 @@ gimp_align_options_class_init (GimpAlignOptionsClass *klass)
                            _("Vertical offset for distribution"),
                            -GIMP_MAX_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE, 0,
                            GIMP_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_LAYERS,
+                            "align-layers",
+                            _("Align or distribute selected layers"),
+                            _("Selected layers will be aligned or distributed by the tool"),
+                            TRUE,
+                            GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ALIGN_VECTORS,
+                            "align-vectors",
+                            _("Align or distribute selected paths"),
+                            _("Selected paths will be aligned or distributed by the tool"),
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS);
 }
 
 static void
 gimp_align_options_init (GimpAlignOptions *options)
 {
+  options->priv = gimp_align_options_get_instance_private (options);
+
+  options->priv->selected_guides = NULL;
+}
+
+static void
+gimp_align_options_finalize (GObject *object)
+{
+  GimpAlignOptions *options = GIMP_ALIGN_OPTIONS (object);
+
+  if (GIMP_CONTEXT (options)->gimp)
+    gimp_align_options_image_changed (gimp_get_user_context (GIMP_CONTEXT (options)->gimp),
+                                      NULL, options);
 }
 
 static void
@@ -124,16 +190,25 @@ gimp_align_options_set_property (GObject      *object,
     {
     case PROP_ALIGN_REFERENCE:
       options->align_reference = g_value_get_enum (value);
+      gimp_align_options_update_area (options);
       break;
 
     case PROP_OFFSET_X:
       options->offset_x = g_value_get_double (value);
       break;
-
     case PROP_OFFSET_Y:
       options->offset_y = g_value_get_double (value);
       break;
 
+    case PROP_ALIGN_LAYERS:
+      options->priv->align_layers = g_value_get_boolean (value);
+      gimp_align_options_update_area (options);
+      break;
+    case PROP_ALIGN_VECTORS:
+      options->priv->align_vectors = g_value_get_boolean (value);
+      gimp_align_options_update_area (options);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -157,11 +232,17 @@ gimp_align_options_get_property (GObject    *object,
     case PROP_OFFSET_X:
       g_value_set_double (value, options->offset_x);
       break;
-
     case PROP_OFFSET_Y:
       g_value_set_double (value, options->offset_y);
       break;
 
+    case PROP_ALIGN_LAYERS:
+      g_value_set_boolean (value, options->priv->align_layers);
+      break;
+    case PROP_ALIGN_VECTORS:
+      g_value_set_boolean (value, options->priv->align_vectors);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -268,14 +349,49 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
   GObject          *config  = G_OBJECT (tool_options);
   GimpAlignOptions *options = GIMP_ALIGN_OPTIONS (tool_options);
   GtkWidget        *vbox    = gimp_tool_options_gui (tool_options);
+  GtkWidget        *widget;
   GtkWidget        *align_vbox;
   GtkWidget        *hbox;
   GtkWidget        *frame;
   GtkWidget        *label;
   GtkWidget        *spinbutton;
   GtkWidget        *combo;
+  gchar            *text;
   gint              n = 0;
 
+  /* Selected objects */
+  widget = gimp_prop_check_button_new (config, "align-layers", NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+
+  widget = gimp_prop_check_button_new (config, "align-vectors", NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  widget = gtk_image_new_from_icon_name (GIMP_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
+  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
+
+  /* TRANSLATORS: the %s strings are modifiers such as Shift, Alt or Cmd. */
+  text = g_strdup_printf (_("%s-pick guides to align or distribute (%s-%s for more)"),
+                          gimp_get_mod_string (GDK_MOD1_MASK),
+                          gimp_get_mod_string (gimp_get_extend_selection_mask ()),
+                          gimp_get_mod_string (GDK_MOD1_MASK));
+  widget = gtk_label_new (text);
+  gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+  gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
+  g_free (text);
+  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
+
+  widget = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
+  options->priv->selected_guides_label = widget;
+
+  /* Align frame */
   frame = gimp_frame_new (_("Align"));
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
   gtk_widget_show (frame);
@@ -288,20 +404,41 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
   gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Relative to"));
   g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
   gtk_box_pack_start (GTK_BOX (align_vbox), combo, FALSE, FALSE, 0);
+  options->priv->reference_combo = combo;
+
 
   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
   gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show (hbox);
+  options->priv->reference_box = hbox;
+
+  widget = gtk_image_new_from_icon_name (GIMP_ICON_CURSOR, GTK_ICON_SIZE_BUTTON);
+  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
+
+  widget = gtk_label_new (_("Select the reference object"));
+  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
 
-  options->button[n++] =
+  widget = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (align_vbox), widget, FALSE, FALSE, 0);
+  gtk_widget_show (widget);
+  options->priv->reference_label = widget;
+
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_LEFT, hbox,
                                    _("Align left edge of target"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_HCENTER, hbox,
                                    _("Align center of target"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_RIGHT, hbox,
                                    _("Align right edge of target"));
 
@@ -309,18 +446,19 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
   gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show (hbox);
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_TOP, hbox,
                                    _("Align top edge of target"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_VCENTER, hbox,
                                    _("Align middle of target"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ALIGN_BOTTOM, hbox,
                                    _("Align bottom of target"));
 
+  /* Distribute frame */
   frame = gimp_frame_new (_("Distribute"));
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
   gtk_widget_show (frame);
@@ -333,19 +471,19 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
   gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show (hbox);
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_LEFT, hbox,
                                    _("Distribute left edges of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_HCENTER, hbox,
                                    _("Distribute horizontal centers of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_RIGHT, hbox,
                                    _("Distribute right edges of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_HFILL, hbox,
                                    _("Distribute targets evenly in the horizontal"));
 
@@ -353,19 +491,19 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
   gtk_box_pack_start (GTK_BOX (align_vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show (hbox);
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_TOP, hbox,
                                    _("Distribute top edges of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_VCENTER, hbox,
                                    _("Distribute vertical centers of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_BOTTOM, hbox,
                                    _("Distribute bottoms of targets"));
 
-  options->button[n++] =
+  options->priv->button[n++] =
     gimp_align_options_button_new (options, GIMP_ARRANGE_VFILL, hbox,
                                    _("Distribute targets evenly in the vertical"));
 
@@ -393,5 +531,295 @@ gimp_align_options_gui (GimpToolOptions *tool_options)
                                           1, 20, 0);
   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
 
+  g_signal_connect (gimp_get_user_context (GIMP_CONTEXT (options)->gimp),
+                    "image-changed",
+                    G_CALLBACK (gimp_align_options_image_changed),
+                    tool_options);
+  gimp_align_options_image_changed (gimp_get_user_context (GIMP_CONTEXT (options)->gimp),
+                                    gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT 
(options)->gimp)),
+                                    options);
+
   return vbox;
 }
+
+GList *
+gimp_align_options_get_objects (GimpAlignOptions *options)
+{
+  GimpImage *image;
+  GList     *objects = NULL;
+
+  image = gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp));
+
+  if (image)
+    {
+      if (options->priv->align_layers)
+        {
+          GList *layers;
+
+          layers = gimp_image_get_selected_layers (image);
+          layers = g_list_copy (layers);
+          objects = g_list_concat (objects, layers);
+        }
+      if (options->priv->align_vectors)
+        {
+          GList *vectors;
+
+          vectors = gimp_image_get_selected_vectors (image);
+          vectors = g_list_copy (vectors);
+          objects = g_list_concat (objects, vectors);
+        }
+
+      if (options->priv->selected_guides)
+        {
+          GList *guides;
+
+          guides = g_list_copy (options->priv->selected_guides);
+          objects = g_list_concat (objects, guides);
+        }
+    }
+
+  return objects;
+}
+
+void
+gimp_align_options_pick_reference (GimpAlignOptions *options,
+                                   GObject          *object)
+{
+  if (options->priv->reference)
+    g_signal_handlers_disconnect_by_func (options->priv->reference,
+                                          G_CALLBACK (gimp_align_options_reference_removed),
+                                          options);
+
+  g_clear_object (&options->priv->reference);
+
+  if (object)
+    {
+      options->priv->reference = g_object_ref (object);
+
+      /* Both GimpItem and GimpGuide/GimpAuxItem have a "removed" signal with
+       * similar signature. */
+      g_signal_connect_object (options->priv->reference,
+                               "removed",
+                               G_CALLBACK (gimp_align_options_reference_removed),
+                               options, 0);
+    }
+
+  gimp_align_options_update_area (options);
+}
+
+GObject *
+gimp_align_options_get_reference (GimpAlignOptions *options,
+                                  gboolean          blink_if_none)
+{
+  GObject   *reference = NULL;
+  GimpImage *image;
+
+  image = gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp));
+
+  if (image)
+    {
+      switch (options->align_reference)
+        {
+        case GIMP_ALIGN_REFERENCE_IMAGE:
+          reference = G_OBJECT (image);
+          break;
+        case GIMP_ALIGN_REFERENCE_SELECTION:
+          reference = G_OBJECT (gimp_image_get_mask (image));
+          break;
+        case GIMP_ALIGN_REFERENCE_PICK:
+          reference = G_OBJECT (options->priv->reference);
+          break;
+        }
+
+      if (reference == NULL && blink_if_none)
+        {
+          if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+            gimp_widget_blink (options->priv->reference_box);
+          else
+            gimp_widget_blink (options->priv->reference_combo);
+        }
+    }
+
+  return reference;
+}
+
+void
+gimp_align_options_pick_guide (GimpAlignOptions *options,
+                               GimpGuide        *guide,
+                               gboolean          extend)
+{
+  if (! extend)
+    g_clear_pointer (&options->priv->selected_guides, g_list_free);
+
+  if (guide)
+    {
+      GList *list;
+
+      if ((list = g_list_find (options->priv->selected_guides, guide)))
+        options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
+      else
+        options->priv->selected_guides = g_list_prepend (options->priv->selected_guides, guide);
+    }
+
+  gimp_align_options_update_area (options);
+}
+
+
+/*  Private functions  */
+
+static void
+gimp_align_options_image_changed (GimpContext      *context,
+                                  GimpImage        *image,
+                                  GimpAlignOptions *options)
+{
+  GimpImage *prev_image;
+
+  prev_image = g_object_get_data (G_OBJECT (options), "gimp-align-options-image");
+
+  if (image != prev_image)
+    {
+      /* We cannot keep track of selected guides across image changes. */
+      g_clear_pointer (&options->priv->selected_guides, g_list_free);
+      gimp_align_options_pick_reference (options, NULL);
+
+      if (prev_image)
+        {
+          g_signal_handlers_disconnect_by_func (prev_image,
+                                                G_CALLBACK (gimp_align_options_update_area),
+                                                options);
+          g_signal_handlers_disconnect_by_func (prev_image,
+                                                G_CALLBACK (gimp_align_options_guide_removed),
+                                                options);
+        }
+      if (image)
+        {
+          g_signal_connect_object (image, "selected-channels-changed",
+                                   G_CALLBACK (gimp_align_options_update_area),
+                                   options, G_CONNECT_SWAPPED);
+          g_signal_connect_object (image, "selected-layers-changed",
+                                   G_CALLBACK (gimp_align_options_update_area),
+                                   options, G_CONNECT_SWAPPED);
+          g_signal_connect_object (image, "guide-removed",
+                                   G_CALLBACK (gimp_align_options_guide_removed),
+                                   options, 0);
+        }
+
+      g_object_set_data (G_OBJECT (options), "gimp-align-options-image", image);
+      gimp_align_options_update_area (options);
+    }
+}
+
+static void
+gimp_align_options_update_area (GimpAlignOptions *options)
+{
+  GimpImage *image;
+  GList     *layers  = NULL;
+  GList     *vectors = NULL;
+  gint       n_items = 0;
+  gchar     *text;
+
+  image = gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp));
+
+  /* GUI not created yet. */
+  if (! options->priv->reference_combo)
+    return;
+
+  if (image)
+    {
+      layers = gimp_image_get_selected_layers (image);
+      vectors = gimp_image_get_selected_vectors (image);
+
+      if (options->priv->align_layers)
+        n_items += g_list_length (layers);
+      if (options->priv->align_vectors)
+        n_items += g_list_length (vectors);
+
+      n_items += g_list_length (options->priv->selected_guides);
+    }
+
+  for (gint i = 0; i < ALIGN_OPTIONS_N_BUTTONS; i++)
+    {
+      if (options->priv->button[i])
+        gtk_widget_set_sensitive (options->priv->button[i], n_items > 0);
+    }
+
+  /* Update the guide picking widgets. */
+  if (options->priv->selected_guides)
+    {
+      gchar *tmp_txt;
+
+      tmp_txt = g_strdup_printf (ngettext ("1 guide will be aligned or distributed",
+                                           "%d guides will be aligned or distributed",
+                                           g_list_length (options->priv->selected_guides)),
+                                 g_list_length (options->priv->selected_guides));
+      text = g_strdup_printf ("<i>%s</i>", tmp_txt);
+      g_free (tmp_txt);
+      gtk_widget_show (options->priv->selected_guides_label);
+    }
+  else
+    {
+      text = NULL;
+      gtk_widget_hide (options->priv->selected_guides_label);
+    }
+
+  gtk_label_set_markup (GTK_LABEL (options->priv->selected_guides_label), text);
+  g_free (text);
+
+  /* Update the reference widgets. */
+  text = NULL;
+  if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+    {
+      if (options->priv->reference)
+        {
+          gchar *tmp_txt;
+
+          if (GIMP_IS_LAYER (options->priv->reference))
+            tmp_txt = g_strdup_printf (_("Reference layer: %s"),
+                                       gimp_object_get_name (options->priv->reference));
+          else if (GIMP_IS_CHANNEL (options->priv->reference))
+            tmp_txt = g_strdup_printf (_("Reference channel: %s"),
+                                       gimp_object_get_name (options->priv->reference));
+          else if (GIMP_IS_VECTORS (options->priv->reference))
+            tmp_txt = g_strdup_printf (_("Reference path: %s"),
+                                       gimp_object_get_name (options->priv->reference));
+          else if (GIMP_IS_GUIDE (options->priv->reference))
+            tmp_txt = g_strdup (_("Reference guide"));
+          else
+            g_return_if_reached ();
+
+          text = g_strdup_printf ("<i>%s</i>", tmp_txt);
+          g_free (tmp_txt);
+        }
+      gtk_widget_show (options->priv->reference_box);
+    }
+  else
+    {
+      gtk_widget_hide (options->priv->reference_box);
+    }
+  gtk_label_set_markup (GTK_LABEL (options->priv->reference_label), text);
+  g_free (text);
+}
+
+static void
+gimp_align_options_guide_removed (GimpImage        *image,
+                                  GimpGuide        *guide,
+                                  GimpAlignOptions *options)
+{
+  GList *list;
+
+  if ((list = g_list_find (options->priv->selected_guides, guide)))
+    options->priv->selected_guides = g_list_delete_link (options->priv->selected_guides, list);
+
+  if (G_OBJECT (guide) == options->priv->reference)
+    gimp_align_options_pick_reference (options, NULL);
+
+  gimp_align_options_update_area (options);
+}
+
+static void
+gimp_align_options_reference_removed (GObject          *object,
+                                      GimpAlignOptions *options)
+{
+  if (G_OBJECT (object) == options->priv->reference)
+    gimp_align_options_pick_reference (options, NULL);
+}
diff --git a/app/tools/gimpalignoptions.h b/app/tools/gimpalignoptions.h
index 5d4fe047ed..45cac97ed0 100644
--- a/app/tools/gimpalignoptions.h
+++ b/app/tools/gimpalignoptions.h
@@ -33,18 +33,19 @@
 #define GIMP_ALIGN_OPTIONS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ALIGN_OPTIONS, 
GimpAlignOptionsClass))
 
 
-typedef struct _GimpAlignOptions      GimpAlignOptions;
-typedef struct _GimpAlignOptionsClass GimpAlignOptionsClass;
+typedef struct _GimpAlignOptions        GimpAlignOptions;
+typedef struct _GimpAlignOptionsPrivate GimpAlignOptionsPrivate;
+typedef struct _GimpAlignOptionsClass   GimpAlignOptionsClass;
 
 struct _GimpAlignOptions
 {
-  GimpToolOptions         parent_instance;
+  GimpToolOptions          parent_instance;
 
-  GimpAlignReferenceType  align_reference;
-  gdouble                 offset_x;
-  gdouble                 offset_y;
+  GimpAlignReferenceType   align_reference;
+  gdouble                  offset_x;
+  gdouble                  offset_y;
 
-  GtkWidget              *button[ALIGN_OPTIONS_N_BUTTONS];
+  GimpAlignOptionsPrivate *priv;
 };
 
 struct _GimpAlignOptionsClass
@@ -56,9 +57,20 @@ struct _GimpAlignOptionsClass
 };
 
 
-GType       gimp_align_options_get_type (void) G_GNUC_CONST;
+GType       gimp_align_options_get_type          (void) G_GNUC_CONST;
 
-GtkWidget * gimp_align_options_gui      (GimpToolOptions *tool_options);
+GtkWidget * gimp_align_options_gui               (GimpToolOptions  *tool_options);
+
+GList     * gimp_align_options_get_objects       (GimpAlignOptions *options);
+
+void        gimp_align_options_pick_reference    (GimpAlignOptions *options,
+                                                  GObject          *object);
+GObject   * gimp_align_options_get_reference     (GimpAlignOptions *options,
+                                                  gboolean          blink_if_none);
+
+void        gimp_align_options_pick_guide        (GimpAlignOptions *options,
+                                                  GimpGuide        *guide,
+                                                  gboolean          extend);
 
 
 #endif /* __GIMP_ALIGN_OPTIONS_H__ */
diff --git a/app/tools/gimpaligntool.c b/app/tools/gimpaligntool.c
index 469899321c..7fcfaf0b76 100644
--- a/app/tools/gimpaligntool.c
+++ b/app/tools/gimpaligntool.c
@@ -101,10 +101,6 @@ static void     gimp_align_tool_draw           (GimpDrawTool          *draw_tool
 static void     gimp_align_tool_align          (GimpAlignTool         *align_tool,
                                                 GimpAlignmentType      align_type);
 
-static void     gimp_align_tool_object_removed (GObject               *object,
-                                                GimpAlignTool         *align_tool);
-static void     gimp_align_tool_clear_selected (GimpAlignTool         *align_tool);
-
 
 G_DEFINE_TYPE (GimpAlignTool, gimp_align_tool, GIMP_TYPE_DRAW_TOOL)
 
@@ -158,7 +154,7 @@ gimp_align_tool_init (GimpAlignTool *align_tool)
                                      GIMP_CURSOR_PRECISION_PIXEL_BORDER);
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_MOVE);
 
-  align_tool->function = ALIGN_TOOL_IDLE;
+  align_tool->function = ALIGN_TOOL_REF_IDLE;
 }
 
 static void
@@ -181,8 +177,6 @@ gimp_align_tool_control (GimpTool       *tool,
                          GimpToolAction  action,
                          GimpDisplay    *display)
 {
-  GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (tool);
-
   switch (action)
     {
     case GIMP_TOOL_ACTION_PAUSE:
@@ -190,7 +184,6 @@ gimp_align_tool_control (GimpTool       *tool,
       break;
 
     case GIMP_TOOL_ACTION_HALT:
-      gimp_align_tool_clear_selected (align_tool);
       break;
 
     case GIMP_TOOL_ACTION_COMMIT:
@@ -246,10 +239,8 @@ gimp_align_tool_button_release (GimpTool              *tool,
   GimpAlignTool    *align_tool = GIMP_ALIGN_TOOL (tool);
   GimpAlignOptions *options    = GIMP_ALIGN_TOOL_GET_OPTIONS (tool);
   GimpDisplayShell *shell      = gimp_display_get_shell (display);
-  GObject          *object     = NULL;
   GimpImage        *image      = gimp_display_get_image (display);
   GdkModifierType   extend_mask;
-  gint              i;
 
   extend_mask = gimp_get_extend_selection_mask ();
 
@@ -266,108 +257,99 @@ gimp_align_tool_button_release (GimpTool              *tool,
       return;
     }
 
-  if (! (state & extend_mask)) /* start a new list */
+  if (state & GDK_MOD1_MASK)
     {
-      gimp_align_tool_clear_selected (align_tool);
-      align_tool->set_reference = FALSE;
-    }
+      GimpGuide *guide = NULL;
 
-  /* if mouse has moved less than EPSILON pixels since button press,
-   * select the nearest thing, otherwise make a rubber-band rectangle
-   */
-  if (hypot (coords->x - align_tool->x1,
-             coords->y - align_tool->y1) < EPSILON)
-    {
-      GimpVectors *vectors;
-      GimpGuide   *guide;
-      GimpLayer   *layer;
-      gint         snap_distance = display->config->snap_distance;
-
-      if ((vectors = gimp_image_pick_vectors (image,
-                                              coords->x, coords->y,
-                                              FUNSCALEX (shell, snap_distance),
-                                              FUNSCALEY (shell, snap_distance))))
-        {
-          object = G_OBJECT (vectors);
-        }
-      else if (gimp_display_shell_get_show_guides (shell) &&
-               (guide = gimp_image_pick_guide (image,
-                                               coords->x, coords->y,
-                                               FUNSCALEX (shell, snap_distance),
-                                               FUNSCALEY (shell, snap_distance))))
+      if (gimp_display_shell_get_show_guides (shell))
         {
-          object = G_OBJECT (guide);
-        }
-      else if ((layer = gimp_image_pick_layer_by_bounds (image,
-                                                         coords->x, coords->y)))
-        {
-          object = G_OBJECT (layer);
-        }
+          gint snap_distance = display->config->snap_distance;
 
-      if (object)
-        {
-          if (! g_list_find (align_tool->selected_objects, object))
-            {
-              align_tool->selected_objects =
-                g_list_append (align_tool->selected_objects, object);
-
-              g_signal_connect (object, "removed",
-                                G_CALLBACK (gimp_align_tool_object_removed),
-                                align_tool);
-
-              /* if an object has been selected using unmodified click,
-               * it should be used as the reference
-               */
-              if (! (state & extend_mask))
-                align_tool->set_reference = TRUE;
-            }
+          guide = gimp_image_pick_guide (image,
+                                          coords->x, coords->y,
+                                          FUNSCALEX (shell, snap_distance),
+                                          FUNSCALEY (shell, snap_distance));
         }
+
+      gimp_align_options_pick_guide (options, guide, (gboolean) state & extend_mask);
     }
-  else  /* FIXME: look for vectors too */
+  else
     {
-      gint   X0 = MIN (coords->x, align_tool->x1);
-      gint   X1 = MAX (coords->x, align_tool->x1);
-      gint   Y0 = MIN (coords->y, align_tool->y1);
-      gint   Y1 = MAX (coords->y, align_tool->y1);
-      GList *all_layers;
-      GList *list;
-
-      all_layers = gimp_image_get_layer_list (image);
-
-      for (list = all_layers; list; list = g_list_next (list))
+      GObject *object = NULL;
+
+      /* Check if a layer is fully included in the rubber-band rectangle.
+       * Don't verify for too small rectangles.
+       */
+      /* FIXME: look for vectors too */
+      if (hypot (coords->x - align_tool->x1,
+                 coords->y - align_tool->y1) > EPSILON)
         {
-          GimpLayer *layer = list->data;
-          gint       x0, y0, x1, y1;
+          gint   X0 = MIN (coords->x, align_tool->x1);
+          gint   X1 = MAX (coords->x, align_tool->x1);
+          gint   Y0 = MIN (coords->y, align_tool->y1);
+          gint   Y1 = MAX (coords->y, align_tool->y1);
+          GList *all_layers;
+          GList *list;
 
-          if (! gimp_item_get_visible (GIMP_ITEM (layer)))
-            continue;
+          all_layers = gimp_image_get_layer_list (image);
 
-          gimp_item_get_offset (GIMP_ITEM (layer), &x0, &y0);
-          x1 = x0 + gimp_item_get_width  (GIMP_ITEM (layer));
-          y1 = y0 + gimp_item_get_height (GIMP_ITEM (layer));
+          for (list = all_layers; list; list = g_list_next (list))
+            {
+              GimpLayer *layer = list->data;
+              gint       x0, y0, x1, y1;
+
+              if (! gimp_item_get_visible (GIMP_ITEM (layer)))
+                continue;
 
-          if (x0 < X0 || y0 < Y0 || x1 > X1 || y1 > Y1)
-            continue;
+              gimp_item_get_offset (GIMP_ITEM (layer), &x0, &y0);
+              x1 = x0 + gimp_item_get_width  (GIMP_ITEM (layer));
+              y1 = y0 + gimp_item_get_height (GIMP_ITEM (layer));
 
-          if (g_list_find (align_tool->selected_objects, layer))
-            continue;
+              if (x0 < X0 || y0 < Y0 || x1 > X1 || y1 > Y1)
+                continue;
 
-          align_tool->selected_objects =
-            g_list_append (align_tool->selected_objects, layer);
+              object = G_OBJECT (layer);
+              break;
+            }
 
-          g_signal_connect (layer, "removed",
-                            G_CALLBACK (gimp_align_tool_object_removed),
-                            align_tool);
+          g_list_free (all_layers);
         }
 
-      g_list_free (all_layers);
-    }
+      if (object == NULL)
+        {
+          GimpVectors *vectors;
+          GimpGuide   *guide;
+          GimpLayer   *layer;
+          GObject     *previously_picked;
+          gint         snap_distance = display->config->snap_distance;
 
-  for (i = 0; i < ALIGN_OPTIONS_N_BUTTONS; i++)
-    {
-      if (options->button[i])
-        gtk_widget_set_sensitive (options->button[i],
-                                  align_tool->selected_objects != NULL);
+          previously_picked = gimp_align_options_get_reference (options, FALSE);
+
+
+          if ((vectors = gimp_image_pick_vectors (image,
+                                                  coords->x, coords->y,
+                                                  FUNSCALEX (shell, snap_distance),
+                                                  FUNSCALEY (shell, snap_distance))))
+            {
+              object = G_OBJECT (vectors);
+            }
+          else if (gimp_display_shell_get_show_guides (shell) &&
+                   (guide = gimp_image_pick_guide (image,
+                                                   coords->x, coords->y,
+                                                   FUNSCALEX (shell, snap_distance),
+                                                   FUNSCALEY (shell, snap_distance))))
+            {
+              object = G_OBJECT (guide);
+            }
+          else if ((layer = gimp_image_pick_layer (image, coords->x, coords->y,
+                                                   previously_picked && GIMP_IS_LAYER (previously_picked)? 
GIMP_LAYER (previously_picked) : NULL)))
+            {
+              object = G_OBJECT (layer);
+            }
+        }
+
+      if (object)
+        gimp_align_options_pick_reference (options, object);
     }
 
   align_tool->x2 = align_tool->x1;
@@ -422,23 +404,22 @@ gimp_align_tool_oper_update (GimpTool         *tool,
                              GimpDisplay      *display)
 {
   GimpAlignTool    *align_tool    = GIMP_ALIGN_TOOL (tool);
+  GimpAlignOptions *options       = GIMP_ALIGN_TOOL_GET_OPTIONS (align_tool);
   GimpDisplayShell *shell         = gimp_display_get_shell (display);
   GimpImage        *image         = gimp_display_get_image (display);
   gint              snap_distance = display->config->snap_distance;
-  gboolean          add;
 
-  add = ((state & gimp_get_extend_selection_mask ()) &&
-         align_tool->selected_objects);
+  state &= gimp_get_all_modifiers_mask ();
+
+  align_tool->function = ALIGN_TOOL_NO_ACTION;
 
   if (gimp_image_pick_vectors (image,
                                coords->x, coords->y,
                                FUNSCALEX (shell, snap_distance),
                                FUNSCALEY (shell, snap_distance)))
     {
-      if (add)
-        align_tool->function = ALIGN_TOOL_ADD_PATH;
-      else
-        align_tool->function = ALIGN_TOOL_PICK_PATH;
+      if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+        align_tool->function = ALIGN_TOOL_REF_PICK_PATH;
     }
   else if (gimp_display_shell_get_show_guides (shell) &&
            gimp_image_pick_guide (image,
@@ -446,21 +427,24 @@ gimp_align_tool_oper_update (GimpTool         *tool,
                                   FUNSCALEX (shell, snap_distance),
                                   FUNSCALEY (shell, snap_distance)))
     {
-      if (add)
-        align_tool->function = ALIGN_TOOL_ADD_GUIDE;
-      else
-        align_tool->function = ALIGN_TOOL_PICK_GUIDE;
+      if (state == (gimp_get_extend_selection_mask () | GDK_MOD1_MASK))
+        align_tool->function = ALIGN_TOOL_ALIGN_ADD_GUIDE;
+      else if (state == GDK_MOD1_MASK)
+        align_tool->function = ALIGN_TOOL_ALIGN_PICK_GUIDE;
+      else if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+        align_tool->function = ALIGN_TOOL_REF_PICK_GUIDE;
     }
   else if (gimp_image_pick_layer_by_bounds (image, coords->x, coords->y))
     {
-      if (add)
-        align_tool->function = ALIGN_TOOL_ADD_LAYER;
-      else
-        align_tool->function = ALIGN_TOOL_PICK_LAYER;
+      if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+        align_tool->function = ALIGN_TOOL_REF_PICK_LAYER;
     }
   else
     {
-      align_tool->function = ALIGN_TOOL_IDLE;
+      if (state & GDK_MOD1_MASK)
+        align_tool->function = ALIGN_TOOL_ALIGN_IDLE;
+      else if (options->align_reference == GIMP_ALIGN_REFERENCE_PICK)
+        align_tool->function = ALIGN_TOOL_REF_IDLE;
     }
 
   gimp_align_tool_status_update (tool, display, state, proximity);
@@ -476,32 +460,30 @@ gimp_align_tool_cursor_update (GimpTool         *tool,
   GimpToolCursorType  tool_cursor = GIMP_TOOL_CURSOR_NONE;
   GimpCursorModifier  modifier    = GIMP_CURSOR_MODIFIER_NONE;
 
-  /* always add '+' when Shift is pressed, even if nothing is selected */
-  if (state & gimp_get_extend_selection_mask ())
-    modifier = GIMP_CURSOR_MODIFIER_PLUS;
-
   switch (align_tool->function)
     {
-    case ALIGN_TOOL_IDLE:
+    case ALIGN_TOOL_REF_IDLE:
+    case ALIGN_TOOL_ALIGN_IDLE:
       tool_cursor = GIMP_TOOL_CURSOR_RECT_SELECT;
       break;
 
-    case ALIGN_TOOL_PICK_LAYER:
-    case ALIGN_TOOL_ADD_LAYER:
+    case ALIGN_TOOL_REF_PICK_LAYER:
       tool_cursor = GIMP_TOOL_CURSOR_HAND;
       break;
 
-    case ALIGN_TOOL_PICK_GUIDE:
-    case ALIGN_TOOL_ADD_GUIDE:
+    case ALIGN_TOOL_ALIGN_ADD_GUIDE:
+      modifier = GIMP_CURSOR_MODIFIER_PLUS;
+    case ALIGN_TOOL_REF_PICK_GUIDE:
+    case ALIGN_TOOL_ALIGN_PICK_GUIDE:
       tool_cursor = GIMP_TOOL_CURSOR_MOVE;
       break;
 
-    case ALIGN_TOOL_PICK_PATH:
-    case ALIGN_TOOL_ADD_PATH:
+    case ALIGN_TOOL_REF_PICK_PATH:
       tool_cursor = GIMP_TOOL_CURSOR_PATHS;
       break;
 
-    case ALIGN_TOOL_DRAG_BOX:
+    case ALIGN_TOOL_REF_DRAG_BOX:
+    case ALIGN_TOOL_NO_ACTION:
       break;
     }
 
@@ -518,8 +500,9 @@ gimp_align_tool_status_update (GimpTool        *tool,
                                GdkModifierType  state,
                                gboolean         proximity)
 {
-  GimpAlignTool   *align_tool = GIMP_ALIGN_TOOL (tool);
-  GdkModifierType  extend_mask;
+  GimpAlignTool    *align_tool = GIMP_ALIGN_TOOL (tool);
+  gchar            *status     = NULL;
+  GdkModifierType   extend_mask;
 
   extend_mask = gimp_get_extend_selection_mask ();
 
@@ -527,75 +510,59 @@ gimp_align_tool_status_update (GimpTool        *tool,
 
   if (proximity)
     {
-      gchar *status = NULL;
-
-      if (! align_tool->selected_objects)
-        {
-          /* no need to suggest Shift if nothing is selected */
-          state |= extend_mask;
-        }
-
       switch (align_tool->function)
         {
-        case ALIGN_TOOL_IDLE:
-          status = gimp_suggest_modifiers (_("Click on a layer, path or guide, "
-                                             "or Click-Drag to pick several "
-                                             "layers"),
-                                           extend_mask & ~state,
-                                           NULL, NULL, NULL);
+        case ALIGN_TOOL_REF_IDLE:
+          status = g_strdup (_("Click on a layer, path or guide, "
+                               "or Click-Drag to pick a reference"));
           break;
-
-        case ALIGN_TOOL_PICK_LAYER:
-          status = gimp_suggest_modifiers (_("Click to pick this layer as "
-                                             "first item"),
-                                           extend_mask & ~state,
+        case ALIGN_TOOL_REF_PICK_LAYER:
+          status = g_strdup (_("Click to pick this layer as reference"));
+          break;
+        case ALIGN_TOOL_REF_PICK_GUIDE:
+          status = gimp_suggest_modifiers (_("Click to pick this guide as reference"),
+                                           GDK_MOD1_MASK & ~state,
                                            NULL, NULL, NULL);
           break;
-
-        case ALIGN_TOOL_ADD_LAYER:
-          status = g_strdup (_("Click to add this layer to the list"));
+        case ALIGN_TOOL_REF_PICK_PATH:
+          status = g_strdup (_("Click to pick this path as reference"));
           break;
 
-        case ALIGN_TOOL_PICK_GUIDE:
-          status = gimp_suggest_modifiers (_("Click to pick this guide as "
-                                             "first item"),
-                                           extend_mask & ~state,
-                                           NULL, NULL, NULL);
+        case ALIGN_TOOL_REF_DRAG_BOX:
           break;
 
-        case ALIGN_TOOL_ADD_GUIDE:
-          status = g_strdup (_("Click to add this guide to the list"));
+        case ALIGN_TOOL_ALIGN_IDLE:
+          status = g_strdup (_("Click on a guide to add it to objects to align, "
+                               "click anywhere else to unselect all guides"));
           break;
-
-        case ALIGN_TOOL_PICK_PATH:
-          status = gimp_suggest_modifiers (_("Click to pick this path as "
-                                             "first item"),
+        case ALIGN_TOOL_ALIGN_PICK_GUIDE:
+          status = gimp_suggest_modifiers (_("Click to select this guide for alignment"),
                                            extend_mask & ~state,
                                            NULL, NULL, NULL);
           break;
-
-        case ALIGN_TOOL_ADD_PATH:
-          status = g_strdup (_("Click to add this path to the list"));
+        case ALIGN_TOOL_ALIGN_ADD_GUIDE:
+          status = g_strdup (_("Click to add this guide to the list of objects to align"));
           break;
 
-        case ALIGN_TOOL_DRAG_BOX:
+        case ALIGN_TOOL_NO_ACTION:
           break;
         }
+    }
 
-      if (status)
-        {
-          gimp_tool_push_status (tool, display, "%s", status);
-          g_free (status);
-        }
+  if (status)
+    {
+      gimp_tool_push_status (tool, display, "%s", status);
+      g_free (status);
     }
 }
 
 static void
 gimp_align_tool_draw (GimpDrawTool *draw_tool)
 {
-  GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (draw_tool);
-  GList         *list;
-  gint           x, y, w, h;
+  GimpAlignTool    *align_tool = GIMP_ALIGN_TOOL (draw_tool);
+  GimpAlignOptions *options = GIMP_ALIGN_TOOL_GET_OPTIONS (align_tool);
+  GObject          *reference;
+  gint              x, y, w, h;
 
   /* draw rubber-band rectangle */
   x = MIN (align_tool->x2, align_tool->x1);
@@ -603,86 +570,84 @@ gimp_align_tool_draw (GimpDrawTool *draw_tool)
   w = MAX (align_tool->x2, align_tool->x1) - x;
   h = MAX (align_tool->y2, align_tool->y1) - y;
 
-  gimp_draw_tool_add_rectangle (draw_tool, FALSE, x, y, w, h);
+  if (w != 0 && h != 0)
+    gimp_draw_tool_add_rectangle (draw_tool, FALSE, x, y, w, h);
 
-  for (list = align_tool->selected_objects;
-       list;
-       list = g_list_next (list))
+  /* Draw handles on the reference object. */
+  reference = gimp_align_options_get_reference (options, FALSE);
+  if (GIMP_IS_ITEM (reference))
     {
-      if (GIMP_IS_ITEM (list->data))
-        {
-          GimpItem *item = list->data;
-          gint      off_x, off_y;
-
-          gimp_item_bounds (item, &x, &y, &w, &h);
-
-          gimp_item_get_offset (item, &off_x, &off_y);
-          x += off_x;
-          y += off_y;
+      GimpItem *item = GIMP_ITEM (reference);
+      gint      off_x, off_y;
+
+      gimp_item_bounds (item, &x, &y, &w, &h);
+
+      gimp_item_get_offset (item, &off_x, &off_y);
+      x += off_x;
+      y += off_y;
+
+      gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
+                                 x, y,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_HANDLE_ANCHOR_NORTH_WEST);
+      gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
+                                 x + w, y,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_HANDLE_ANCHOR_NORTH_EAST);
+      gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
+                                 x, y + h,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_HANDLE_ANCHOR_SOUTH_WEST);
+      gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
+                                 x + w, y + h,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_TOOL_HANDLE_SIZE_SMALL,
+                                 GIMP_HANDLE_ANCHOR_SOUTH_EAST);
+    }
+  else if (GIMP_IS_GUIDE (reference))
+    {
+      GimpGuide *guide = GIMP_GUIDE (reference);
+      GimpImage *image = gimp_display_get_image (GIMP_TOOL (draw_tool)->display);
+      gint       x, y;
+      gint       w, h;
 
+      switch (gimp_guide_get_orientation (guide))
+        {
+        case GIMP_ORIENTATION_VERTICAL:
+          x = gimp_guide_get_position (guide);
+          h = gimp_image_get_height (image);
           gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                     x, y,
+                                     x, h,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                     GIMP_HANDLE_ANCHOR_NORTH_WEST);
+                                     GIMP_HANDLE_ANCHOR_SOUTH);
           gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                     x + w, y,
+                                     x, 0,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                     GIMP_HANDLE_ANCHOR_NORTH_EAST);
+                                     GIMP_HANDLE_ANCHOR_NORTH);
+          break;
+
+        case GIMP_ORIENTATION_HORIZONTAL:
+          y = gimp_guide_get_position (guide);
+          w = gimp_image_get_width (image);
           gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                     x, y + h,
+                                     w, y,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                     GIMP_HANDLE_ANCHOR_SOUTH_WEST);
+                                     GIMP_HANDLE_ANCHOR_EAST);
           gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                     x + w, y + h,
+                                     0, y,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
                                      GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                     GIMP_HANDLE_ANCHOR_SOUTH_EAST);
-        }
-      else if (GIMP_IS_GUIDE (list->data))
-        {
-          GimpGuide *guide = list->data;
-          GimpImage *image = gimp_display_get_image (GIMP_TOOL (draw_tool)->display);
-          gint       x, y;
-          gint       w, h;
-
-          switch (gimp_guide_get_orientation (guide))
-            {
-            case GIMP_ORIENTATION_VERTICAL:
-              x = gimp_guide_get_position (guide);
-              h = gimp_image_get_height (image);
-              gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                         x, h,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_HANDLE_ANCHOR_SOUTH);
-              gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                         x, 0,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_HANDLE_ANCHOR_NORTH);
-              break;
-
-            case GIMP_ORIENTATION_HORIZONTAL:
-              y = gimp_guide_get_position (guide);
-              w = gimp_image_get_width (image);
-              gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                         w, y,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_HANDLE_ANCHOR_EAST);
-              gimp_draw_tool_add_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
-                                         0, y,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_TOOL_HANDLE_SIZE_SMALL,
-                                         GIMP_HANDLE_ANCHOR_WEST);
-              break;
+                                     GIMP_HANDLE_ANCHOR_WEST);
+          break;
 
-            default:
-              break;
-            }
+        default:
+          break;
         }
     }
 }
@@ -694,14 +659,16 @@ gimp_align_tool_align (GimpAlignTool     *align_tool,
   GimpAlignOptions *options = GIMP_ALIGN_TOOL_GET_OPTIONS (align_tool);
   GimpImage        *image;
   GObject          *reference_object = NULL;
+  GList            *objects;
   GList            *list;
   gint              offset = 0;
 
   /* if nothing is selected, just return */
-  if (! align_tool->selected_objects)
+  objects = gimp_align_options_get_objects (options);
+  if (! objects)
     return;
 
-  image  = gimp_display_get_image (GIMP_TOOL (align_tool)->display);
+  image = gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp));
 
   switch (align_type)
     {
@@ -734,50 +701,9 @@ gimp_align_tool_align (GimpAlignTool     *align_tool,
    * "set_reference" is TRUE, otherwise use NULL.
    */
 
-  list = align_tool->selected_objects;
-
-  switch (options->align_reference)
-    {
-    case GIMP_ALIGN_REFERENCE_IMAGE:
-      reference_object = G_OBJECT (image);
-      break;
-
-    case GIMP_ALIGN_REFERENCE_FIRST:
-      if (g_list_length (list) == 1)
-        {
-          reference_object = G_OBJECT (image);
-        }
-      else
-        {
-          if (align_tool->set_reference)
-            {
-              reference_object = G_OBJECT (list->data);
-              list = g_list_next (list);
-            }
-          else
-            {
-              reference_object = NULL;
-            }
-        }
-      break;
-
-    case GIMP_ALIGN_REFERENCE_SELECTION:
-      reference_object = G_OBJECT (gimp_image_get_mask (image));
-      break;
-
-    case GIMP_ALIGN_REFERENCE_ACTIVE_LAYER:
-      reference_object = G_OBJECT (gimp_image_get_active_layer (image));
-      break;
-
-    case GIMP_ALIGN_REFERENCE_ACTIVE_CHANNEL:
-      reference_object = G_OBJECT (gimp_image_get_active_channel (image));
-      break;
-
-    case GIMP_ALIGN_REFERENCE_ACTIVE_PATH:
-      reference_object = G_OBJECT (gimp_image_get_active_vectors (image));
-      break;
-    }
+  list = objects;
 
+  reference_object = gimp_align_options_get_reference (options, TRUE);
   if (! reference_object)
     return;
 
@@ -792,33 +718,5 @@ gimp_align_tool_align (GimpAlignTool     *align_tool,
   gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool));
 
   gimp_image_flush (image);
-}
-
-static void
-gimp_align_tool_object_removed (GObject       *object,
-                                GimpAlignTool *align_tool)
-{
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (align_tool));
-
-  if (align_tool->selected_objects)
-    g_signal_handlers_disconnect_by_func (object,
-                                          gimp_align_tool_object_removed,
-                                          align_tool);
-
-  align_tool->selected_objects = g_list_remove (align_tool->selected_objects,
-                                                object);
-
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool));
-}
-
-static void
-gimp_align_tool_clear_selected (GimpAlignTool *align_tool)
-{
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (align_tool));
-
-  while (align_tool->selected_objects)
-    gimp_align_tool_object_removed (align_tool->selected_objects->data,
-                                    align_tool);
-
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (align_tool));
+  g_list_free (objects);
 }
diff --git a/app/tools/gimpaligntool.h b/app/tools/gimpaligntool.h
index e84a9cbdf8..2bf666f2e9 100644
--- a/app/tools/gimpaligntool.h
+++ b/app/tools/gimpaligntool.h
@@ -25,14 +25,17 @@
 /*  tool function/operation/state/mode  */
 typedef enum
 {
-  ALIGN_TOOL_IDLE,
-  ALIGN_TOOL_PICK_LAYER,
-  ALIGN_TOOL_ADD_LAYER,
-  ALIGN_TOOL_PICK_GUIDE,
-  ALIGN_TOOL_ADD_GUIDE,
-  ALIGN_TOOL_PICK_PATH,
-  ALIGN_TOOL_ADD_PATH,
-  ALIGN_TOOL_DRAG_BOX
+  ALIGN_TOOL_NO_ACTION,
+
+  ALIGN_TOOL_REF_IDLE,
+  ALIGN_TOOL_REF_PICK_LAYER,
+  ALIGN_TOOL_REF_PICK_GUIDE,
+  ALIGN_TOOL_REF_PICK_PATH,
+  ALIGN_TOOL_REF_DRAG_BOX,
+
+  ALIGN_TOOL_ALIGN_IDLE,
+  ALIGN_TOOL_ALIGN_PICK_GUIDE,
+  ALIGN_TOOL_ALIGN_ADD_GUIDE,
 } GimpAlignToolFunction;
 
 


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