gtkadjustment.c 27.6 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 74 75
enum
{
  PROP_0,
  PROP_VALUE,
  PROP_LOWER,
  PROP_UPPER,
  PROP_STEP_INCREMENT,
  PROP_PAGE_INCREMENT,
  PROP_PAGE_SIZE
};
Elliot Lee's avatar
Elliot Lee committed
76

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


Michael Natterer's avatar
Michael Natterer committed
85 86 87 88 89 90 91 92 93 94 95
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
96

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

99 100
static guint64 adjustment_changed_stamp = 0; /* protected by global gdk lock */

101
G_DEFINE_TYPE_WITH_PRIVATE (GtkAdjustment, gtk_adjustment, G_TYPE_INITIALLY_UNOWNED)
Elliot Lee's avatar
Elliot Lee committed
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116
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
117 118 119
static void
gtk_adjustment_class_init (GtkAdjustmentClass *class)
{
120 121
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

122
  gobject_class->finalize                    = gtk_adjustment_finalize;
Michael Natterer's avatar
Michael Natterer committed
123 124 125
  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;
126

127 128 129
  class->changed = NULL;
  class->value_changed = NULL;

130 131
  /**
   * GtkAdjustment:value:
132
   *
133
   * The value of the adjustment.
134
   *
135 136
   * Since: 2.4
   */
137 138 139 140 141
  g_object_class_install_property (gobject_class,
                                   PROP_VALUE,
                                   g_param_spec_double ("value",
							P_("Value"),
							P_("The value of the adjustment"),
142 143 144
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
							0.0,
145
							GTK_PARAM_READWRITE));
146

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

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

184 185
  /**
   * GtkAdjustment:step-increment:
186
   *
187
   * The step increment of the adjustment.
188
   *
189 190
   * Since: 2.4
   */
191 192 193 194 195
  g_object_class_install_property (gobject_class,
                                   PROP_STEP_INCREMENT,
                                   g_param_spec_double ("step-increment",
							P_("Step Increment"),
							P_("The step increment of the adjustment"),
196 197 198
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
							0.0,
199
							GTK_PARAM_READWRITE));
200

201 202
  /**
   * GtkAdjustment:page-increment:
203
   *
204
   * The page increment of the adjustment.
205
   *
206 207
   * Since: 2.4
   */
208 209 210 211 212
  g_object_class_install_property (gobject_class,
                                   PROP_PAGE_INCREMENT,
                                   g_param_spec_double ("page-increment",
							P_("Page Increment"),
							P_("The page increment of the adjustment"),
213 214 215
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
							0.0,
216
							GTK_PARAM_READWRITE));
217

218 219
  /**
   * GtkAdjustment:page-size:
220 221
   *
   * The page size of the adjustment.
222
   * Note that the page-size is irrelevant and should be set to zero
223
   * if the adjustment is used for a simple scalar value, e.g. in a
224
   * #GtkSpinButton.
225
   *
226 227
   * Since: 2.4
   */
228 229 230 231 232
  g_object_class_install_property (gobject_class,
                                   PROP_PAGE_SIZE,
                                   g_param_spec_double ("page-size",
							P_("Page Size"),
							P_("The page size of the adjustment"),
233 234 235
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
							0.0,
236
							GTK_PARAM_READWRITE));
237

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

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

static void
gtk_adjustment_init (GtkAdjustment *adjustment)
{
273
  adjustment->priv = gtk_adjustment_get_instance_private (adjustment);
Elliot Lee's avatar
Elliot Lee committed
274 275
}

276
static void
Michael Natterer's avatar
Michael Natterer committed
277 278 279 280
gtk_adjustment_get_property (GObject    *object,
                             guint       prop_id,
                             GValue     *value,
                             GParamSpec *pspec)
281 282
{
  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
283
  GtkAdjustmentPrivate *priv = adjustment->priv;
284 285 286 287

  switch (prop_id)
    {
    case PROP_VALUE:
288
      g_value_set_double (value, priv->value);
289 290
      break;
    case PROP_LOWER:
291
      g_value_set_double (value, priv->lower);
292 293
      break;
    case PROP_UPPER:
294
      g_value_set_double (value, priv->upper);
295 296
      break;
    case PROP_STEP_INCREMENT:
297
      g_value_set_double (value, priv->step_increment);
298 299
      break;
    case PROP_PAGE_INCREMENT:
300
      g_value_set_double (value, priv->page_increment);
301 302
      break;
    case PROP_PAGE_SIZE:
303
      g_value_set_double (value, priv->page_size);
304 305 306 307 308 309 310 311
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
Michael Natterer's avatar
Michael Natterer committed
312 313 314 315
gtk_adjustment_set_property (GObject      *object,
                             guint         prop_id,
                             const GValue *value,
                             GParamSpec   *pspec)
316 317 318
{
  GtkAdjustment *adjustment = GTK_ADJUSTMENT (object);
  gdouble double_value = g_value_get_double (value);
319
  GtkAdjustmentPrivate *priv = adjustment->priv;
320 321 322 323

  switch (prop_id)
    {
    case PROP_VALUE:
Michael Natterer's avatar
Michael Natterer committed
324
      gtk_adjustment_set_value (adjustment, double_value);
325 326
      break;
    case PROP_LOWER:
327
      priv->lower = double_value;
328 329
      break;
    case PROP_UPPER:
330
      priv->upper = double_value;
331 332
      break;
    case PROP_STEP_INCREMENT:
333
      priv->step_increment = double_value;
334 335
      break;
    case PROP_PAGE_INCREMENT:
336
      priv->page_increment = double_value;
337 338
      break;
    case PROP_PAGE_SIZE:
339
      priv->page_size = double_value;
340 341 342 343 344 345 346
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

347 348 349 350 351 352 353 354 355 356 357 358 359
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);
  g_object_notify (G_OBJECT (adjustment), "value");
}

Michael Natterer's avatar
Michael Natterer committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
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)
385 386
    {
      adjustment_changed_stamp++;
387
      emit_changed (GTK_ADJUSTMENT (object));
388
    }
Michael Natterer's avatar
Michael Natterer committed
389 390
}

391 392
/**
 * gtk_adjustment_new:
393 394 395 396 397 398
 * @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
399 400 401
 *
 * Creates a new #GtkAdjustment.
 *
402
 * Returns: a new #GtkAdjustment
403
 */
404
GtkAdjustment *
405 406 407 408 409 410
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
411
{
412
  return g_object_new (GTK_TYPE_ADJUSTMENT,
413 414 415 416
		       "lower", lower,
		       "upper", upper,
		       "step-increment", step_increment,
		       "page-increment", page_increment,
417
		       "page-size", page_size,
418
		       "value", value,
419
		       NULL);
Elliot Lee's avatar
Elliot Lee committed
420
}
421

422 423 424 425
/**
 * gtk_adjustment_get_value:
 * @adjustment: a #GtkAdjustment
 *
426 427
 * Gets the current value of the adjustment.
 * See gtk_adjustment_set_value().
428
 *
429
 * Returns: The current value of the adjustment
430 431 432 433
 **/
gdouble
gtk_adjustment_get_value (GtkAdjustment *adjustment)
{
Michael Natterer's avatar
Michael Natterer committed
434
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);
435

436
  return adjustment->priv->value;
437 438
}

