Index: app/core/core-enums.h
===================================================================
RCS file: /cvs/gnome/gimp/app/core/core-enums.h,v
retrieving revision 1.115
diff -u -3 -r1.115 core-enums.h
--- app/core/core-enums.h	9 Jun 2006 21:52:18 -0000	1.115
+++ app/core/core-enums.h	28 Jun 2006 04:06:20 -0000
@@ -232,6 +232,7 @@
 {
   GIMP_ORIENTATION_HORIZONTAL, /*< desc="Horizontal" >*/
   GIMP_ORIENTATION_VERTICAL,   /*< desc="Vertical"   >*/
+  GIMP_ORIENTATION_FREE,       /*< desc="Free"   >*/
   GIMP_ORIENTATION_UNKNOWN     /*< desc="Unknown"    >*/
 } GimpOrientationType;
 
Index: app/core/gimpguide.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpguide.c,v
retrieving revision 1.8
diff -u -3 -r1.8 gimpguide.c
--- app/core/gimpguide.c	7 Jun 2006 21:29:53 -0000	1.8
+++ app/core/gimpguide.c	28 Jun 2006 04:06:20 -0000
@@ -31,6 +31,8 @@
 #include "gimpguide.h"
 #include "gimpmarshal.h"
 
+#include "gimp-intl.h"
+
 enum
 {
   REMOVED,
@@ -42,7 +44,8 @@
   PROP_0,
   PROP_ID,
   PROP_ORIENTATION,
-  PROP_POSITION
+  PROP_POSITION,
+  PROP_ANGLE
 };
 
 
@@ -92,10 +95,20 @@
                                  GIMP_TYPE_ORIENTATION_TYPE,
                                  GIMP_ORIENTATION_UNKNOWN,
                                  0);
+
+
+
   GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_POSITION,
                                 "position", NULL,
                                 -1, GIMP_MAX_IMAGE_SIZE, -1,
                                 0);
+
+  GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_ANGLE,
+                                "angle",
+                                N_("Horizontal inclination angle for the guide."),
+                                - G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+                                GIMP_PARAM_STATIC_STRINGS);
+
 }
 
 static void
@@ -122,6 +135,9 @@
     case PROP_POSITION:
       g_value_set_int (value, guide->position);
       break;
+    case PROP_ANGLE:
+      g_value_set_double (value, guide->angle);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -147,6 +163,9 @@
     case PROP_POSITION:
       guide->position = g_value_get_int (value);
       break;
+    case PROP_ANGLE:
+      guide->angle = g_value_get_double (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -215,4 +234,22 @@
   g_return_if_fail (GIMP_IS_GUIDE (guide));
 
   g_signal_emit (guide, gimp_guide_signals[REMOVED], 0);
+}
+
+gdouble
+gimp_guide_get_angle (GimpGuide *guide)
+{
+  g_return_val_if_fail (GIMP_IS_GUIDE (guide), 0.0);
+  return guide->angle;
+}
+
+void 
+gimp_guide_set_angle (GimpGuide *guide,
+                      gdouble angle)
+{
+  g_return_if_fail (GIMP_IS_GUIDE (guide));
+
+  guide->angle = angle;
+
+  g_object_notify (G_OBJECT (guide), "angle");
 }
Index: app/core/gimpguide.h
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpguide.h,v
retrieving revision 1.5
diff -u -3 -r1.5 gimpguide.h
--- app/core/gimpguide.h	7 Jun 2006 20:13:51 -0000	1.5
+++ app/core/gimpguide.h	28 Jun 2006 04:06:20 -0000
@@ -43,6 +43,7 @@
   guint32              guide_ID;
   GimpOrientationType  orientation;
   gint                 position;
+  gdouble              angle;
 };
 
 struct _GimpGuideClass
@@ -68,6 +69,9 @@
 gint                gimp_guide_get_position    (GimpGuide           *guide);
 void                gimp_guide_set_position    (GimpGuide           *guide,
                                                 gint                 position);
+gdouble             gimp_guide_get_angle       (GimpGuide *guide);
+void                gimp_guide_set_angle       (GimpGuide *guide,
+                                                gdouble angle);
 void                gimp_guide_removed         (GimpGuide           *guide);
 
 #endif /* __GIMP_GUIDE_H__ */
Index: app/core/gimpimage-guides.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-guides.c,v
retrieving revision 1.224
diff -u -3 -r1.224 gimpimage-guides.c
--- app/core/gimpimage-guides.c	7 Jun 2006 20:13:51 -0000	1.224
+++ app/core/gimpimage-guides.c	28 Jun 2006 04:06:20 -0000
@@ -77,20 +77,54 @@
   return guide;
 }
 
+
+GimpGuide *
+gimp_image_add_free_guide (GimpImage *image,
+                           gint       position,
+                           gfloat     angle,
+                           gboolean   push_undo)
+{
+  GimpGuide *guide;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  /* Position refers to the intersection of the guide with the Y axis at x=0.
+   It can be < 0 or greater than the image height.
+  */
+
+  guide = gimp_guide_new (GIMP_ORIENTATION_FREE,
+                          image->gimp->next_guide_ID++);
+
+  if (push_undo)
+    gimp_image_undo_push_image_guide (image, _("Add Free Guide"),
+                                      guide);
+
+  gimp_image_add_guide (image, guide, position);
+  gimp_guide_set_angle (guide, angle);
+  g_object_unref (G_OBJECT (guide));
+
+  return guide;
+}
+
 void
 gimp_image_add_guide (GimpImage *image,
                       GimpGuide *guide,
                       gint       position)
