gimpzoommodel.c 18.8 KB
Newer Older
1 2 3 4 5 6
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
 * gimpzoommodel.c
 * Copyright (C) 2005  David Odin <dindinx@gimp.org>
 *
7
 * This library is free software: you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 3 of the License, or (at your option) any later version.
11 12 13 14 15 16 17
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
19
 * <https://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27
 */

#include "config.h"

#include <gtk/gtk.h>

#include "gimpwidgetstypes.h"

28
#include "libgimpbase/gimpbase.h"
Sven Neumann's avatar
Sven Neumann committed
29 30
#include "libgimpmath/gimpmath.h"

31
#include "gimphelpui.h"
32
#include "gimpwidgetsmarshal.h"
33 34 35
#include "gimpzoommodel.h"


36 37 38 39 40 41 42 43 44
/**
 * SECTION: gimpzoommodel
 * @title: GimpZoomModel
 * @short_description: A model for zoom values.
 *
 * A model for zoom values.
 **/


45 46 47
#define ZOOM_MIN  (1.0 / 256.0)
#define ZOOM_MAX  (256.0)

48 49 50 51 52 53
enum
{
  ZOOMED,
  LAST_SIGNAL
};

54 55 56
enum
{
  PROP_0,
57 58
  PROP_VALUE,
  PROP_MINIMUM,
59 60 61
  PROP_MAXIMUM,
  PROP_FRACTION,
  PROP_PERCENTAGE
62 63
};

64

65
struct _GimpZoomModelPrivate
66
{
67 68 69
  gdouble  value;
  gdouble  minimum;
  gdouble  maximum;
70
};
71

72
#define GET_PRIVATE(obj) (((GimpZoomModel *) (obj))->priv)
73 74


75 76 77 78 79 80 81 82 83
static void  gimp_zoom_model_set_property (GObject      *object,
                                           guint         property_id,
                                           const GValue *value,
                                           GParamSpec   *pspec);
static void  gimp_zoom_model_get_property (GObject      *object,
                                           guint         property_id,
                                           GValue       *value,
                                           GParamSpec   *pspec);

84

85 86
static guint zoom_model_signals[LAST_SIGNAL] = { 0, };

87
G_DEFINE_TYPE_WITH_PRIVATE (GimpZoomModel, gimp_zoom_model, G_TYPE_OBJECT)
88

89 90
#define parent_class gimp_zoom_model_parent_class

91