439 440 441 442 443 444 445 446 447 448 449
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;
}

450 451 452 453
static void
adjustment_set_value (GtkAdjustment *adjustment,
                      gdouble        value)
{
454
  if (adjustment->priv->value != value)
455 456
    {
      adjustment->priv->value = value;
457
      emit_value_changed (adjustment);
458 459 460
    }
}

461
static void gtk_adjustment_on_frame_clock_update (GdkFrameClock *clock,
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
                                                  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);
    }
}

490 491 492 493 494 495 496 497 498 499 500
/* 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;
}

501
static void
502
gtk_adjustment_on_frame_clock_update (GdkFrameClock *clock,
503
                                      GtkAdjustment *adjustment)
504 505
{
  GtkAdjustmentPrivate *priv = adjustment->priv;
506 507 508
  gint64 now;

  now = gdk_frame_clock_get_frame_time (clock);
509 510 511 512 513 514 515 516 517 518 519 520

  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);
521
      gtk_adjustment_end_updating (adjustment);
522 523 524 525
    }
}

static void
526 527 528
gtk_adjustment_set_value_internal (GtkAdjustment *adjustment,
                                   gdouble        value,
                                   gboolean       animate)
529 530 531
{
  GtkAdjustmentPrivate *priv = adjustment->priv;

532 533 534 535 536
  /* 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);
537

538
  if (animate && priv->duration != 0 && priv->clock != NULL)
539
    {
540
      if (priv->tick_id && priv->target == value)
541 542
        return;

543
      priv->source = priv->value;
544
      priv->target = value;
545 546
      priv->start_time = gdk_frame_clock_get_frame_time (priv->clock);
      priv->end_time = priv->start_time + 1000 * priv->duration;
547
      gtk_adjustment_begin_updating (adjustment);
548 549
    }
  else
550 551 552 553
    {
      gtk_adjustment_end_updating (adjustment);
      adjustment_set_value (adjustment, value);
    }
554 555
}

556 557
/**
 * gtk_adjustment_set_value:
558 559
 * @adjustment: a #GtkAdjustment
 * @value: the new value
560 561
 *
 * Sets the #GtkAdjustment value. The value is clamped to lie between
562
 * #GtkAdjustment:lower and #GtkAdjustment:upper.
563
 *
564 565 566
 * 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.
567
 */