+
 {
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (GIMP_IS_GUIDE (guide));
-  g_return_if_fail (position >= 0);
 
-  if (gimp_guide_get_orientation (guide) == GIMP_ORIENTATION_HORIZONTAL)
+  g_return_if_fail (gimp_guide_get_orientation (guide) !=
+                    GIMP_ORIENTATION_UNKNOWN);
+  if (gimp_guide_get_orientation(guide) != GIMP_ORIENTATION_FREE)
+    g_return_if_fail (position >= 0);
+  if (gimp_guide_get_orientation(guide) == GIMP_ORIENTATION_HORIZONTAL)
     g_return_if_fail (position <= image->height);
-  else
+  else if (gimp_guide_get_orientation(guide) == GIMP_ORIENTATION_VERTICAL)
     g_return_if_fail (position <= image->width);
 
+
   image->guides = g_list_prepend (image->guides, guide);
 
   gimp_guide_set_position (guide, position);
@@ -126,12 +160,14 @@
                        gboolean   push_undo)
 {
   g_return_if_fail (GIMP_IS_IMAGE (image));
+
   g_return_if_fail (GIMP_IS_GUIDE (guide));
-  g_return_if_fail (position >= 0);
+  g_return_if_fail (gimp_guide_get_orientation (guide) ==
+                    GIMP_ORIENTATION_FREE || position >= 0);
 
   if (gimp_guide_get_orientation (guide) == GIMP_ORIENTATION_HORIZONTAL)
     g_return_if_fail (position <= image->height);
-  else
+  else if (guide->orientation == GIMP_ORIENTATION_VERTICAL)
     g_return_if_fail (position <= image->width);
 
   if (push_undo)
@@ -206,6 +242,10 @@
   GimpGuide *ret = NULL;
   gdouble    dist;
   gdouble    mindist = G_MAXDOUBLE;
+  gdouble    x1;
+  gdouble    y1;
+  gdouble    u;
+  gdouble    res_factor;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
   g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
@@ -219,11 +259,12 @@
   for (list = image->guides; list; list = g_list_next (list))
     {
       gint position;
+      gdouble angle;
 
       guide = list->data;
       position = gimp_guide_get_position (guide);
 
-      if (position < 0)
+      if (position < 0 && gimp_guide_get_orientation (guide) != GIMP_ORIENTATION_FREE)
         continue;
 
       switch (gimp_guide_get_orientation (guide))
@@ -245,6 +286,24 @@
               mindist = dist * epsilon_y / epsilon_x;
               ret = guide;
             }
+          break;
+        case GIMP_ORIENTATION_FREE:
+          angle = gimp_guide_get_angle (guide);
+          /* FIXME: not finished - if guides are horz. or vert, treat as such. */
+          /* if (angle == 0.0 || angle == G_PI_2) */
+          /* nop  ; */
+          u = tan (angle);
+          x1 = (y - position + 1 / u * x) / ( u +  1 / u);
+          y1 = position + u * x1;
+          dist = sqrt ((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
+          res_factor = fabs (cos (angle)) +
+                       fabs (sin (angle) / epsilon_y * epsilon_x);
+          if (dist < MIN (epsilon_x * res_factor, mindist * res_factor))
+            {
+              mindist = dist / res_factor;
+              ret = guide;
+            }
+
           break;
 
         default:
Index: app/core/gimpimage-guides.h
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-guides.h,v
retrieving revision 1.112
diff -u -3 -r1.112 gimpimage-guides.h
--- app/core/gimpimage-guides.h	6 Jun 2006 22:48:55 -0000	1.112
+++ app/core/gimpimage-guides.h	28 Jun 2006 04:06:20 -0000
@@ -26,6 +26,11 @@
 GimpGuide * gimp_image_add_vguide     (GimpImage *image,
                                        gint       position,
                                        gboolean   push_undo);
+GimpGuide * gimp_image_add_free_guide (GimpImage *image,
+                                       gint       position,
+                                       gfloat     angle,
+                                       gboolean   push_undo);
+
 
 void        gimp_image_add_guide      (GimpImage *image,
                                        GimpGuide *guide,
Index: app/core/gimpimage-snap.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-snap.c,v
retrieving revision 1.19
diff -u -3 -r1.19 gimpimage-snap.c
--- app/core/gimpimage-snap.c	7 Jun 2006 15:47:31 -0000	1.19
+++ app/core/gimpimage-snap.c	28 Jun 2006 04:06:20 -0000
@@ -41,8 +41,10 @@
 gboolean
 gimp_image_snap_x (GimpImage *image,
                    gdouble    x,
+                   gdouble    y,
                    gdouble   *tx,
                    gdouble    epsilon_x,
+                   gdouble    epsilon_y,
                    gboolean   snap_to_guides,
                    gboolean   snap_to_grid,
                    gboolean   snap_to_canvas)
@@ -74,7 +76,8 @@
           GimpGuide *guide    = list->data;
           gint       position = gimp_guide_get_position (guide);
 
-          if (position < 0)
+          if (guide->position < 0 &&
+              guide->orientation != GIMP_ORIENTATION_FREE)
             continue;
 
           if (gimp_guide_get_orientation (guide) == GIMP_ORIENTATION_VERTICAL)
@@ -88,6 +91,28 @@
                   snapped = TRUE;
                 }
             }
+          if (guide->orientation == GIMP_ORIENTATION_FREE)
+            {
+              gdouble u;
+              gint    x1;
+              gint    y1;
+
+              if (guide->angle == 0.0 || guide->angle == G_PI_2)
+                continue;
+              u = tan (guide->angle);
+              x1 = (y - guide->position + 1 / u * x) / ( u +  1 / u);
+              y1 = guide->position + u * x1;
+              dist = sqrt ((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
+
+              if (dist < MIN (epsilon_x, mindist))
+                {
+                  mindist = dist;
+                  *tx = x1;
+                  snapped = TRUE;
+                }
+            }
+
+
         }
     }
 
@@ -146,8 +171,10 @@
 gboolean
 gimp_image_snap_y (GimpImage *image,
                    gdouble    y,
+                   gdouble    x,
                    gdouble   *ty,
                    gdouble    epsilon_y,
+                   gdouble    epsilon_x,
                    gboolean   snap_to_guides,
                    gboolean   snap_to_grid,
                    gboolean   snap_to_canvas)
@@ -179,7 +206,8 @@
           GimpGuide *guide    = list->data;
           gint       position = gimp_guide_get_position (guide);
 
-          if (position < 0)
+          if (guide->position < 0 &&
+              guide->orientation != GIMP_ORIENTATION_FREE)
             continue;
 
           if (gimp_guide_get_orientation (guide) == GIMP_ORIENTATION_HORIZONTAL)
@@ -193,6 +221,27 @@
                   snapped = TRUE;
                 }
             }