92 93 94
static void
gimp_zoom_model_class_init (GimpZoomModelClass *klass)
{
95 96 97 98 99 100 101 102
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  /**
   * GimpZoomModel::zoomed:
   * @model: the object that received the signal
   * @old_factor: the zoom factor before it changes
   * @new_factor: the zoom factor after it has changed.
   *
103
   * Emitted when the zoom factor of the zoom model changes.
104 105 106 107 108 109 110 111 112 113 114
   */
  zoom_model_signals[ZOOMED] =
      g_signal_new ("zoomed",
                    G_TYPE_FROM_CLASS (klass),
                    G_SIGNAL_RUN_LAST,
                    G_STRUCT_OFFSET (GimpZoomModelClass,
                                     zoomed),
                    NULL, NULL,
                    _gimp_widgets_marshal_VOID__DOUBLE_DOUBLE,
                    G_TYPE_NONE, 2,
                    G_TYPE_DOUBLE, G_TYPE_DOUBLE);
115

116 117
  object_class->set_property = gimp_zoom_model_set_property;
  object_class->get_property = gimp_zoom_model_get_property;
118

119 120 121 122 123
  /**
   * GimpZoomModel:value:
   *
   * The zoom factor.
   */
124 125
  g_object_class_install_property (object_class, PROP_VALUE,
                                   g_param_spec_double ("value",
126 127
                                                        "Value",
                                                        "Zoom factor",
128
                                                        ZOOM_MIN, ZOOM_MAX,
129
                                                        1.0,
130
                                                        GIMP_PARAM_READWRITE));
131 132 133 134 135
  /**
   * GimpZoomModel:minimum:
   *
   * The minimum zoom factor.
   */
136 137
  g_object_class_install_property (object_class, PROP_MINIMUM,
                                   g_param_spec_double ("minimum",
138 139
                                                        "Minimum",
                                                        "Lower limit for the zoom factor",
140 141
                                                        ZOOM_MIN, ZOOM_MAX,
                                                        ZOOM_MIN,
142
                                                        GIMP_PARAM_READWRITE));
143 144 145 146 147
  /**
   * GimpZoomModel:maximum:
   *
   * The maximum zoom factor.
   */
148 149
  g_object_class_install_property (object_class, PROP_MAXIMUM,
                                   g_param_spec_double ("maximum",
150 151
                                                        "Maximum",
                                                        "Upper limit for the zoom factor",
152 153
                                                        ZOOM_MIN, ZOOM_MAX,
                                                        ZOOM_MAX,
154
                                                        GIMP_PARAM_READWRITE));
155

156 157 158 159 160
  /**
   * GimpZoomModel:fraction:
   *
   * The zoom factor expressed as a fraction.
   */
161 162
  g_object_class_install_property (object_class, PROP_FRACTION,
                                   g_param_spec_string ("fraction",
163 164
                                                        "Fraction",
                                                        "The zoom factor expressed as a fraction",
165
                                                        "1:1",
166
                                                        GIMP_PARAM_READABLE));
167 168 169 170 171
  /**
   * GimpZoomModel:percentage:
   *
   * The zoom factor expressed as percentage.
   */
172 173
  g_object_class_install_property (object_class, PROP_PERCENTAGE,
                                   g_param_spec_string ("percentage",
174 175
                                                        "Percentage",
                                                        "The zoom factor expressed as a percentage",
176
                                                        "100%",
177
                                                        GIMP_PARAM_READABLE));
178 179 180
}

static void
181
gimp_zoom_model_init (GimpZoomModel *model)
182
{
183 184
  GimpZoomModelPrivate *priv;

185
  model->priv = gimp_zoom_model_get_instance_private (model);
186

187
  priv = GET_PRIVATE (model);
188

Sven Neumann's avatar
Sven Neumann committed
189
  priv->value   = 1.0;
190 191
  priv->minimum = ZOOM_MIN;
  priv->maximum = ZOOM_MAX;
192 193 194 195 196 197 198 199
}

