Getting colder with our second freeze... it's 3.31.91 release day and string freeze, upload a tarball and lock those strings 🏂

gtkadjustment.c 27.7 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20 21
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 24
 */

25
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
26
#include "gtkadjustment.h"
27
#include "gtkadjustmentprivate.h"
28
#include "gtkmarshalers.h"
29 30
#include "gtkprivate.h"
#include "gtkintl.h"
31

Elliot Lee's avatar
Elliot Lee committed
32

33 34 35 36 37 38 39
/**
 * SECTION:gtkadjustment
 * @Short_description: A representation of an adjustable bounded value
 * @Title: GtkAdjustment
 *
 * The #GtkAdjustment object represents a value which has an associated lower
 * and upper bound, together with step and page increments, and a page size.
40 41
 * It is used within several GTK+ widgets, including #GtkSpinButton, #GtkViewport,
 * and #GtkRange (which is a base class for #GtkScrollbar and #GtkScale).
42 43 44 45 46 47
 *
 * The #GtkAdjustment object does not update the value itself. Instead
 * it is left up to the owner of the #GtkAdjustment to control the value.
 */


48 49 50 51 52 53 54
struct _GtkAdjustmentPrivate {
  gdouble lower;
  gdouble upper;
  gdouble value;
  gdouble step_increment;
  gdouble page_increment;
  gdouble page_size;
55 56 57 58 59 60 61 62 63

  gdouble source;
  gdouble target;

  guint duration;
  gint64 start_time;
  gint64 end_time;
  guint tick_id;
  GdkFrameClock *clock;
64 65
};

66 67 68 69 70 71 72 73
enum
{
  PROP_0,
  PROP_VALUE,
  PROP_LOWER,
  PROP_UPPER,
  PROP_STEP_INCREMENT,
  PROP_PAGE_INCREMENT,
74 75
  PROP_PAGE_SIZE,
  NUM_PROPERTIES
76
};
Elliot Lee's avatar
Elliot Lee committed
77

Michael Natterer's avatar
Michael Natterer committed
78 79
enum
{
Elliot Lee's avatar
Elliot Lee committed
80 81 82 83 84 85
  CHANGED,
  VALUE_CHANGED,
  LAST_SIGNAL
};


Michael Natterer's avatar
Michael Natterer committed
86 87 88 89 90 91 92 93 94 95 96
static void gtk_adjustment_get_property                (GObject      *object,
                                                        guint         prop_id,
                                                        GValue       *value,
                                                        GParamSpec   *pspec);
static void gtk_adjustment_set_property                (GObject      *object,
                                                        guint         prop_id,
                                                        const GValue *value,
                                                        GParamSpec   *pspec);
static void gtk_adjustment_dispatch_properties_changed (GObject      *object,
                                                        guint         n_pspecs,
                                                        GParamSpec  **pspecs);
Elliot Lee's avatar
Elliot Lee committed
97

98
static guint adjustment_signals[LAST_SIGNAL] = { 0 };
Elliot Lee's avatar
Elliot Lee committed
99

100 101
static GParamSpec *adjustment_props[NUM_PROPERTIES] = { NULL, };

102 103
static guint64 adjustment_changed_stamp = 0; /* protected by global gdk lock */

104
G_DEFINE_TYPE_WITH_PRIVATE (GtkAdjustment, gtk_adjustment, G_TYPE_INITIALLY_UNOWNED)
Elliot Lee's avatar
Elliot Lee committed
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119
static void
gtk_adjustment_finalize (GObject *object)
{
  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
  GtkAdjustmentPrivate *priv = adjustment->priv;

  if (priv->tick_id)
    g_signal_handler_disconnect (priv->clock, priv->tick_id);
  if (priv->clock)
    g_object_unref (priv->clock);

  G_OBJECT_CLASS (gtk_adjustment_parent_class)->finalize (object);
}