+          if (guide->orientation == GIMP_ORIENTATION_FREE)
+            {
+              gdouble u;
+              gint    x1;
+              gint    y1;
+
+              if (guide->angle == 0.0 || guide->angle == G_PI_2)
+                continue;
+              u = tan (guide->angle);
+              x1 = (y - guide->position + 1 / u * x) / ( u +  1 / u);
+              y1 = guide->position + u * x1;
+              dist = sqrt ((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
+
+              if (dist < MIN (epsilon_y, mindist))
+                {
+                  mindist = dist;
+                  *ty = y1;
+                  snapped = TRUE;
+                }
+            }
+
         }
     }
 
@@ -295,7 +344,8 @@
           GimpGuide *guide    = list->data;
           gint       position = gimp_guide_get_position (guide);
 
-          if (position < 0)
+          if (position < 0 &&
+              gimp_guide_get_orientation (guide) != GIMP_ORIENTATION_FREE)
             continue;
 
           switch (gimp_guide_get_orientation (guide))
@@ -322,6 +372,33 @@
                 }
               break;
 
+            case GIMP_ORIENTATION_FREE:
+              {
+                gdouble u;
+                gdouble angle;
+                gint    x1;
+                gint    y1;
+
+                angle = gimp_guide_get_angle (guide);
+
+                if (angle == 0.0 || angle == G_PI_2)
+                  continue;
+                u = tan (angle);
+                x1 = (y - position + 1 / u * x) / ( u +  1 / u);
+                y1 = position + u * x1;
+                dist = sqrt ((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
+
+                if (dist < MIN (epsilon_x, mindist_x))
+                  {
+                    mindist_x = mindist_y = dist;
+                    *tx = x1;
+                    *ty = y1;
+                    snapped = TRUE;
+                  }
+
+              }
+              break;
+
             default:
               break;
             }
@@ -488,8 +565,23 @@
     return FALSE;
 
   /*  left edge  */
-  if (gimp_image_snap_x (image, x1, &nx,
+
+  /* top */
+  if (gimp_image_snap_x (image, x1, y1, &nx,
+                         MIN (epsilon_x, mindist_x),
+                         MIN (epsilon_y, mindist_y),
+                         snap_to_guides,
+                         snap_to_grid,
+                         snap_to_canvas))
+    {
+      mindist_x = ABS (nx - x1);
+      *tx1 = nx;
+      snapped = TRUE;
+    }
+  /* botton */
+  if (gimp_image_snap_x (image, x1, y2, &nx,
                          MIN (epsilon_x, mindist_x),
+                         MIN (epsilon_y, mindist_y),
                          snap_to_guides,
                          snap_to_grid,
                          snap_to_canvas))
@@ -499,9 +591,24 @@
       snapped = TRUE;
     }
 
+
   /*  right edge  */
-  if (gimp_image_snap_x (image, x2, &nx,
+  /* top */
+  if (gimp_image_snap_x (image, x2, y1,  &nx,
+                         MIN (epsilon_x, mindist_x),
+                         MIN (epsilon_y, mindist_y),
+                         snap_to_guides,
+                         snap_to_grid,
+                         snap_to_canvas))
+    {
+      mindist_x = ABS (nx - x2);
+      *tx1 = RINT (x1 + (nx - x2));
+      snapped = TRUE;
+    }
+  /* botton */
+  if (gimp_image_snap_x (image, x2, y2,  &nx,
                          MIN (epsilon_x, mindist_x),
+                         MIN (epsilon_y, mindist_y),
                          snap_to_guides,
                          snap_to_grid,
                          snap_to_canvas))
@@ -511,9 +618,24 @@
       snapped = TRUE;
     }
 
+
   /*  top edge  */
-  if (gimp_image_snap_y (image, y1, &ny,
+  /* left */
+  if (gimp_image_snap_y (image, y1, x1, &ny,
                          MIN (epsilon_y, mindist_y),
+                         MIN (epsilon_x, mindist_x),
+                         snap_to_guides,
+                         snap_to_grid,
+                         snap_to_canvas))
+    {
+      mindist_y = ABS (ny - y1);
+      *ty1 = ny;
+      snapped = TRUE;
+    }
+  /* right */
+  if (gimp_image_snap_y (image, y1, x2, &ny,
+                         MIN (epsilon_y, mindist_y),
+                         MIN (epsilon_x, mindist_x),
                          snap_to_guides,
                          snap_to_grid,
                          snap_to_canvas))
@@ -524,8 +646,22 @@
     }
 
   /*  bottom edge  */
-  if (gimp_image_snap_y (image, y2, &ny,
+  /* left */
+  if (gimp_image_snap_y (image, y2, x1, &ny,
                          MIN (epsilon_y, mindist_y),
+                         MIN (epsilon_x, mindist_x),
+                         snap_to_guides,
+                         snap_to_grid,
+                         snap_to_canvas))
+    {
+      mindist_y = ABS (ny - y2);
+      *ty1 = RINT (y1 + (ny - y2));
+      snapped = TRUE;
+    }
+  /* right */
+  if (gimp_image_snap_y (image, y2, x2, &ny,
+                         MIN (epsilon_y, mindist_y),
+                         MIN (epsilon_x, mindist_x),
                          snap_to_guides,
                          snap_to_grid,
                          snap_to_canvas))
Index: app/core/gimpimage-snap.h
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-snap.h,v
retrieving revision 1.5
diff -u -3 -r1.5 gimpimage-snap.h
--- app/core/gimpimage-snap.h	28 Mar 2006 17:08:23 -0000	1.5
+++ app/core/gimpimage-snap.h	28 Jun 2006 04:06:20 -0000
@@ -22,15 +22,19 @@
 
 gboolean    gimp_image_snap_x         (GimpImage *image,
                                        gdouble    x,
+                                       gdouble    y,
                                        gdouble   *tx,
                                        gdouble    epsilon_x,
+                                       gdouble    epsilon_y,
                                        gboolean   snap_to_guides,
                                        gboolean   snap_to_grid,
                                        gboolean   snap_to_canvas);
 gboolean    gimp_image_snap_y         (GimpImage *image,
                                        gdouble    y,
+                                       gdouble    x,
                                        gdouble   *ty,
                                        gdouble    epsilon_y,
+                                       gdouble    epsilon_x,
                                        gboolean   snap_to_guides,
                                        gboolean   snap_to_grid,
                                        gboolean   snap_to_canvas);
Index: app/core/gimpimage-undo-push.c
===================================================================
RCS file: /cvs/gnome/gimp/app/core/gimpimage-undo-push.c,v
retrieving revision 1.252
diff -u -3 -r1.252 gimpimage-undo-push.c
--- app/core/gimpimage-undo-push.c	7 Jun 2006 15:47:31 -0000	1.252
+++ app/core/gimpimage-undo-push.c	28 Jun 2006 04:06:20 -0000
@@ -319,6 +319,7 @@
   GimpGuide           *guide;
   GimpOrientationType  orientation;
   gint                 position;
+  gdouble              angle;
 };
 
 static gboolean undo_pop_image_guide  (GimpUndo            *undo,
@@ -351,6 +352,7 @@
       gu->guide       = g_object_ref (guide);
       gu->orientation = gimp_guide_get_orientation (guide);
       gu->position    = gimp_guide_get_position (guide);
+      gu->angle       = gimp_guide_get_angle (guide);
 
       return TRUE;
     }
@@ -366,9 +368,13 @@
   GuideUndo           *gu = undo->data;
   GimpOrientationType  old_orientation;
   gint                 old_position;
+  gdouble              old_angle;
+
 
   old_orientation = gimp_guide_get_orientation (gu->guide);
   old_position    = gimp_guide_get_position (gu->guide);
+  old_angle       = gimp_guide_get_angle (gu->guide);
+
 
   /*  add and move guides manually (nor using the gimp_image_guide
    *  API), because we might be in the middle of an image resizing
@@ -379,8 +385,12 @@
   if (old_position == -1)
     {
       undo->image->guides = g_list_prepend (undo->image->guides, gu->guide);
+
       gimp_guide_set_position (gu->guide, gu->position);
+      gimp_guide_set_angle (gu->guide, gu->angle);
       g_object_ref (gu->guide);
+      g_object_ref (gu->guide);
+
       gimp_image_update_guide (undo->image, gu->guide);
     }
   else if (gu->position == -1)
@@ -391,6 +401,7 @@
     {
       gimp_image_update_guide (undo->image, gu->guide);
       gimp_guide_set_position (gu->guide, gu->position);
+      gimp_guide_set_angle (gu->guide, gu->angle);
       gimp_image_update_guide (undo->image, gu->guide);
     }
 
@@ -398,7 +409,8 @@
 
   gu->position    = old_position;
   gu->orientation = old_orientation;
-
+  gu->angle       = old_angle;
+  
   return TRUE;
 }
 
@@ -498,9 +510,11 @@
 
 struct _SamplePointUndo
 {
+
   GimpSamplePoint *sample_point;
   gint             x;
   gint             y;
+
 };
 
 static gboolean undo_pop_image_sample_point  (GimpUndo            *undo,
@@ -576,6 +590,7 @@
     }
   else
     {
+
       gimp_image_update_sample_point (undo->image, spu->sample_point);
       spu->sample_point->x = spu->x;
       spu->sample_point->y = spu->y;
Index: app/display/gimpdisplayshell-draw.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-draw.c,v
retrieving revision 1.324
diff -u -3 -r1.324 gimpdisplayshell-draw.c
--- app/display/gimpdisplayshell-draw.c	19 Jun 2006 17:49:55 -0000	1.324
+++ app/display/gimpdisplayshell-draw.c	28 Jun 2006 04:06:20 -0000
@@ -63,15 +63,18 @@
                                gboolean          active)
 {
   gint  position;
-  gint  x1, x2, y1, y2;
+  gdouble angle;
+  gint  x1, x2, x3, x4;
+  gint  y1, y2, y3, y4;
   gint  x, y, w, h;
+  gint  guide_style;
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
   g_return_if_fail (GIMP_IS_GUIDE (guide));
 
   position = gimp_guide_get_position (guide);
 
-  if (position < 0)
+  if (position < 0 && gimp_guide_get_orientation (guide) != GIMP_ORIENTATION_FREE)
     return;
 
   gimp_display_shell_transform_xy (shell, 0, 0, &x1, &y1, FALSE);
@@ -87,6 +90,9 @@
   x2 = MIN (x2, w);
   y2 = MIN (y2, h);
 
+  guide_style = active ? GIMP_CANVAS_STYLE_GUIDE_NORMAL :
+                GIMP_CANVAS_STYLE_GUIDE_ACTIVE;
+
   switch (gimp_guide_get_orientation (guide))
     {
     case GIMP_ORIENTATION_HORIZONTAL:
@@ -99,14 +105,51 @@
       x1 = x2 = x;
       break;
 
-    case GIMP_ORIENTATION_UNKNOWN:
-      return;
+    case GIMP_ORIENTATION_FREE:
+      angle = gimp_guide_get_angle (guide);
+      gimp_display_shell_transform_xy (shell,
+                                       0, position, &x, &y, FALSE);
+      x3 = x;
+      y3 = y;
+      x4 = x2;
+
+      y4 = y + (x4 - x) * tan (angle);
+
+      if (y4 < y1)
+        {
+          y4 = y1;
+          x4 = x + (y4 - y) / tan (angle);
+        }
+      else if (y4 > y2)
+        {
+          y4 = y2;
+          x4 = x + (y4 - y) / tan (angle);
+        }
+
+      if (y3 < y1)
+        {
+          y3 = y1 - 1;
+          x3 = x + (y3 - y) / tan (angle);
+        }
+      else if (y3 > y2)
+        {
+          y3 = y2;
+          x3 = x + (y3 - y) / tan (angle);
+        }
+
+      x1 = x3;
+      y1 = y3;
+      x2 = x4;
+      y2 = y4;
+
+      if (angle > 0)
+        guide_style = active ? GIMP_CANVAS_STYLE_GUIDE_REVERSED_NORMAL :
+                      GIMP_CANVAS_STYLE_GUIDE_REVERSED_ACTIVE;
+      break;
     }
 
   gimp_canvas_draw_line (GIMP_CANVAS (shell->canvas),
-                         (active ?
-                          GIMP_CANVAS_STYLE_GUIDE_ACTIVE :
-                          GIMP_CANVAS_STYLE_GUIDE_NORMAL), x1, y1, x2, y2);
+                         guide_style, x1, y1, x2, y2);
 }
 
 void
Index: app/display/gimpdisplayshell.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell.c,v
retrieving revision 1.391
diff -u -3 -r1.391 gimpdisplayshell.c
--- app/display/gimpdisplayshell.c	7 Jun 2006 19:51:33 -0000	1.391
+++ app/display/gimpdisplayshell.c	28 Jun 2006 04:06:21 -0000
@@ -1283,15 +1283,19 @@
 gimp_display_shell_expose_guide (GimpDisplayShell *shell,
                                  GimpGuide        *guide)
 {
-  gint position;
-  gint x, y;
+  gint    x;
+  gint    y;
+  gint    h;
+  gint    i;
+  gdouble u;
+  gint    position;
+  #define BLOCK_SIZE 16
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
   g_return_if_fail (GIMP_IS_GUIDE (guide));
 
   position = gimp_guide_get_position (guide);
-
-  if (position < 0)
+  if (position < 0 && gimp_guide_get_orientation (guide) != GIMP_ORIENTATION_FREE)
     return;
 
   gimp_display_shell_transform_xy (shell,
@@ -1309,9 +1313,24 @@
       gimp_display_shell_expose_area (shell, x, 0, 1, shell->disp_height);
       break;
 
+    case GIMP_ORIENTATION_FREE:
+      gimp_display_shell_transform_xy (shell,
+                                       0,
+                                       position,
+                                       &x, &y,
+                                       FALSE);
+      u  = tan (guide->angle);
+      h =  ABS (u * BLOCK_SIZE);
+      for (i = 0; i <= shell->disp_width; i += BLOCK_SIZE)
+        gimp_display_shell_expose_area (shell, i - BLOCK_SIZE,
+                                        y + u * (i - x) - h,
+                                        BLOCK_SIZE * 2, h * 2);
+      break;
+
     default:
       break;
     }
+  #undef BLOCK_SIZE
 }
 
 void
Index: app/display/gimpcanvas.h
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpcanvas.h,v
retrieving revision 1.8
diff -u -3 -r1.8 gimpcanvas.h
--- app/display/gimpcanvas.h	24 Jun 2005 23:28:37 -0000	1.8
+++ app/display/gimpcanvas.h	28 Jun 2006 04:06:21 -0000
@@ -36,6 +36,8 @@
   GIMP_CANVAS_STYLE_LAYER_BOUNDARY,
   GIMP_CANVAS_STYLE_GUIDE_NORMAL,
   GIMP_CANVAS_STYLE_GUIDE_ACTIVE,
+  GIMP_CANVAS_STYLE_GUIDE_REVERSED_NORMAL,
+  GIMP_CANVAS_STYLE_GUIDE_REVERSED_ACTIVE,
   GIMP_CANVAS_STYLE_SAMPLE_POINT_NORMAL,
   GIMP_CANVAS_STYLE_SAMPLE_POINT_ACTIVE,
   GIMP_CANVAS_STYLE_CUSTOM,
@@ -62,6 +64,7 @@
 
   GdkGC          *gc[GIMP_CANVAS_NUM_STYLES];
   GdkBitmap      *stipple[GIMP_CANVAS_NUM_STIPPLES];
+  GdkBitmap      *reversed_stipple;
   PangoLayout    *layout;
 };
 
Index: app/display/gimpcanvas.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpcanvas.c,v
retrieving revision 1.19
diff -u -3 -r1.19 gimpcanvas.c
--- app/display/gimpcanvas.c	15 May 2006 09:46:16 -0000	1.19
+++ app/display/gimpcanvas.c	28 Jun 2006 04:06:21 -0000
@@ -124,7 +124,17 @@
   },
 };
 
-
+static const guchar reversed_stipple [8] =
+  {
+    0xF0,    /*  ####----  */
+    0x78,    /*  -####---  */
+    0x3C,    /*  --####--  */
+    0x1E,    /*  ---####-  */
+    0x0F,    /*  ----####  */
+    0x87,    /*  #----###  */
+    0xC3,    /*  ##----##  */
+    0xE1,    /*  ###----#  */
+  };
 static void
 gimp_canvas_class_init (GimpCanvasClass *klass)
 {
@@ -144,6 +154,8 @@
 
   for (i = 0; i < GIMP_CANVAS_NUM_STIPPLES; i++)
     canvas->stipple[i] = NULL;
+
+  canvas->reversed_stipple = NULL;
 }
 
 static void
@@ -156,6 +168,9 @@
   canvas->stipple[0] =
     gdk_bitmap_create_from_data (widget->window,
                                  (const gchar *) stipples[0], 8, 8);
+  canvas->reversed_stipple =
+    gdk_bitmap_create_from_data (widget->window,
+                                 (const gchar *) reversed_stipple, 8, 8);
 }
 
 static void
@@ -181,7 +196,11 @@
           canvas->stipple[i] = NULL;
         }
     }
-
+  if (canvas->reversed_stipple)
+    {
+      g_object_unref (canvas->stipple[i]);
+      canvas->stipple[i] = NULL;
+    }
   if (canvas->layout)
     {
       g_object_unref (canvas->layout);
@@ -241,6 +260,13 @@
       values.stipple   = canvas->stipple[0];
       break;
 
+    case GIMP_CANVAS_STYLE_GUIDE_REVERSED_NORMAL:
+    case GIMP_CANVAS_STYLE_GUIDE_REVERSED_ACTIVE:
+      mask |= GDK_GC_CAP_STYLE | GDK_GC_FILL | GDK_GC_STIPPLE;
+      values.cap_style = GDK_CAP_NOT_LAST;
+      values.fill      = GDK_OPAQUE_STIPPLED;
+      values.stipple   = canvas->reversed_stipple;
+      break;
     case GIMP_CANVAS_STYLE_CUSTOM:
     default:
       return NULL;
@@ -301,6 +327,7 @@
       break;
 
     case GIMP_CANVAS_STYLE_GUIDE_NORMAL:
+    case GIMP_CANVAS_STYLE_GUIDE_REVERSED_NORMAL:
       fg.red   = 0x0;
       fg.green = 0x0;
       fg.blue  = 0x0;
@@ -311,6 +338,7 @@
       break;
 
     case GIMP_CANVAS_STYLE_GUIDE_ACTIVE:
+    case GIMP_CANVAS_STYLE_GUIDE_REVERSED_ACTIVE:
       fg.red   = 0x0;
       fg.green = 0x0;
       fg.blue  = 0x0;
Index: app/tools/gimpmoveoptions.h
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimpmoveoptions.h,v
retrieving revision 1.7
diff -u -3 -r1.7 gimpmoveoptions.h
--- app/tools/gimpmoveoptions.h	30 Oct 2004 15:02:39 -0000	1.7
+++ app/tools/gimpmoveoptions.h	28 Jun 2006 04:06:21 -0000
@@ -40,6 +40,7 @@
 
   GimpTransformType  move_type;
   gboolean           move_current;
+  gboolean           change_active;
 };
 
 
Index: app/tools/gimpmovetool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimpmovetool.c,v
retrieving revision 1.151
diff -u -3 -r1.151 gimpmovetool.c
--- app/tools/gimpmovetool.c	7 Jun 2006 15:47:32 -0000	1.151
+++ app/tools/gimpmovetool.c	28 Jun 2006 04:06:21 -0000
@@ -54,7 +54,9 @@
 
 #define SWAP_ORIENT(orient) ((orient) == GIMP_ORIENTATION_HORIZONTAL ? \
                              GIMP_ORIENTATION_VERTICAL : \
-                             GIMP_ORIENTATION_HORIZONTAL)
+                             (orient) == GIMP_ORIENTATION_VERTICAL ? \
+                             GIMP_ORIENTATION_HORIZONTAL : \
+                             GIMP_ORIENTATION_VERTICAL )
 
 
 
