Index: app/display/gimpdisplayshell-scale.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-scale.c,v
retrieving revision 1.66
diff -u -p -r1.66 gimpdisplayshell-scale.c
--- app/display/gimpdisplayshell-scale.c	11 Jan 2004 12:55:45 -0000	1.66
+++ app/display/gimpdisplayshell-scale.c	16 Jan 2004 20:37:45 -0000
@@ -72,32 +72,116 @@ gimp_display_shell_scale_zoom_fraction (
                                         gint         *scalesrc,
                                         gint         *scaledest)
 {
-  gdouble ratio;
+  /* Array sizes http://experts.about.com/q/1587/1057651.htm */
+#define NUM_PRESETS 48
+#define BIAS_ELEM 16
+  gint presets[NUM_PRESETS] = {
+      1,   2,   3,   4,   5,   6,   7,   8, /*  +1 */
+      9,  10,  11,  12,  13,  14,  15,  16, /*  +1 */
+     18,  20,  22,  24,  26,  28,  30,  32, /*  +2 */
+     36,  40,  44,  48,  52,  56,  60,  64, /*  +4 */
+     72,  80,  88,  96, 104, 112, 120, 128, /*  +8 */
+    144, 160, 176, 192, 208, 224, 240, 255  /* +16 */
+  };
+  gint     src, dest;
+  gint     nratio;
+  gdouble  ratio;
+  gboolean swapped = FALSE;
+  gint     shift;
+  gint     mid = BIAS_ELEM;
+  gint     low = 0;
+  gint     high = (NUM_PRESETS-1);
 
   g_return_if_fail (scalesrc != NULL);
   g_return_if_fail (scaledest != NULL);
 
-  ratio = (double) *scaledest/ *scalesrc;
+  src  = *scalesrc;
+  dest = *scaledest;
 
-  switch (zoom_type)
+  if (! (zoom_type == GIMP_ZOOM_IN || zoom_type == GIMP_ZOOM_OUT))
     {
-    case GIMP_ZOOM_IN:
-      ratio *= G_SQRT2;
-      break;
-
-    case GIMP_ZOOM_OUT:
-      ratio /= G_SQRT2;
-      break;
+      /* zoom_type is an "encoding" of desired zoom */
+      src  = CLAMP (zoom_type % 100, 1, 0xFF);
+      dest = CLAMP (zoom_type / 100, 1, 0xFF);
+    }
+  else if (src == 1 && dest == 1)
+    {
+      /* Flip point, manual handling */
+      switch (zoom_type)
+        {
+        case GIMP_ZOOM_IN:
+          dest = 3;
+          src = 2;
+          break;
+
+        case GIMP_ZOOM_OUT:
+          dest = 3;
+          src = 4;
+          break;
+        }
+    }
+  else
+    {
+      /* Handling by presets */
+      ratio = (double) *scaledest / *scalesrc;
+      if (ratio < 1.0)
+        {
+          swapped = TRUE;
+          ratio = (1.0 / ratio);
+          /* printf("r %f\n", ratio); */
+        }
+
+      /* 
+         Readjust into N:1 (or 1:N) erring in the right side so
+         direction is kept and jump is only one step
+           swapped FALSE: 1 2 3 4 5
+                       IN     ->     floor
+                       OUT   <-      ceil
+           swapped TRUE:  5 4 3 2 1
+                       IN     ->     ceil
+                       OUT   <-      floor
+       */
+      if ((zoom_type == GIMP_ZOOM_IN && swapped == TRUE) ||
+          (zoom_type == GIMP_ZOOM_OUT && swapped == FALSE))
+        {
+          nratio = (int) ceil(ratio);
+          shift = -1;
+        }
+      else
+        {
+          nratio = (int) floor(ratio);
+          shift = 1;
+        }
+
+      /* Modified binary search */
+      while (low <= high) {
+        if (presets[mid] == nratio)
+          break;
+
+        if (presets[mid] > nratio)
+            high = mid - 1;
+        else
+            low = mid + 1;
+
+        /* Special handling of mid, at the end, due the bias trick */
+        if (low <= high)
+          mid = (low + high) / 2;
+      }
 
-    default:
-      *scalesrc  = CLAMP (zoom_type % 100, 1, 0xFF);
-      *scaledest = CLAMP (zoom_type / 100, 1, 0xFF);
-      return;
-      break;
+      src = 1;
+      dest = CLAMP (presets[mid+shift], 1, 0xFF);
     }
 
-  /* set scalesrc and scaledest to a fraction close to ratio */
-  gimp_display_shell_scale_calc_fraction (ratio, scalesrc, scaledest);
+  if (swapped)
+    {
+      *scalesrc  = dest;
+      *scaledest = src;
+    }
+  else
+    {
+      *scalesrc  = src;
+      *scaledest = dest;
+    }
 }
 
 void