568
void
Michael Natterer's avatar
Michael Natterer committed
569 570
gtk_adjustment_set_value (GtkAdjustment *adjustment,
			  gdouble        value)
571 572 573
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

574 575
  gtk_adjustment_set_value_internal (adjustment, value, FALSE);
}
576

577 578 579 580 581
void
gtk_adjustment_animate_to_value (GtkAdjustment *adjustment,
			         gdouble        value)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
582

583
  gtk_adjustment_set_value_internal (adjustment, value, TRUE);
584 585
}

586 587 588 589 590 591
/**
 * gtk_adjustment_get_lower:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the minimum value of the adjustment.
 *
592
 * Returns: The current minimum value of the adjustment
593 594 595 596 597 598 599 600
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_lower (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

601
  return adjustment->priv->lower;
602 603 604 605 606 607 608 609 610 611
}

/**
 * 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
612 613 614 615 616 617
 * 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.
618 619 620
 *
 * Alternatively, using a single g_object_set() for all the properties
 * to change, or using gtk_adjustment_configure() has the same effect
621
 * of compressing #GtkAdjustment::changed emissions.
622 623 624 625 626 627 628 629 630
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_lower (GtkAdjustment *adjustment,
                          gdouble        lower)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

631
  if (lower != adjustment->priv->lower)
632 633 634 635 636 637 638 639 640
    g_object_set (adjustment, "lower", lower, NULL);
}

/**
 * gtk_adjustment_get_upper:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the maximum value of the adjustment.
 *
641
 * Returns: The current maximum value of the adjustment
642 643 644 645 646 647 648 649
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_upper (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

650
  return adjustment->priv->upper;
651 652 653 654 655 656 657 658 659
}

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

675
  if (upper != adjustment->priv->upper)
676 677 678 679 680 681 682 683 684
    g_object_set (adjustment, "upper", upper, NULL);
}

/**
 * gtk_adjustment_get_step_increment:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the step increment of the adjustment.
 *
685
 * Returns: The current step increment of the adjustment.
686 687 688 689 690 691 692 693
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_step_increment (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

694
  return adjustment->priv->step_increment;
695 696 697 698 699 700 701 702 703 704
}

/**
 * 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
705 706
 * emissions of the #GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
707 708 709 710 711 712 713 714 715
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_step_increment (GtkAdjustment *adjustment,
                                   gdouble        step_increment)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

716
  if (step_increment != adjustment->priv->step_increment)
717 718 719 720 721 722 723 724 725
    g_object_set (adjustment, "step-increment", step_increment, NULL);
}

/**
 * gtk_adjustment_get_page_increment:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the page increment of the adjustment.
 *
726
 * Returns: The current page increment of the adjustment
727 728 729 730 731 732 733 734
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_page_increment (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

735
  return adjustment->priv->page_increment;
736 737 738 739 740 741 742 743 744 745
}

/**
 * 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
746 747
 * emissions of the #GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
748 749 750 751 752 753 754 755 756
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_page_increment (GtkAdjustment *adjustment,
                                   gdouble        page_increment)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

757
  if (page_increment != adjustment->priv->page_increment)
758 759 760 761 762 763 764 765 766
    g_object_set (adjustment, "page-increment", page_increment, NULL);
}

/**
 * gtk_adjustment_get_page_size:
 * @adjustment: a #GtkAdjustment
 *
 * Retrieves the page size of the adjustment.
 *
767
 * Returns: The current page size of the adjustment
768 769 770 771 772 773 774 775
 *
 * Since: 2.14
 **/