@@ -419,7 +421,10 @@
                                                        move->guide_position,
                                                        TRUE);
                   break;
-
+                case GIMP_ORIENTATION_FREE:
+                  break;
+                case GIMP_ORIENTATION_UNKNOWN:
+                  break;
                 default:
                   g_assert_not_reached ();
                 }
@@ -490,11 +495,12 @@
                                        &tx, &ty,
                                        FALSE);
 
-      if (tx < 0 || tx >= shell->disp_width ||
-          ty < 0 || ty >= shell->disp_height)
+
+      if (move->guide_orientation != GIMP_ORIENTATION_FREE &&
+          (tx < 0 || tx >= shell->disp_width ||
+          ty < 0 || ty >= shell->disp_height))
         {
           move->guide_position = -1;
-
           delete_guide = TRUE;
         }
       else
@@ -503,8 +509,12 @@
 
           if (move->guide_orientation == GIMP_ORIENTATION_HORIZONTAL)
             move->guide_position = RINT (coords->y);
-          else
+          else if (move->guide_orientation == GIMP_ORIENTATION_VERTICAL)
             move->guide_position = RINT (coords->x);
+          else if (move->guide_orientation == GIMP_ORIENTATION_FREE)
+            move->guide_position = RINT (coords->y
+                                   - tan (gimp_guide_get_angle(move->guide))
+                                   * coords->x);
 
           gimp_display_shell_untransform_viewport (shell, &x, &y,
                                                    &width, &height);