static void
gimp_zoom_model_set_property (GObject      *object,
                              guint         property_id,
                              const GValue *value,
                              GParamSpec   *pspec)
{
200
  GimpZoomModelPrivate *priv  = GET_PRIVATE (object);
201
  gdouble               previous_value;
202

203
  previous_value = priv->value;
Sven Neumann's avatar
Sven Neumann committed
204 205
  g_object_freeze_notify (object);

206 207
  switch (property_id)
    {
208 209
    case PROP_VALUE:
      priv->value = g_value_get_double (value);
Sven Neumann's avatar
Sven Neumann committed
210

211
      g_object_notify (object, "value");
212 213
      g_object_notify (object, "fraction");
      g_object_notify (object, "percentage");
214 215
      break;

216 217
    case PROP_MINIMUM:
      priv->minimum = MIN (g_value_get_double (value), priv->maximum);
218 219
      break;

220 221
    case PROP_MAXIMUM:
      priv->maximum = MAX (g_value_get_double (value), priv->minimum);
222 223 224 225 226 227
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
228

229
  if (priv->value > priv->maximum || priv->value < priv->minimum)
230
    {
231
      priv->value = CLAMP (priv->value, priv->minimum, priv->maximum);
Sven Neumann's avatar
Sven Neumann committed
232

233
      g_object_notify (object, "value");
234 235
      g_object_notify (object, "fraction");
      g_object_notify (object, "percentage");
236
    }
Sven Neumann's avatar
Sven Neumann committed
237 238

  g_object_thaw_notify (object);
239

240 241 242 243 244
  if (priv->value != previous_value)
    {
      g_signal_emit (object, zoom_model_signals[ZOOMED],
                     0, previous_value, priv->value);
    }
245 246 247 248 249 250 251 252
}

static void
gimp_zoom_model_get_property (GObject    *object,
                              guint       property_id,
                              GValue     *value,
                              GParamSpec *pspec)
{
253
  GimpZoomModelPrivate *priv = GET_PRIVATE (object);
254
  gchar                *tmp;
255 256 257

  switch (property_id)
    {
258 259
    case PROP_VALUE:
      g_value_set_double (value, priv->value);
260 261
      break;

262 263
    case PROP_MINIMUM:
      g_value_set_double (value, priv->minimum);
264 265
      break;

266 267
    case PROP_MAXIMUM:
      g_value_set_double (value, priv->maximum);
268 269
      break;

270
    case PROP_FRACTION:
271 272 273
      {
        gint  numerator;
        gint  denominator;
Sven Neumann's avatar
Sven Neumann committed
274

275 276 277 278 279 280 281
        gimp_zoom_model_get_fraction (GIMP_ZOOM_MODEL (object),
                                      &numerator, &denominator);

        tmp = g_strdup_printf ("%d:%d", numerator, denominator);
        g_value_set_string (value, tmp);
        g_free (tmp);
      }
282 283 284
      break;

    case PROP_PERCENTAGE:
285 286
      tmp = g_strdup_printf (priv->value >= 0.15 ? "%.0f%%" : "%.2f%%",
                             priv->value * 100.0);
287 288 289 290
      g_value_set_string (value, tmp);
      g_free (tmp);
      break;

291 292 293 294 295 296 297
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
298
gimp_zoom_model_zoom_in (GimpZoomModel *model)
299
{
300
  GimpZoomModelPrivate *priv = GET_PRIVATE (model);
301

302 303
  if (priv->value < priv->maximum)
    gimp_zoom_model_zoom (model, GIMP_ZOOM_IN, 0.0);
304 305 306
}

static void
307
gimp_zoom_model_zoom_out (GimpZoomModel *model)
308
{
309
  GimpZoomModelPrivate *priv = GET_PRIVATE (model);
310

311
  if (priv->value > priv->minimum)
312
    gimp_zoom_model_zoom (model, GIMP_ZOOM_OUT, 0.0);
313 314
}

Sven Neumann's avatar
Sven Neumann committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
/**
 * gimp_zoom_model_new:
 *
 * Creates a new #GimpZoomModel.
 *
 * Return value: a new #GimpZoomModel.
 *
 * Since GIMP 2.4
 **/
GimpZoomModel *
gimp_zoom_model_new (void)
{
  return g_object_new (GIMP_TYPE_ZOOM_MODEL, NULL);
}


/**
 * gimp_zoom_model_set_range:
 * @model: a #GimpZoomModel
 * @min: new lower limit for zoom factor
 * @max: new upper limit for zoom factor
 *
 * Sets the allowed range of the @model.
 *
 * Since GIMP 2.4
 **/
void
gimp_zoom_model_set_range (GimpZoomModel *model,
                           gdouble        min,
                           gdouble        max)
{
346
  g_return_if_fail (GIMP_IS_ZOOM_MODEL (model));
Sven Neumann's avatar
Sven Neumann committed
347
  g_return_if_fail (min < max);
348 349
  g_return_if_fail (min >= ZOOM_MIN);
  g_return_if_fail (max <= ZOOM_MAX);
Sven Neumann's avatar
Sven Neumann committed
350 351

  g_object_set (model,
352 353 354
                "minimum", min,
                "maximum", max,
                NULL);
Sven Neumann's avatar
Sven Neumann committed
355 356 357
}

/**
358 359 360 361
 * gimp_zoom_model_zoom:
 * @model:     a #GimpZoomModel
 * @zoom_type: the #GimpZoomType
 * @scale:     ignored unless @zoom_type == %GIMP_ZOOM_TO
Sven Neumann's avatar
Sven Neumann committed
362 363 364
 *
 * Since GIMP 2.4
 **/
365 366 367 368
void
gimp_zoom_model_zoom (GimpZoomModel *model,
                      GimpZoomType   zoom_type,
                      gdouble        scale)
Sven Neumann's avatar
Sven Neumann committed
369
{
370 371
  gdouble delta = 0.0;

372
  g_return_if_fail (GIMP_IS_ZOOM_MODEL (model));
Sven Neumann's avatar
Sven Neumann committed
373

374 375 376
  if (zoom_type == GIMP_ZOOM_SMOOTH)
    delta = scale;

377 378
  if (zoom_type != GIMP_ZOOM_TO)
    scale = gimp_zoom_model_get_factor (model);
Sven Neumann's avatar
Sven Neumann committed
379

380
  g_object_set (model,
381
                "value", gimp_zoom_model_zoom_step (zoom_type, scale, delta),
382
                NULL);
Sven Neumann's avatar
Sven Neumann committed
383 384 385
}

/**
386
 * gimp_zoom_model_get_factor:
Sven Neumann's avatar
Sven Neumann committed
387 388
 * @model: a #GimpZoomModel
 *
389
 * Retrieves the current zoom factor of @model.
Sven Neumann's avatar
Sven Neumann committed
390
 *
391
 * Return value: the current scale factor
Sven Neumann's avatar
Sven Neumann committed
392 393 394
 *
 * Since GIMP 2.4
 **/
395 396
gdouble
gimp_zoom_model_get_factor (GimpZoomModel *model)
Sven Neumann's avatar
Sven Neumann committed
397
{
398
  g_return_val_if_fail (GIMP_IS_ZOOM_MODEL (model), 1.0);
Sven Neumann's avatar
Sven Neumann committed
399

400
  return GET_PRIVATE (model)->value;
Sven Neumann's avatar
Sven Neumann committed
401 402
}

403

Sven Neumann's avatar
Sven Neumann committed
404 405
/**
 * gimp_zoom_model_get_fraction
406 407
 * @model:       a #GimpZoomModel
 * @numerator:   return location for numerator
Sven Neumann's avatar
Sven Neumann committed
408 409
 * @denominator: return location for denominator
 *
410
 * Retrieves the current zoom factor of @model as a fraction.
Sven Neumann's avatar
Sven Neumann committed
411 412 413
 *
 * Since GIMP 2.4
 **/
414
void
415 416 417
gimp_zoom_model_get_fraction (GimpZoomModel *model,
                              gint          *numerator,
                              gint          *denominator)
418 419 420
{
  gint     p0, p1, p2;
  gint     q0, q1, q2;
421
  gdouble  zoom_factor;
422 423 424
  gdouble  remainder, next_cf;
  gboolean swapped = FALSE;

425
  g_return_if_fail (GIMP_IS_ZOOM_MODEL (model));
426 427
  g_return_if_fail (numerator != NULL && denominator != NULL);

428 429
  zoom_factor = gimp_zoom_model_get_factor (model);

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
  /* make sure that zooming behaves symmetrically */
  if (zoom_factor < 1.0)
    {
      zoom_factor = 1.0 / zoom_factor;
      swapped = TRUE;
    }

  /* calculate the continued fraction for the desired zoom factor */

  p0 = 1;
  q0 = 0;
  p1 = floor (zoom_factor);
  q1 = 1;

  remainder = zoom_factor - p1;

  while (fabs (remainder) >= 0.0001 &&
         fabs (((gdouble) p1 / q1) - zoom_factor) > 0.0001)
    {
      remainder = 1.0 / remainder;

      next_cf = floor (remainder);

      p2 = next_cf * p1 + p0;
      q2 = next_cf * q1 + q0;

      /* Numerator and Denominator are limited by 256 */
      /* also absurd ratios like 170:171 are excluded */
      if (p2 > 256 || q2 > 256 || (p2 > 1 && q2 > 1 && p2 * q2 > 200))
        break;

      /* remember the last two fractions */
      p0 = p1;
      p1 = p2;
      q0 = q1;
      q1 = q2;

      remainder = remainder - next_cf;
    }

  zoom_factor = (gdouble) p1 / q1;

  /* hard upper and lower bounds for zoom ratio */

  if (zoom_factor > 256.0)
    {
      p1 = 256;
      q1 = 1;
    }
  else if (zoom_factor < 1.0 / 256.0)
    {
      p1 = 1;
      q1 = 256;
    }

  if (swapped)
    {
      *numerator = q1;
      *denominator = p1;
    }
  else
    {
      *numerator = p1;
      *denominator = q1;
    }
}

497
static GtkWidget *
498
zoom_button_new (const gchar *icon_name,
499 500 501
                 GtkIconSize  icon_size)
{
  GtkWidget *button;
502
  GtkWidget *image;
503

504 505 506
  image = gtk_image_new_from_icon_name (icon_name,
                                        icon_size > 0 ?
                                        icon_size : GTK_ICON_SIZE_BUTTON);
507

508 509 510
  button = gtk_button_new ();
  gtk_container_add (GTK_CONTAINER (button), image);
  gtk_widget_show (image);
511 512 513 514

  return button;
}

515 516 517 518 519 520
static void
zoom_in_button_callback (GimpZoomModel *model,
                         gdouble        old,
                         gdouble        new,
                         GtkWidget     *button)
{
521
  GimpZoomModelPrivate *priv = GET_PRIVATE (model);
522 523 524 525 526 527 528 529 530 531

  gtk_widget_set_sensitive (button, priv->value != priv->maximum);
}

static void
zoom_out_button_callback (GimpZoomModel *model,
                          gdouble        old,
                          gdouble        new,
                          GtkWidget     *button)
{
532
  GimpZoomModelPrivate *priv = GET_PRIVATE (model);
533 534 535 536

  gtk_widget_set_sensitive (button, priv->value != priv->minimum);
}

537
/**
538 539 540 541
 * gimp_zoom_button_new:
 * @model:     a #GimpZoomModel
 * @zoom_type:
 * @icon_size: use 0 for a button with text labels
542
 *
543
 * Return value: a newly created GtkButton
544 545 546 547
 *
 * Since GIMP 2.4
 **/
GtkWidget *
548 549 550
gimp_zoom_button_new (GimpZoomModel *model,
                      GimpZoomType   zoom_type,
                      GtkIconSize    icon_size)
551
{
552
  GtkWidget *button = NULL;
553 554 555

  g_return_val_if_fail (GIMP_IS_ZOOM_MODEL (model), NULL);

556
  switch (zoom_type)
557
    {
558
    case GIMP_ZOOM_IN:
559
      button = zoom_button_new ("zoom-in", icon_size);
560 561 562
      g_signal_connect_swapped (button, "clicked",
                                G_CALLBACK (gimp_zoom_model_zoom_in),
                                model);
563 564 565
      g_signal_connect_object (model, "zoomed",
                               G_CALLBACK (zoom_in_button_callback),
                               button, 0);
566
      break;
567

568
    case GIMP_ZOOM_OUT:
569
      button = zoom_button_new ("zoom-out", icon_size);
570 571 572
      g_signal_connect_swapped (button, "clicked",
                                G_CALLBACK (gimp_zoom_model_zoom_out),
                                model);
573 574 575
      g_signal_connect_object (model, "zoomed",
                               G_CALLBACK (zoom_out_button_callback),
                               button, 0);
576 577 578 579 580
      break;

    default:
      g_warning ("sorry, no button for this zoom type (%d)", zoom_type);
      break;
581 582
    }

583
  if (button)
584
    {
585 586 587 588
      gdouble zoom = gimp_zoom_model_get_factor (model);

      /*  set initial button sensitivity  */
      g_signal_emit (model, zoom_model_signals[ZOOMED], 0, zoom, zoom);
589

590
      if (icon_size > 0)
591
        {
592 593 594 595 596 597 598
          const gchar *desc;

          if (gimp_enum_get_value (GIMP_TYPE_ZOOM_TYPE, zoom_type,
                                   NULL, NULL, &desc, NULL))
            {
              gimp_help_set_help_data (button, desc, NULL);
            }
599 600 601
        }
    }

602
  return button;
603 604
}

Sven Neumann's avatar
Sven Neumann committed
605 606
/**
 * gimp_zoom_model_zoom_step:
607
 * @zoom_type: the zoom type
608
 * @scale:     ignored unless @zoom_type == %GIMP_ZOOM_TO
609
 * @delta:     the delta from a smooth zoom event
Sven Neumann's avatar
Sven Neumann committed
610 611 612 613 614 615 616
 *
 * Utility function to calculate a new scale factor.
 *
 * Return value: the new scale factor
 *
 * Since GIMP 2.4
 **/
617 618
gdouble
gimp_zoom_model_zoom_step (GimpZoomType zoom_type,
619 620
                           gdouble      scale,
                           gdouble      delta)
621 622 623 624 625 626 627 628
{
  gint    i, n_presets;
  gdouble new_scale = 1.0;

  /* This table is constructed to have fractions, that approximate
   * sqrt(2)^k. This gives a smooth feeling regardless of the starting
   * zoom level.
   *
629
   * Zooming in/out always jumps to a zoom step from the list below.
630 631
   * However, we try to guarantee a certain size of the step, to
   * avoid silly jumps from 101% to 100%.
632
   *
633 634 635 636 637 638
   * The factor 1.1 is chosen a bit arbitrary, but feels better
   * than the geometric median of the zoom steps (2^(1/4)).
   */

#define ZOOM_MIN_STEP 1.1

639
  const gdouble presets[] = {
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
    1.0 / 256, 1.0 / 180, 1.0 / 128, 1.0 / 90,
    1.0 / 64,  1.0 / 45,  1.0 / 32,  1.0 / 23,
    1.0 / 16,  1.0 / 11,  1.0 / 8,   2.0 / 11,
    1.0 / 4,   1.0 / 3,   1.0 / 2,   2.0 / 3,
      1.0,
               3.0 / 2,      2.0,      3.0,
      4.0,    11.0 / 2,      8.0,     11.0,
      16.0,     23.0,       32.0,     45.0,
      64.0,     90.0,      128.0,    180.0,
      256.0,
  };

  n_presets = G_N_ELEMENTS (presets);

  switch (zoom_type)
    {
    case GIMP_ZOOM_IN:
      scale *= ZOOM_MIN_STEP;

659
      new_scale = presets[n_presets - 1];
660 661 662 663 664 665 666 667 668 669 670 671 672 673
      for (i = n_presets - 1; i >= 0 && presets[i] > scale; i--)
        new_scale = presets[i];

      break;

    case GIMP_ZOOM_OUT:
      scale /= ZOOM_MIN_STEP;

      new_scale = presets[0];
      for (i = 0; i < n_presets && presets[i] < scale; i++)
        new_scale = presets[i];

      break;

674
    case GIMP_ZOOM_IN_MORE:
675 676 677
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_IN, scale, 0.0);
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_IN, scale, 0.0);
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_IN, scale, 0.0);
678 679 680 681
      new_scale = scale;
      break;

    case GIMP_ZOOM_OUT_MORE:
682 683 684
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_OUT, scale, 0.0);
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_OUT, scale, 0.0);
      scale = gimp_zoom_model_zoom_step (GIMP_ZOOM_OUT, scale, 0.0);
685 686 687 688 689 690 691 692 693 694 695
      new_scale = scale;
      break;

    case GIMP_ZOOM_IN_MAX:
      new_scale = ZOOM_MAX;
      break;

    case GIMP_ZOOM_OUT_MAX:
      new_scale = ZOOM_MIN;
      break;

696 697 698
    case GIMP_ZOOM_TO:
      new_scale = scale;
      break;
699 700 701 702 703 704 705 706 707 708

    case GIMP_ZOOM_SMOOTH:
      if (delta > 0.0)
        new_scale = scale * (1.0 + 0.1 * delta);
      else if (delta < 0.0)
        new_scale = scale / (1.0 + 0.1 * -delta);
      else
        new_scale = scale;
      break;

709 710
    }

711
  return CLAMP (new_scale, ZOOM_MIN, ZOOM_MAX);
712 713 714

#undef ZOOM_MIN_STEP
}