gdouble
gtk_adjustment_get_page_size (GtkAdjustment *adjustment)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), 0.0);

776
  return adjustment->priv->page_size;
777 778 779 780 781 782 783 784 785 786
}

/**
 * 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
787 788
 * emissions of the GtkAdjustment::changed signal when setting
 * multiple adjustment properties.
789 790 791 792 793 794 795 796 797
 *
 * Since: 2.14
 **/
void
gtk_adjustment_set_page_size (GtkAdjustment *adjustment,
                              gdouble        page_size)
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

798
  if (page_size != adjustment->priv->page_size)
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    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.
 *
814 815 816 817
 * 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.
818 819 820 821 822 823 824 825 826 827 828 829
 *
 * Since: 2.14
 **/
void
gtk_adjustment_configure (GtkAdjustment *adjustment,
                          gdouble        value,
                          gdouble        lower,
                          gdouble        upper,
                          gdouble        step_increment,
                          gdouble        page_increment,
                          gdouble        page_size)
{
830
  GtkAdjustmentPrivate *priv;
831 832 833 834 835
  gboolean value_changed = FALSE;
  guint64 old_stamp = adjustment_changed_stamp;

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

836 837
  priv = adjustment->priv;

838 839 840 841 842 843 844 845 846 847
  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);

848 849 850 851 852
  /* 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);
853

854
  if (value != priv->value)
855 856 857 858
    {
      /* set value manually to make sure "changed" is emitted with the
       * new value in place and is emitted before "value-changed"
       */
859
      priv->value = value;
860 861 862 863 864 865
      value_changed = TRUE;
    }

  g_object_thaw_notify (G_OBJECT (adjustment));

  if (old_stamp == adjustment_changed_stamp)
866
    emit_changed (adjustment); /* force emission before ::value-changed */
867 868

  if (value_changed)
869
    emit_value_changed (adjustment);
870 871
}

872 873 874 875 876 877
/**
 * 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
878
 * changed any of the #GtkAdjustment properties other than the value.
879 880 881
 *
 * Deprecated: 3.18: GTK+ emits #GtkAdjustment::changed itself whenever any
 *    of the properties (other than value) change
882
 */
883
void
Michael Natterer's avatar
Michael Natterer committed
884
gtk_adjustment_changed (GtkAdjustment *adjustment)
885 886
{
  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
887
  emit_changed (adjustment);
888 889
}

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

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

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

932 933 934 935
  priv = adjustment->priv;

  lower = CLAMP (lower, priv->lower, priv->upper);
  upper = CLAMP (upper, priv->lower, priv->upper);
936 937 938

  need_emission = FALSE;

939
  if (priv->value + priv->page_size < upper)
940
    {
941
      priv->value = upper - priv->page_size;
942 943
      need_emission = TRUE;
    }
944
  if (priv->value > lower)
945
    {
946
      priv->value = lower;
947 948 949 950
      need_emission = TRUE;
    }

  if (need_emission)
951
    emit_value_changed (adjustment);
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 990 991 992 993 994 995 996

/**
 * 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;
}

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
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);
    }

1024
  priv->duration = duration;
1025
}
1026

Matthias Clasen's avatar
Matthias Clasen committed
1027
guint
1028 1029 1030 1031
gtk_adjustment_get_animation_duration (GtkAdjustment *adjustment)
{
  return adjustment->priv->duration;
}
1032 1033 1034 1035 1036 1037

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