@@ -741,7 +751,8 @@
 {
   GimpMoveTool *move = GIMP_MOVE_TOOL (draw_tool);
 
-  if (move->moving_guide && move->guide_position != -1)
+  if (move->moving_guide && (move->guide_position != -1 ||
+      move->guide_orientation == GIMP_ORIENTATION_FREE))
     {
       switch (move->guide_orientation)
         {
@@ -760,7 +771,31 @@
                                     draw_tool->display->image->height,
                                     FALSE);
           break;
-
+        case GIMP_ORIENTATION_FREE:
+          {
+            gint x1;
+            gint y1;
+            gdouble angle = gimp_guide_get_angle (move->guide);
+
+            x1 = draw_tool->display->image->width;
+            y1 = move->guide_position + tan (angle) * x1;
+            if (y1 < 0)
+              {
+                y1 = 0;
+                x1 = - move->guide_position / tan (angle);
+              }
+            else if (y1 > draw_tool->display->image->height)
+              {
+                y1 = draw_tool->display->image->height;
+                x1 = (y1 - move->guide_position) / tan (angle);
+              }
+            gimp_draw_tool_draw_line (draw_tool,
+                                    0, move->guide_position,
+                                    x1,
+                                    y1,
+                                    FALSE);
+          }
+          break;
         default:
           g_assert_not_reached ();
         }
Index: tools/pdbgen/pdb/guides.pdb
===================================================================
RCS file: /cvs/gnome/gimp/tools/pdbgen/pdb/guides.pdb,v
retrieving revision 1.31
diff -u -3 -r1.31 guides.pdb
--- tools/pdbgen/pdb/guides.pdb	7 Jun 2006 15:47:33 -0000	1.31
+++ tools/pdbgen/pdb/guides.pdb	28 Jun 2006 04:06:21 -0000
@@ -97,6 +97,69 @@
     );
 }
 