Elliot Lee's avatar
Elliot Lee committed
120 121 122
static void
gtk_adjustment_class_init (GtkAdjustmentClass *class)
{
123 124
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

125
  gobject_class->finalize                    = gtk_adjustment_finalize;
Michael Natterer's avatar
Michael Natterer committed
126 127 128
  gobject_class->set_property                = gtk_adjustment_set_property;
  gobject_class->get_property                = gtk_adjustment_get_property;
  gobject_class->dispatch_properties_changed = gtk_adjustment_dispatch_properties_changed;
129

130 131 132
  class->changed = NULL;
  class->value_changed = NULL;

133 134
  /**
   * GtkAdjustment:value:
135
   *
136
   * The value of the adjustment.
137
   *
138 139
   * Since: 2.4
   */
140 141 142 143 144 145 146
  adjustment_props[PROP_VALUE] =
      g_param_spec_double ("value",
                           P_("Value"),
                           P_("The value of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);
147

148 149
  /**
   * GtkAdjustment:lower:
150
   *
151
   * The minimum value of the adjustment.
152
   *
153 154
   * Since: 2.4
   */
155 156 157 158 159 160 161
  adjustment_props[PROP_LOWER] =
      g_param_spec_double ("lower",
                           P_("Minimum Value"),
                           P_("The minimum value of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);
162

163 164
  /**
   * GtkAdjustment:upper:
165 166 167 168
   *
   * The maximum value of the adjustment.
   * Note that values will be restricted by
   * `upper - page-size` if the page-size
169 170 171 172
   * property is nonzero.
   *
   * Since: 2.4
   */
173 174 175 176 177 178 179
  adjustment_props[PROP_UPPER] =
      g_param_spec_double ("upper",
                           P_("Maximum Value"),
                           P_("The maximum value of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);
180

181 182
  /**
   * GtkAdjustment:step-increment:
183
   *
184
   * The step increment of the adjustment.
185
   *
186 187
   * Since: 2.4
   */
188 189 190 191 192 193 194
  adjustment_props[PROP_STEP_INCREMENT] =
      g_param_spec_double ("step-increment",
                           P_("Step Increment"),
                           P_("The step increment of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);
195

196 197
  /**
   * GtkAdjustment:page-increment:
198
   *
199
   * The page increment of the adjustment.
200
   *
201 202
   * Since: 2.4
   */
203 204 205 206 207 208 209
  adjustment_props[PROP_PAGE_INCREMENT] =
      g_param_spec_double ("page-increment",
                           P_("Page Increment"),
                           P_("The page increment of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);
210

211 212
  /**
   * GtkAdjustment:page-size:
213 214
   *
   * The page size of the adjustment.
215
   * Note that the page-size is irrelevant and should be set to zero
216
   * if the adjustment is used for a simple scalar value, e.g. in a
217
   * #GtkSpinButton.
218
   *
219 220
   * Since: 2.4
   */
221 222 223 224 225 226 227 228 229
  adjustment_props[PROP_PAGE_SIZE] =
      g_param_spec_double ("page-size",
                           P_("Page Size"),
                           P_("The page size of the adjustment"),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           0.0,
                           GTK_PARAM_READWRITE);

  g_object_class_install_properties (gobject_class, NUM_PROPERTIES, adjustment_props);
230

231 232
  /**
   * GtkAdjustment::changed:
233
   * @adjustment: the object which received the signal
234
   *
235 236
   * Emitted when one or more of the #GtkAdjustment properties have been
   * changed, other than the #GtkAdjustment:value property.
237
   */
Elliot Lee's avatar
Elliot Lee committed
238
  adjustment_signals[CHANGED] =
239
    g_signal_new (I_("changed"),
Manish Singh's avatar
Manish Singh committed
240 241 242 243
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
		  G_STRUCT_OFFSET (GtkAdjustmentClass, changed),
		  NULL, NULL,
244
		  NULL,
Manish Singh's avatar
Manish Singh committed
245
		  G_TYPE_NONE, 0);
Michael Natterer's avatar
Michael Natterer committed
246

247 248
  /**
   * GtkAdjustment::value-changed:
249
   * @adjustment: the object which received the signal
250
   *
251
   * Emitted when the #GtkAdjustment:value property has been changed.
252
   */
Elliot Lee's avatar
Elliot Lee committed
253
  adjustment_signals[VALUE_CHANGED] =
254
    g_signal_new (I_("value-changed"),
Manish Singh's avatar
Manish Singh committed
255 256 257 258
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
		  G_STRUCT_OFFSET (GtkAdjustmentClass, value_changed),
		  NULL, NULL,
259
		  NULL,
Manish Singh's avatar
Manish Singh committed
260
		  G_TYPE_NONE, 0);
Elliot Lee's avatar
Elliot Lee committed
261 262 263 264 265
}

static void
gtk_adjustment_init (GtkAdjustment *adjustment)
{
266
  adjustment->priv = gtk_adjustment_get_instance_private (adjustment);
Elliot Lee's avatar
Elliot Lee committed
267 268
}

269
static void
Michael Natterer's avatar
Michael Natterer committed
270 271 272 273
gtk_adjustment_get_property (GObject    *object,
                             guint       prop_id,
                             GValue     *value,
                             GParamSpec *pspec)
274 275
{
  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
276
  GtkAdjustmentPrivate *priv = adjustment->priv;
277 278 279 280

  switch (prop_id)
    {
    case PROP_VALUE:
281
      g_value_set_double (value, priv->value);
282 283
      break;
    case PROP_LOWER:
284
      g_value_set_double (value, priv->lower);
285 286
      break;
    case PROP_UPPER:
287
      g_value_set_double (value, priv->upper);
288 289
      break;
    case PROP_STEP_INCREMENT:
290
      g_value_set_double (value, priv->step_increment);
291 292
      break;
    case PROP_PAGE_INCREMENT:
293
      g_value_set_double (value, priv->page_increment);
294 295
      break;
    case PROP_PAGE_SIZE:
296
      g_value_set_double (value, priv->page_size);
297 298 299 300 301 302 303 304
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
Michael Natterer's avatar
Michael Natterer committed
305 306 307 308
gtk_adjustment_set_property (GObject      *object,
                             guint         prop_id,
                             const GValue *value,
                             GParamSpec   *pspec)
309 310 311
{
  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
  gdouble double_value = g_value_get_double (value);
312
  GtkAdjustmentPrivate *priv = adjustment->priv;
313 314 315 316

  switch (prop_id)
    {
    case PROP_VALUE:
Michael Natterer's avatar
Michael Natterer committed
317
      gtk_adjustment_set_value (adjustment, double_value);
318 319
      break;
    case PROP_LOWER:
320
      priv->lower = double_value;
321 322
      break;
    case PROP_UPPER:
323
      priv->upper = double_value;
324 325
      break;
    case PROP_STEP_INCREMENT:
326
      priv->step_increment = double_value;
327 328
      break;
    case PROP_PAGE_INCREMENT:
329
      priv->page_increment = double_value;
330 331
      break;
    case PROP_PAGE_SIZE:
332
      priv->page_size = double_value;
333 334 335 336 337 338 339
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

340 341 342 343 344 345 346 347 348 349
static inline void
emit_changed (GtkAdjustment *adjustment)
{
  g_signal_emit (adjustment, adjustment_signals[CHANGED], 0);
}

static inline void
emit_value_changed (GtkAdjustment *adjustment)
{
  g_signal_emit (adjustment, adjustment_signals[VALUE_CHANGED], 0);
350
  g_object_notify_by_pspec (G_OBJECT (adjustment), adjustment_props[PROP_VALUE]);
351 352
}

Michael Natterer's avatar
Michael Natterer committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
static void
gtk_adjustment_dispatch_properties_changed (GObject     *object,
                                            guint        n_pspecs,
                                            GParamSpec **pspecs)
{
  gboolean changed = FALSE;
  gint i;

  G_OBJECT_CLASS (gtk_adjustment_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);

  for (i = 0; i < n_pspecs; i++)
    switch (pspecs[i]->param_id)
      {
      case PROP_LOWER:
      case PROP_UPPER:
      case PROP_STEP_INCREMENT:
      case PROP_PAGE_INCREMENT:
      case PROP_PAGE_SIZE:
        changed = TRUE;
        break;
      default:
        break;
      }

  if (changed)
378 379
    {
      adjustment_changed_stamp++;
380
      emit_changed (GTK_ADJUSTMENT (object));
381
    }
Michael Natterer's avatar
Michael Natterer committed
382 383
}

384 385
/**
 * gtk_adjustment_new:
386 387 388 389 390 391
 * @value: the initial value
 * @lower: the minimum value
 * @upper: the maximum value
 * @step_increment: the step increment
 * @page_increment: the page increment
 * @page_size: the page size
392 393 394
 *
 * Creates a new #GtkAdjustment.
 *
395
 * Returns: a new #GtkAdjustment
396
 */
397
GtkAdjustment *
398 399 400 401 402 403
gtk_adjustment_new (gdouble value,
		    gdouble lower,
		    gdouble upper,
		    gdouble step_increment,
		    gdouble page_increment,
		    gdouble page_size)
Elliot Lee's avatar
Elliot Lee committed
404
{
405
  return g_object_new (GTK_TYPE_ADJUSTMENT,
406 407 408 409
		       "lower", lower,
		       "upper", upper,
		       "step-increment", step_increment,
		       "page-increment", page_increment,
410
		       "page-size", page_size,
411
		       "value", value,
412
		       NULL);
Elliot Lee's avatar
Elliot Lee committed
413
}
414

415 416 417 418
/**
 * gtk_adjustment_get_value:
 * @adjustment: a #GtkAdjustment
 *
419 420
 * Gets the current value of the adjustment.
 * See gtk_adjustment_set_value().
421
 *
422
 * Returns: The current value of the adjustment
423 424 425 426
 **/
gdouble
gtk_adjustment_get_value (GtkAdjustment *adjustment)
{
Michael Natterer's avatar
Michael Natterer committed
427
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
428

429
  return adjustment->priv->value;
430 431
}

432 433 434 435 436 437 438 439 440 441 442
gdouble
gtk_adjustment_get_target_value (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

  if (adjustment->priv->tick_id)
    return adjustment->priv->target;
  else
    return adjustment->priv->value;
}

443 444 445 446
static void
adjustment_set_value (GtkAdjustment *adjustment,
                      gdouble        value)
{
447
  if (adjustment->priv->value != value)
448 449
    {
      adjustment->priv->value = value;
450
      emit_value_changed (adjustment);
451 452 453
    }
}

454
static void gtk_adjustment_on_frame_clock_update (GdkFrameClock *clock,
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
                                                  GtkAdjustment *adjustment);

static void
gtk_adjustment_begin_updating (GtkAdjustment *adjustment)
{
  GtkAdjustmentPrivate *priv = adjustment->priv;

  if (priv->tick_id == 0)
    {
      priv->tick_id = g_signal_connect (priv->clock, "update",
                                        G_CALLBACK (gtk_adjustment_on_frame_clock_update), adjustment);
      gdk_frame_clock_begin_updating (priv->clock);
    }
}

static void
gtk_adjustment_end_updating (GtkAdjustment *adjustment)
{
  GtkAdjustmentPrivate *priv = adjustment->priv;

  if (priv->tick_id != 0)
    {
      g_signal_handler_disconnect (priv->clock, priv->tick_id);
      priv->tick_id = 0;
      gdk_frame_clock_end_updating (priv->clock);
    }
}

483 484 485 486 487 488 489 490 491 492 493
/* From clutter-easing.c, based on Robert Penner's
 * infamous easing equations, MIT license.
 */
static gdouble
ease_out_cubic (gdouble t)
{
  gdouble p = t - 1;

  return p * p * p + 1;
}

494
static void
495
gtk_adjustment_on_frame_clock_update (GdkFrameClock *clock,
496
                                      GtkAdjustment *adjustment)
497 498
{
  GtkAdjustmentPrivate *priv = adjustment->priv;
499 500 501
  gint64 now;

  now = gdk_frame_clock_get_frame_time (clock);
502 503 504 505 506 507 508 509 510 511 512 513

  if (now < priv->end_time)
    {
      gdouble t;

      t = (now - priv->start_time) / (gdouble) (priv->end_time - priv->start_time);
      t = ease_out_cubic (t);
      adjustment_set_value (adjustment, priv->source + t * (priv->target - priv->source));
    }
  else
    {
      adjustment_set_value (adjustment, priv->target);
514
      gtk_adjustment_end_updating (adjustment);
515 516 517 518
    }
}

static void
519 520 521
gtk_adjustment_set_value_internal (GtkAdjustment *adjustment,
                                   gdouble        value,
                                   gboolean       animate)
522 523 524
{
  GtkAdjustmentPrivate *priv = adjustment->priv;

525 526 527 528 529
  /* don't use CLAMP() so we don't end up below lower if upper - page_size
   * is smaller than lower
   */
  value = MIN (value, priv->upper - priv->page_size);
  value = MAX (value, priv->lower);
530

531
  if (animate && priv->duration != 0 && priv->clock != NULL)
532
    {
533
      if (priv->tick_id && priv->target == value)
534 535
        return;

536
      priv->source = priv->value;
537
      priv->target = value;
538 539
      priv->start_time = gdk_frame_clock_get_frame_time (priv->clock);
      priv->end_time = priv->start_time + 1000 * priv->duration;
540
      gtk_adjustment_begin_updating (adjustment);
541 542
    }
  else
543 544 545 546
    {
      gtk_adjustment_end_updating (adjustment);
      adjustment_set_value (adjustment, value);
    }
547 548
}

549 550
/**
 * gtk_adjustment_set_value:
551 552
 * @adjustment: a #GtkAdjustment
 * @value: the new value
553 554
 *
 * Sets the #GtkAdjustment value. The value is clamped to lie between
555
 * #GtkAdjustment:lower and #GtkAdjustment:upper.
556
 *
557 558 559
 * Note that for adjustments which are used in a #GtkScrollbar, the
 * effective range of allowed values goes from #GtkAdjustment:lower to
 * #GtkAdjustment:upper - #GtkAdjustment:page-size.
560
 */
561
void
Michael Natterer's avatar
Michael Natterer committed
562 563
gtk_adjustment_set_value (GtkAdjustment *adjustment,
			  gdouble        value)
564 565 566
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

567 568
  gtk_adjustment_set_value_internal (adjustment, value, FALSE);
}
569

570 571 572 573 574
void
gtk_adjustment_animate_to_value (GtkAdjustment *adjustment,
			         gdouble        value)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
575

576
  gtk_adjustment_set_value_internal (adjustment, value, TRUE);
577 578
}

579 580 581 582 583 584
/**
 * gtk_adjustment_get_lower:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the minimum value of the adjustment.
 *
585
 * Returns: The current minimum value of the adjustment
586 587 588 589 590 591 592 593
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_lower (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

594
  return adjustment->priv->lower;
595 596 597 598 599 600 601 602 603 604
}

/**
 * gtk_adjustment_set_lower:
 * @adjustment: a #GtkAdjustment
 * @lower: the new minimum value
 *
 * Sets the minimum value of the adjustment.
 *
 * When setting multiple adjustment properties via their individual
605 606 607 608 609 610
 * setters, multiple #GtkAdjustment::changed signals will be emitted.
 * However, since the emission of the #GtkAdjustment::changed signal
 * is tied to the emission of the #GObject::notify signals of the changed
 * properties, it’s possible to compress the #GtkAdjustment::changed
 * signals into one by calling g_object_freeze_notify() and
 * g_object_thaw_notify() around the calls to the individual setters.
611 612 613
 *
 * Alternatively, using a single g_object_set() for all the properties
 * to change, or using gtk_adjustment_configure() has the same effect
614
 * of compressing #GtkAdjustment::changed emissions.
615 616 617 618 619 620 621 622 623
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_lower (GtkAdjustment *adjustment,
                          gdouble        lower)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

624
  if (lower != adjustment->priv->lower)
625 626 627 628 629 630 631 632 633
    g_object_set (adjustment, "lower", lower, NULL);
}

/**
 * gtk_adjustment_get_upper:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the maximum value of the adjustment.
 *
634
 * Returns: The current maximum value of the adjustment
635 636 637 638 639 640 641 642
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_upper (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

643
  return adjustment->priv->upper;
644 645 646 647 648 649 650 651 652
}

/**
 * gtk_adjustment_set_upper:
 * @adjustment: a #GtkAdjustment
 * @upper: the new maximum value
 *
 * Sets the maximum value of the adjustment.
 *
653 654
 * Note that values will be restricted by `upper - page-size`
 * if the page-size property is nonzero.
655 656
 *
 * See gtk_adjustment_set_lower() about how to compress multiple
657 658
 * emissions of the #GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
659 660 661 662 663 664 665 666 667
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_upper (GtkAdjustment *adjustment,
                          gdouble        upper)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

668
  if (upper != adjustment->priv->upper)
669 670 671 672 673 674 675 676 677
    g_object_set (adjustment, "upper", upper, NULL);
}

/**
 * gtk_adjustment_get_step_increment:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the step increment of the adjustment.
 *
678
 * Returns: The current step increment of the adjustment.
679 680 681 682 683 684 685 686
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_step_increment (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

687
  return adjustment->priv->step_increment;
688 689 690 691 692 693 694 695 696 697
}

/**
 * gtk_adjustment_set_step_increment:
 * @adjustment: a #GtkAdjustment
 * @step_increment: the new step increment
 *
 * Sets the step increment of the adjustment.
 *
 * See gtk_adjustment_set_lower() about how to compress multiple
698 699
 * emissions of the #GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
700 701 702 703 704 705 706 707 708
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_step_increment (GtkAdjustment *adjustment,
                                   gdouble        step_increment)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

709
  if (step_increment != adjustment->priv->step_increment)
710 711 712 713 714 715 716 717 718
    g_object_set (adjustment, "step-increment", step_increment, NULL);
}

/**
 * gtk_adjustment_get_page_increment:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the page increment of the adjustment.
 *
719
 * Returns: The current page increment of the adjustment
720 721 722 723 724 725 726 727
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_page_increment (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

728
  return adjustment->priv->page_increment;
729 730 731 732 733 734 735 736 737 738
}

/**
 * gtk_adjustment_set_page_increment:
 * @adjustment: a #GtkAdjustment
 * @page_increment: the new page increment
 *
 * Sets the page increment of the adjustment.
 *
 * See gtk_adjustment_set_lower() about how to compress multiple
739 740
 * emissions of the #GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
741 742 743 744 745 746 747 748 749
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_page_increment (GtkAdjustment *adjustment,
                                   gdouble        page_increment)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

750
  if (page_increment != adjustment->priv->page_increment)
751 752 753 754 755 756 757 758 759
    g_object_set (adjustment, "page-increment", page_increment, NULL);
}

/**
 * gtk_adjustment_get_page_size:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the page size of the adjustment.
 *
760
 * Returns: The current page size of the adjustment
761 762 763 764 765 766 767 768
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_page_size (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

769
  return adjustment->priv->page_size;
770 771 772 773 774 775 776 777 778 779
}

/**
 * gtk_adjustment_set_page_size:
 * @adjustment: a #GtkAdjustment
 * @page_size: the new page size
 *
 * Sets the page size of the adjustment.
 *
 * See gtk_adjustment_set_lower() about how to compress multiple
780 781
 * emissions of the GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
782 783 784 785 786 787 788 789 790
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_page_size (GtkAdjustment *adjustment,
                              gdouble        page_size)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

791
  if (page_size != adjustment->priv->page_size)
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
    g_object_set (adjustment, "page-size", page_size, NULL);
}

/**
 * gtk_adjustment_configure:
 * @adjustment: a #GtkAdjustment
 * @value: the new value
 * @lower: the new minimum value
 * @upper: the new maximum value
 * @step_increment: the new step increment
 * @page_increment: the new page increment
 * @page_size: the new page size
 *
 * Sets all properties of the adjustment at once.
 *
807 808 809 810
 * Use this function to avoid multiple emissions of the
 * #GtkAdjustment::changed signal. See gtk_adjustment_set_lower()
 * for an alternative way of compressing multiple emissions of
 * #GtkAdjustment::changed into one.
811 812 813 814 815 816 817 818 819 820 821 822
 *
 * Since: 2.14
 **/
void
gtk_adjustment_configure (GtkAdjustment *adjustment,
                          gdouble        value,
                          gdouble        lower,
                          gdouble        upper,
                          gdouble        step_increment,
                          gdouble        page_increment,
                          gdouble        page_size)
{
823
  GtkAdjustmentPrivate *priv;
824 825 826 827 828
  gboolean value_changed = FALSE;
  guint64 old_stamp = adjustment_changed_stamp;

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

829 830
  priv = adjustment->priv;

831 832 833 834 835 836 837 838 839 840
  g_object_freeze_notify (G_OBJECT (adjustment));

  g_object_set (adjustment,
                "lower", lower,
                "upper", upper,
                "step-increment", step_increment,
                "page-increment", page_increment,
                "page-size", page_size,
                NULL);

841 842 843 844 845
  /* don't use CLAMP() so we don't end up below lower if upper - page_size
   * is smaller than lower
   */
  value = MIN (value, upper - page_size);
  value = MAX (value, lower);
846

847
  if (value != priv->value)
848 849 850 851
    {
      /* set value manually to make sure "changed" is emitted with the
       * new value in place and is emitted before "value-changed"
       */
852
      priv->value = value;
853 854 855 856 857 858
      value_changed = TRUE;
    }

  g_object_thaw_notify (G_OBJECT (adjustment));

  if (old_stamp == adjustment_changed_stamp)
859
    emit_changed (adjustment); /* force emission before ::value-changed */
860 861

  if (value_changed)
862
    emit_value_changed (adjustment);
863 864
}

865 866 867 868 869 870
/**
 * gtk_adjustment_changed:
 * @adjustment: a #GtkAdjustment
 *
 * Emits a #GtkAdjustment::changed signal from the #GtkAdjustment.
 * This is typically called by the owner of the #GtkAdjustment after it has
871
 * changed any of the #GtkAdjustment properties other than the value.
872 873 874
 *
 * Deprecated: 3.18: GTK+ emits #GtkAdjustment::changed itself whenever any
 *    of the properties (other than value) change
875
 */
876
void
Michael Natterer's avatar
Michael Natterer committed
877
gtk_adjustment_changed (GtkAdjustment *adjustment)
878 879
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
880
  emit_changed (adjustment);
881 882
}

883 884 885 886
/**
 * gtk_adjustment_value_changed:
 * @adjustment: a #GtkAdjustment
 *
887
 * Emits a #GtkAdjustment::value-changed signal from the #GtkAdjustment.
888
 * This is typically called by the owner of the #GtkAdjustment after it has
889
 * changed the #GtkAdjustment:value property.
890 891 892
 *
 * Deprecated: 3.18: GTK+ emits #GtkAdjustment::value-changed itself whenever
 *    the value changes
893
 */
894
void
Michael Natterer's avatar
Michael Natterer committed
895
gtk_adjustment_value_changed (GtkAdjustment *adjustment)
896 897
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
898
  emit_value_changed (adjustment);
899
}
900

901 902
/**
 * gtk_adjustment_clamp_page:
903 904 905
 * @adjustment: a #GtkAdjustment
 * @lower: the lower value
 * @upper: the upper value
906
 *
907
 * Updates the #GtkAdjustment:value property to ensure that the range
908
 * between @lower and @upper is in the current page (i.e. between
909
 * #GtkAdjustment:value and #GtkAdjustment:value + #GtkAdjustment:page-size).
910 911
 * If the range is larger than the page size, then only the start of it will
 * be in the current page.
912 913
 *
 * A #GtkAdjustment::value-changed signal will be emitted if the value is changed.
914
 */
915 916
void
gtk_adjustment_clamp_page (GtkAdjustment *adjustment,
917 918
			   gdouble        lower,
			   gdouble        upper)
919
{
920
  GtkAdjustmentPrivate *priv;
921
  gboolean need_emission;
922 923 924

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

925 926 927 928
  priv = adjustment->priv;

  lower = CLAMP (lower, priv->lower, priv->upper);
  upper = CLAMP (upper, priv->lower, priv->upper);
929 930 931

  need_emission = FALSE;

932
  if (priv->value + priv->page_size < upper)
933
    {
934
      priv->value = upper - priv->page_size;
935 936
      need_emission = TRUE;
    }
937
  if (priv->value > lower)
938
    {
939
      priv->value = lower;
940 941 942 943
      need_emission = TRUE;
    }

  if (need_emission)
944
    emit_value_changed (adjustment);
945
}
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989

/**
 * gtk_adjustment_get_minimum_increment:
 * @adjustment: a #GtkAdjustment
 *
 * Gets the smaller of step increment and page increment.
 *
 * Returns: the minimum increment of @adjustment
 *
 * Since: 3.2
 */
gdouble
gtk_adjustment_get_minimum_increment (GtkAdjustment *adjustment)
{
  GtkAdjustmentPrivate *priv;
  gdouble minimum_increment;

  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0);

  priv = adjustment->priv;

    if (priv->step_increment != 0 && priv->page_increment != 0)
    {
      if (ABS (priv->step_increment) < ABS (priv->page_increment))
        minimum_increment = priv->step_increment;
      else
        minimum_increment = priv->page_increment;
    }
  else if (priv->step_increment == 0 && priv->page_increment == 0)
    {
      minimum_increment = 0;
    }
  else if (priv->step_increment == 0)
    {
      minimum_increment = priv->page_increment;
    }
  else
    {
      minimum_increment = priv->step_increment;
    }

  return minimum_increment;
}

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
void
gtk_adjustment_enable_animation (GtkAdjustment *adjustment,
                                 GdkFrameClock *clock,
                                 guint          duration)
{
  GtkAdjustmentPrivate *priv = adjustment->priv;

  if (priv->clock != clock)
    {
      if (priv->tick_id)
        {
          adjustment_set_value (adjustment, priv->target);

          g_signal_handler_disconnect (priv->clock, priv->tick_id);
          priv->tick_id = 0;
          gdk_frame_clock_end_updating (priv->clock);
        }

      if (priv->clock)
        g_object_unref (priv->clock);

      priv->clock = clock;

      if (priv->clock)
        g_object_ref (priv->clock);
    }

1017
  priv->duration = duration;
1018
}
1019

Matthias Clasen's avatar
Matthias Clasen committed
1020
guint
1021 1022 1023 1024
gtk_adjustment_get_animation_duration (GtkAdjustment *adjustment)
{
  return adjustment->priv->duration;
}
1025 1026 1027 1028 1029 1030

gboolean
gtk_adjustment_is_animating (GtkAdjustment *adjustment)
{
  return adjustment->priv->tick_id != 0;
}