+sub pdb_misc {
+    $author = $copyright = 'Adam D. Moss';
+    $date = '1998';
+}
+
+sub image_add_free_guide {
+
+
+    $blurb = "Add a Free guide to an image.";
+
+    $help = <<HELP;
+This procedure adds a free guide to an image. It takes the input image, an angle
+(degrees), and a y position at x==0 of the new guide as parameters. It returns the guide
+ID of the new guide.
+HELP
+
+    $author = 'Joao S. O. Bueno Calligaris and Adam D. Moss';
+    $copyright = 'Adam D. Moss';
+    $date = '2005';
+
+    @inargs = (
+	{ name => 'image', type => 'image',
+	  desc => 'The image' },
+	{ name => "yposition", type => 'int32',
+	  desc => "The guide's y offset at x == 0;",
+	  alias => 'offset' },
+	{ name => "angle", type => 'float',
+	  desc => "The guide's angle;",
+	  alias => 'angle' },
+    );
+    @outargs = (
+	{ name => 'guide', type => 'guide',
+	  desc => 'The new guide' }
+    );
+    
+
+    my $func = 'f';
+    %invoke = (
+	code => <<CODE
+{
+  if (angle > -89.99 && angle < 89.99)
+    {
+      GimpGuide *g;
+      if (angle != 0)
+        {
+          angle = - angle / 180.0 * G_PI;
+          g = gimp_image_add_free_guide (image, yposition, angle, TRUE);
+        }
+      else
+        {
+          g = gimp_image_add_hguide (image, yposition, TRUE);
+        }
+      guide = g->guide_ID;
+    }
+  else
+    success = FALSE;
+}
+CODE
+    );
+}
+
+
+
 sub image_delete_guide {
     $blurb = 'Deletes a guide from an image.';
 
@@ -241,7 +304,7 @@
 
 @headers = qw("core/gimpguide.h" "core/gimpimage-guides.h" "core/gimpimage-undo-push.h");
 
-@procs = qw(image_add_hguide image_add_vguide image_delete_guide
+@procs = qw(image_add_hguide image_add_vguide image_add_free_guide image_delete_guide
 	    image_find_next_guide image_get_guide_orientation
 	    image_get_guide_position);
 
Index: plug-ins/script-fu/scripts/guides-new.scm
===================================================================
RCS file: /cvs/gnome/gimp/plug-ins/script-fu/scripts/guides-new.scm,v
retrieving revision 1.6
diff -u -3 -r1.6 guides-new.scm
--- plug-ins/script-fu/scripts/guides-new.scm	23 Jan 2006 23:18:02 -0000	1.6
+++ plug-ins/script-fu/scripts/guides-new.scm	28 Jun 2006 04:06:21 -0000
@@ -1,35 +1,46 @@
 ;; -*-scheme-*-
 
-;; Alan Horkan 2004.  Public Domain.  
+;; Alan Horkan 2004.  Public Domain.
 ;; so long as remove this block of comments from your script
-;; feel free to use it for whatever you like.  
+;; feel free to use it for whatever you like.
 
 (define (script-fu-guide-new image
 			     drawable
 			     direction
+			     angle
 			     position)
   (let* ((width (car (gimp-image-width image)))
 	 (height (car (gimp-image-height image))))
 
-    (if (= direction 0) 
+    (if (= direction 0)
 	;; check position is inside the image boundaries
-	(if (<= position height) (gimp-image-add-hguide image position))
+
+	(if (<= position height) (gimp-image-add-hguide image position)))
+    (if (= direction 1)
 	(if (<= position width) (gimp-image-add-vguide image position)))
 
+    (if (= direction 2)
+	(gimp-image-add-free-guide image position angle))
+
+    (gimp-image-undo-group-end image)
+
     (gimp-displays-flush)))
-    
-(script-fu-register "script-fu-guide-new" 
-		    _"New _Guide..." 
+
+(script-fu-register "script-fu-guide-new"
+		    _"New _Guide..."
 		    "Add a single Line Guide with the specified postion and orientation. Postion is specified in Pixels (px)."
-		    "Alan Horkan"
+		    "Joao S. O. Bueno Calligaris & Alan Horkan"
 		    "Alan Horkan, 2004.  Public Domain."
-		    "2004-04-02"
+		    "2005-02-28"
 		    ""
-		    SF-IMAGE      "Image"      0 
+		    SF-IMAGE      "Image"      0
 		    SF-DRAWABLE   "Drawable"   0
-		    SF-OPTION     _"Direction" '(_"Horizontal" 
-						 _"Vertical")
+		    SF-OPTION     _"Direction" '(_"Horizontal"
+						 _"Vertical"
+						 _"Free")
+		    SF-ADJUSTMENT "Angle"      '(0 -89.9 89.9 1 10 0 1)
 		    SF-ADJUSTMENT "Position"   '(0 0 262144 1 10 0 1))
-    
-(script-fu-menu-register "script-fu-guide-new" 
+
+
+(script-fu-menu-register "script-fu-guide-new"
 			 "<Image>/Image/Guides")
