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

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

26
#include "config.h"
27

Elliot Lee's avatar
Elliot Lee committed
28
#include <stdio.h>
29
#include <math.h>
30

31
#include "gtkrange.h"
32
#include "gtkrangeprivate.h"
33

34
#include "gtkadjustmentprivate.h"
35 36
#include "gtkcolorscaleprivate.h"
#include "gtkintl.h"
37
#include "gtkmain.h"
38
#include "gtkmarshalers.h"
39
#include "gtkorientableprivate.h"
40
#include "gtkprivate.h"
41
#include "gtkscale.h"
42
#include "gtkscrollbar.h"
43
#include "gtktypebuiltins.h"
44
#include "gtkwindow.h"
45
#include "a11y/gtkrangeaccessible.h"
46 47 48 49 50 51 52

/**
 * SECTION:gtkrange
 * @Short_description: Base class for widgets which visualize an adjustment
 * @Title: GtkRange
 *
 * #GtkRange is the common base class for widgets which visualize an
53
 * adjustment, e.g #GtkScale or #GtkScrollbar.
54 55 56
 *
 * Apart from signals for monitoring the parameters of the adjustment,
 * #GtkRange provides properties and methods for influencing the sensitivity
57 58
 * of the “steppers”. It also provides properties and methods for setting a
 * “fill level” on range widgets. See gtk_range_set_fill_level().
59 60 61
 */


62 63
#define SCROLL_DELAY_FACTOR 5    /* Scroll repeat multiplier */
#define UPDATE_DELAY        300  /* Delay for queued update */
64 65
#define TIMEOUT_INITIAL     500
#define TIMEOUT_REPEAT      50
66
#define ZOOM_HOLD_TIME      500
67
#define AUTOSCROLL_FACTOR   20
68
#define SCROLL_EDGE_SIZE 15
Elliot Lee's avatar
Elliot Lee committed
69

70
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
71

72 73 74 75 76 77 78 79 80 81 82
typedef enum {
  MOUSE_OUTSIDE,
  MOUSE_STEPPER_A,
  MOUSE_STEPPER_B,
  MOUSE_STEPPER_C,
  MOUSE_STEPPER_D,
  MOUSE_TROUGH,
  MOUSE_SLIDER,
  MOUSE_WIDGET /* inside widget but not in any of the above GUI elements */
} MouseLocation;

83
struct _GtkRangePrivate
84 85 86 87 88 89
{
  MouseLocation      mouse_location;
  /* last mouse coords we got, or -1 if mouse is outside the range */
  gint  mouse_x;
  gint  mouse_y;
  MouseLocation      grab_location;   /* "grabbed" mouse location, OUTSIDE for no grab */
90

91
  GtkRangeStepTimer *timer;
92

93 94 95 96 97
  GtkAdjustment     *adjustment;
  GtkSensitivityType lower_sensitivity;
  GtkSensitivityType upper_sensitivity;

  GdkRectangle       range_rect;     /* Area of entire stepper + trough assembly in widget->window coords */
98
  /* These are in widget->window coordinates */
99 100 101 102 103 104 105
  GdkRectangle       stepper_a;
  GdkRectangle       stepper_b;
  GdkRectangle       stepper_c;
  GdkRectangle       stepper_d;
  GdkRectangle       trough;         /* The trough rectangle is the area the thumb can slide in, not the entire range_rect */
  GdkRectangle       slider;
  GdkWindow         *event_window;
106

107 108
  GQuark             slider_detail_quark;
  GQuark             stepper_detail_quark[4];
109

110
  GtkOrientation     orientation;
111 112 113 114 115 116 117 118 119

  gdouble  fill_level;
  gdouble *marks;

  gint *mark_pos;
  gint  min_slider_size;
  gint  n_marks;
  gint  round_digits;                /* Round off value to this many digits, -1 for no rounding */
  gint  slide_initial_slider_position;
120
  gint  slide_initial_coordinate_delta;
121 122
  gint  slider_start;                /* Slider range along the long dimension, in widget->window coords */
  gint  slider_end;
123

124 125 126 127 128 129 130 131 132 133 134
  /* Steppers are: < > ---- < >
   *               a b      c d
   */
  guint has_stepper_a          : 1;
  guint has_stepper_b          : 1;
  guint has_stepper_c          : 1;
  guint has_stepper_d          : 1;

  guint flippable              : 1;
  guint inverted               : 1;
  guint need_recalc            : 1;
135
  guint recalc_marks           : 1;
136 137
  guint slider_size_fixed      : 1;
  guint trough_click_forward   : 1;  /* trough click was on the forward side of slider */
138 139

  /* Stepper sensitivity */
140 141
  guint lower_sensitive        : 1;
  guint upper_sensitive        : 1;
142

143 144 145
  /* The range has an origin, should be drawn differently. Used by GtkScale */
  guint has_origin             : 1;

146 147
  /* Whether we're doing fine adjustment */
  guint zoom                   : 1;
148
  guint zoom_set               : 1;
149
  GtkGesture *long_press_gesture;
150 151
  GtkScrollType autoscroll_mode;
  guint autoscroll_id;
152

153 154 155
  GtkGesture *multipress_gesture;
  GtkGesture *drag_gesture;

156
  /* Fill level */
157
  guint show_fill_level        : 1;
158
  guint restrict_to_fill_level : 1;
159 160 161

  /* Whether dragging is ongoing */
  guint in_drag                : 1;
162
};
163

164

165 166 167 168 169 170 171 172 173
enum {
  PROP_0,
  PROP_ORIENTATION,
  PROP_ADJUSTMENT,
  PROP_INVERTED,
  PROP_LOWER_STEPPER_SENSITIVITY,
  PROP_UPPER_STEPPER_SENSITIVITY,
  PROP_SHOW_FILL_LEVEL,
  PROP_RESTRICT_TO_FILL_LEVEL,
174 175
  PROP_FILL_LEVEL,
  PROP_ROUND_DIGITS
176
};
177

178 179 180 181 182 183
enum {
  VALUE_CHANGED,
  ADJUST_BOUNDS,
  MOVE_SLIDER,
  CHANGE_VALUE,
  LAST_SIGNAL
184 185
};

186 187 188 189 190 191
typedef enum {
  STEPPER_A,
  STEPPER_B,
  STEPPER_C,
  STEPPER_D
} Stepper;
192

193 194 195 196 197 198 199 200
static void gtk_range_set_property   (GObject          *object,
                                      guint             prop_id,
                                      const GValue     *value,
                                      GParamSpec       *pspec);
static void gtk_range_get_property   (GObject          *object,
                                      guint             prop_id,
                                      GValue           *value,
                                      GParamSpec       *pspec);
201
static void gtk_range_destroy        (GtkWidget        *widget);
202 203 204 205 206 207 208 209
static void gtk_range_get_preferred_width
                                     (GtkWidget        *widget,
                                      gint             *minimum,
                                      gint             *natural);
static void gtk_range_get_preferred_height
                                     (GtkWidget        *widget,
                                      gint             *minimum,
                                      gint             *natural);
210 211 212 213
static void gtk_range_size_allocate  (GtkWidget        *widget,
                                      GtkAllocation    *allocation);
static void gtk_range_realize        (GtkWidget        *widget);
static void gtk_range_unrealize      (GtkWidget        *widget);
214 215
static void gtk_range_map            (GtkWidget        *widget);
static void gtk_range_unmap          (GtkWidget        *widget);
216 217
static gboolean gtk_range_draw       (GtkWidget        *widget,
                                      cairo_t          *cr);
218 219 220 221 222 223 224 225 226 227 228

static void gtk_range_multipress_gesture_pressed  (GtkGestureMultiPress *gesture,
                                                   guint                 n_press,
                                                   gdouble               x,
                                                   gdouble               y,
                                                   GtkRange             *range);
static void gtk_range_multipress_gesture_released (GtkGestureMultiPress *gesture,
                                                   guint                 n_press,
                                                   gdouble               x,
                                                   gdouble               y,
                                                   GtkRange             *range);
229 230 231 232
static void gtk_range_drag_gesture_begin          (GtkGestureDrag       *gesture,
                                                   gdouble               offset_x,
                                                   gdouble               offset_y,
                                                   GtkRange             *range);
233 234 235 236 237 238 239 240 241 242 243 244 245 246
static void gtk_range_drag_gesture_update         (GtkGestureDrag       *gesture,
                                                   gdouble               offset_x,
                                                   gdouble               offset_y,
                                                   GtkRange             *range);
static void gtk_range_drag_gesture_end            (GtkGestureDrag       *gesture,
                                                   gdouble               offset_x,
                                                   gdouble               offset_y,
                                                   GtkRange             *range);
static void gtk_range_long_press_gesture_pressed  (GtkGestureLongPress  *gesture,
                                                   gdouble               x,
                                                   gdouble               y,
                                                   GtkRange             *range);


247
static gboolean gtk_range_scroll_event   (GtkWidget        *widget,
248
                                      GdkEventScroll   *event);
249 250
static gboolean gtk_range_event       (GtkWidget       *widget,
                                       GdkEvent        *event);
251
static void gtk_range_style_updated  (GtkWidget        *widget);
252 253 254
static void update_slider_position   (GtkRange	       *range,
				      gint              mouse_x,
				      gint              mouse_y);
255
static void stop_scrolling           (GtkRange         *range);
256 257

/* Range methods */
258

259
static void gtk_range_move_slider              (GtkRange         *range,
260 261 262
                                                GtkScrollType     scroll);

/* Internals */
263
static gboolean      gtk_range_scroll                   (GtkRange      *range,
264 265
                                                         GtkScrollType  scroll);
static gboolean      gtk_range_update_mouse_location    (GtkRange      *range);
266 267
static void          gtk_range_calc_layout              (GtkRange      *range,
							 gdouble	adjustment_value);
268
static void          gtk_range_calc_marks               (GtkRange      *range);
269 270 271 272
static void          gtk_range_get_props                (GtkRange      *range,
                                                         gint          *slider_width,
                                                         gint          *stepper_size,
                                                         gint          *trough_border,
273
                                                         gint          *stepper_spacing,
274
                                                         gboolean      *trough_under_steppers,
275 276
							 gint          *arrow_displacement_x,
							 gint	       *arrow_displacement_y);
277 278 279 280 281 282 283 284
static void          gtk_range_calc_request             (GtkRange      *range,
                                                         gint           slider_width,
                                                         gint           stepper_size,
                                                         gint           trough_border,
                                                         gint           stepper_spacing,
                                                         GdkRectangle  *range_rect,
                                                         GtkBorder     *border,
                                                         gint          *n_steppers_p,
285 286
                                                         gboolean      *has_steppers_ab,
                                                         gboolean      *has_steppers_cd,
287 288 289 290 291 292 293 294 295 296
                                                         gint          *slider_length_p);
static void          gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
                                                         gpointer       data);
static void          gtk_range_adjustment_changed       (GtkAdjustment *adjustment,
                                                         gpointer       data);
static void          gtk_range_add_step_timer           (GtkRange      *range,
                                                         GtkScrollType  step);
static void          gtk_range_remove_step_timer        (GtkRange      *range);
static GdkRectangle* get_area                           (GtkRange      *range,
                                                         MouseLocation  location);
297 298 299
static gboolean      gtk_range_real_change_value        (GtkRange      *range,
                                                         GtkScrollType  scroll,
                                                         gdouble        value);
300 301
static gboolean      gtk_range_key_press                (GtkWidget     *range,
							 GdkEventKey   *event);
302

Elliot Lee's avatar
Elliot Lee committed
303

304
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET,
305
                                  G_ADD_PRIVATE (GtkRange)
306 307 308
                                  G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                         NULL))

309
static guint signals[LAST_SIGNAL];
Elliot Lee's avatar
Elliot Lee committed
310 311 312 313 314


static void
gtk_range_class_init (GtkRangeClass *class)
{
Alexander Larsson's avatar
Alexander Larsson committed
315
  GObjectClass   *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
316 317
  GtkWidgetClass *widget_class;

Alexander Larsson's avatar
Alexander Larsson committed
318
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
319 320
  widget_class = (GtkWidgetClass*) class;

Alexander Larsson's avatar
Alexander Larsson committed
321 322
  gobject_class->set_property = gtk_range_set_property;
  gobject_class->get_property = gtk_range_get_property;
323

324
  widget_class->destroy = gtk_range_destroy;
325 326
  widget_class->get_preferred_width = gtk_range_get_preferred_width;
  widget_class->get_preferred_height = gtk_range_get_preferred_height;
327 328
  widget_class->size_allocate = gtk_range_size_allocate;
  widget_class->realize = gtk_range_realize;
329
  widget_class->unrealize = gtk_range_unrealize;
330 331
  widget_class->map = gtk_range_map;
  widget_class->unmap = gtk_range_unmap;
332
  widget_class->draw = gtk_range_draw;
333
  widget_class->event = gtk_range_event;
334
  widget_class->scroll_event = gtk_range_scroll_event;
335
  widget_class->style_updated = gtk_range_style_updated;
336
  widget_class->key_press_event = gtk_range_key_press;
337 338

  class->move_slider = gtk_range_move_slider;
339
  class->change_value = gtk_range_real_change_value;
340

341 342
  class->slider_detail = "slider";
  class->stepper_detail = "stepper";
343

Matthias Clasen's avatar
Matthias Clasen committed
344 345
  /**
   * GtkRange::value-changed:
346
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
347 348 349
   *
   * Emitted when the range value changes.
   */
350
  signals[VALUE_CHANGED] =
351
    g_signal_new (I_("value-changed"),
Manish Singh's avatar
Manish Singh committed
352
                  G_TYPE_FROM_CLASS (gobject_class),
353 354 355
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, value_changed),
                  NULL, NULL,
356
                  _gtk_marshal_VOID__VOID,
357
                  G_TYPE_NONE, 0);
358 359 360 361 362

  /**
   * GtkRange::adjust-bounds:
   * @range: the #GtkRange that received the signal
   * @value: the value before we clamp
363 364 365
   *
   * Emitted before clamping a value, to give the application a
   * chance to adjust the bounds.
366
   */
367
  signals[ADJUST_BOUNDS] =
368
    g_signal_new (I_("adjust-bounds"),
Manish Singh's avatar
Manish Singh committed
369
                  G_TYPE_FROM_CLASS (gobject_class),
370 371 372 373 374 375 376
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, adjust_bounds),
                  NULL, NULL,
                  _gtk_marshal_VOID__DOUBLE,
                  G_TYPE_NONE, 1,
                  G_TYPE_DOUBLE);
  
Matthias Clasen's avatar
Matthias Clasen committed
377 378
  /**
   * GtkRange::move-slider:
379
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
380 381 382 383
   * @step: how to move the slider
   *
   * Virtual function that moves the slider. Used for keybindings.
   */
384
  signals[MOVE_SLIDER] =
385
    g_signal_new (I_("move-slider"),
Manish Singh's avatar
Manish Singh committed
386
                  G_TYPE_FROM_CLASS (gobject_class),
387 388 389
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkRangeClass, move_slider),
                  NULL, NULL,
390
                  _gtk_marshal_VOID__ENUM,
391 392
                  G_TYPE_NONE, 1,
                  GTK_TYPE_SCROLL_TYPE);
393 394 395

  /**
   * GtkRange::change-value:
396
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
397 398
   * @scroll: the type of scroll action that was performed
   * @value: the new value resulting from the scroll action
399
   *
400
   * The #GtkRange::change-value signal is emitted when a scroll action is
401 402 403 404 405 406 407 408
   * performed on a range.  It allows an application to determine the
   * type of scroll event that occurred and the resultant new value.
   * The application can handle the event itself and return %TRUE to
   * prevent further processing.  Or, by returning %FALSE, it can pass
   * the event to other handlers until the default GTK+ handler is
   * reached.
   *
   * The value parameter is unrounded.  An application that overrides
409 410 411
   * the GtkRange::change-value signal is responsible for clamping the
   * value to the desired number of decimal digits; the default GTK+
   * handler clamps the value based on #GtkRange:round-digits.
412 413
   *
   * It is not possible to use delayed update policies in an overridden
414
   * #GtkRange::change-value handler.
415
   *
416 417 418
   * Returns: %TRUE to prevent other handlers from being invoked for
   *     the signal, %FALSE to propagate the signal further
   *
419 420 421
   * Since: 2.6
   */
  signals[CHANGE_VALUE] =
422
    g_signal_new (I_("change-value"),
423 424 425 426 427 428 429 430
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, change_value),
                  _gtk_boolean_handled_accumulator, NULL,
                  _gtk_marshal_BOOLEAN__ENUM_DOUBLE,
                  G_TYPE_BOOLEAN, 2,
                  GTK_TYPE_SCROLL_TYPE,
                  G_TYPE_DOUBLE);
Tim Janik's avatar
Tim Janik committed
431

432 433 434 435
  g_object_class_override_property (gobject_class,
                                    PROP_ORIENTATION,
                                    "orientation");

436 437 438
  g_object_class_install_property (gobject_class,
                                   PROP_ADJUSTMENT,
                                   g_param_spec_object ("adjustment",
439 440
							P_("Adjustment"),
							P_("The GtkAdjustment that contains the current value of this range object"),
441
                                                        GTK_TYPE_ADJUSTMENT,
442
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
443

444 445 446
  g_object_class_install_property (gobject_class,
                                   PROP_INVERTED,
                                   g_param_spec_boolean ("inverted",
447 448
							P_("Inverted"),
							P_("Invert direction slider moves to increase range value"),
449
                                                         FALSE,
450
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
451 452 453 454 455 456 457 458

  g_object_class_install_property (gobject_class,
                                   PROP_LOWER_STEPPER_SENSITIVITY,
                                   g_param_spec_enum ("lower-stepper-sensitivity",
						      P_("Lower stepper sensitivity"),
						      P_("The sensitivity policy for the stepper that points to the adjustment's lower side"),
						      GTK_TYPE_SENSITIVITY_TYPE,
						      GTK_SENSITIVITY_AUTO,
459
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
460 461 462 463 464 465 466 467

  g_object_class_install_property (gobject_class,
                                   PROP_UPPER_STEPPER_SENSITIVITY,
                                   g_param_spec_enum ("upper-stepper-sensitivity",
						      P_("Upper stepper sensitivity"),
						      P_("The sensitivity policy for the stepper that points to the adjustment's upper side"),
						      GTK_TYPE_SENSITIVITY_TYPE,
						      GTK_SENSITIVITY_AUTO,
468
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
469

470 471 472
  /**
   * GtkRange:show-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
473
   * The show-fill-level property controls whether fill level indicator
474 475 476 477 478 479 480 481 482 483 484
   * graphics are displayed on the trough. See
   * gtk_range_set_show_fill_level().
   *
   * Since: 2.12
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_SHOW_FILL_LEVEL,
                                   g_param_spec_boolean ("show-fill-level",
                                                         P_("Show Fill Level"),
                                                         P_("Whether to display a fill level indicator graphics on trough."),
                                                         FALSE,
485
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
486 487 488 489

  /**
   * GtkRange:restrict-to-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
490
   * The restrict-to-fill-level property controls whether slider
491
   * movement is restricted to an upper boundary set by the
Matthias Clasen's avatar
Matthias Clasen committed
492
   * fill level. See gtk_range_set_restrict_to_fill_level().
493 494 495 496 497 498 499 500 501
   *
   * Since: 2.12
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_RESTRICT_TO_FILL_LEVEL,
                                   g_param_spec_boolean ("restrict-to-fill-level",
                                                         P_("Restrict to Fill Level"),
                                                         P_("Whether to restrict the upper boundary to the fill level."),
                                                         TRUE,
502
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

  /**
   * GtkRange:fill-level:
   *
   * The fill level (e.g. prebuffering of a network stream).
   * See gtk_range_set_fill_level().
   *
   * Since: 2.12
   **/
  g_object_class_install_property (gobject_class,
                                   PROP_FILL_LEVEL,
                                   g_param_spec_double ("fill-level",
							P_("Fill Level"),
							P_("The fill level."),
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
                                                        G_MAXDOUBLE,
520
                                                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
521

522 523 524 525 526 527 528 529 530 531 532 533
  /**
   * GtkRange:round-digits:
   *
   * The number of digits to round the value to when
   * it changes, or -1. See #GtkRange::change-value.
   *
   * Since: 2.24
   */
  g_object_class_install_property (gobject_class,
                                   PROP_ROUND_DIGITS,
                                   g_param_spec_int ("round-digits",
                                                     P_("Round Digits"),
Matthias Clasen's avatar
Matthias Clasen committed
534
                                                     P_("The number of digits to round the value to."),
535 536
                                                     -1, G_MAXINT, -1,
                                                     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
537

538
  gtk_widget_class_install_style_property (widget_class,
539
					   g_param_spec_int ("slider-width",
540 541
							     P_("Slider Width"),
							     P_("Width of scrollbar or scale thumb"),
542 543
							     0,
							     G_MAXINT,
544
							     14,
545
							     GTK_PARAM_READABLE));
546
  gtk_widget_class_install_style_property (widget_class,
547
					   g_param_spec_int ("trough-border",
548 549
                                                             P_("Trough Border"),
                                                             P_("Spacing between thumb/steppers and outer trough bevel"),
550 551 552
                                                             0,
                                                             G_MAXINT,
                                                             1,
553
                                                             GTK_PARAM_READABLE));
554
  gtk_widget_class_install_style_property (widget_class,
555
					   g_param_spec_int ("stepper-size",
556 557
							     P_("Stepper Size"),
							     P_("Length of step buttons at ends"),
558 559
							     0,
							     G_MAXINT,
560
							     14,
561
							     GTK_PARAM_READABLE));
562 563 564 565 566 567
  /**
   * GtkRange:stepper-spacing:
   *
   * The spacing between the stepper buttons and thumb. Note that
   * stepper-spacing won't have any effect if there are no steppers.
   */
568
  gtk_widget_class_install_style_property (widget_class,
569
					   g_param_spec_int ("stepper-spacing",
570 571
							     P_("Stepper Spacing"),
							     P_("Spacing between step buttons and thumb"),
572
                                                             0,
573
							     G_MAXINT,
574
							     0,
575
							     GTK_PARAM_READABLE));
576
  gtk_widget_class_install_style_property (widget_class,
577
					   g_param_spec_int ("arrow-displacement-x",
578 579
							     P_("Arrow X Displacement"),
							     P_("How far in the x direction to move the arrow when the button is depressed"),
580 581 582
							     G_MININT,
							     G_MAXINT,
							     0,
583
							     GTK_PARAM_READABLE));
584
  gtk_widget_class_install_style_property (widget_class,
585
					   g_param_spec_int ("arrow-displacement-y",
586 587
							     P_("Arrow Y Displacement"),
							     P_("How far in the y direction to move the arrow when the button is depressed"),
588 589 590
							     G_MININT,
							     G_MAXINT,
							     0,
591
							     GTK_PARAM_READABLE));
592

593 594 595 596
  /**
   * GtkRange:trough-under-steppers:
   *
   * Whether to draw the trough across the full length of the range or
597
   * to exclude the steppers and their spacing.
598 599 600 601 602 603
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boolean ("trough-under-steppers",
                                                                 P_("Trough Under Steppers"),
604
                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
605 606
                                                                 TRUE,
                                                                 GTK_PARAM_READABLE));
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621
  /**
   * GtkRange:arrow-scaling:
   *
   * The arrow size proportion relative to the scroll button size.
   *
   * Since: 2.14
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_float ("arrow-scaling",
							       P_("Arrow scaling"),
							       P_("Arrow scaling with regard to scroll button size"),
							       0.0, 1.0, 0.5,
							       GTK_PARAM_READABLE));

622
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
623 624
}

625
static void
Alexander Larsson's avatar
Alexander Larsson committed
626 627 628 629
gtk_range_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
630
{
631
  GtkRange *range = GTK_RANGE (object);
632
  GtkRangePrivate *priv = range->priv;
633

Alexander Larsson's avatar
Alexander Larsson committed
634
  switch (prop_id)
635
    {
636
    case PROP_ORIENTATION:
637 638 639
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
640

641 642 643 644 645
          priv->slider_detail_quark = 0;
          priv->stepper_detail_quark[0] = 0;
          priv->stepper_detail_quark[1] = 0;
          priv->stepper_detail_quark[2] = 0;
          priv->stepper_detail_quark[3] = 0;
646

647 648 649 650
          _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));
          gtk_widget_queue_resize (GTK_WIDGET (range));
          g_object_notify_by_pspec (object, pspec);
        }
651
      break;
652 653 654
    case PROP_ADJUSTMENT:
      gtk_range_set_adjustment (range, g_value_get_object (value));
      break;
655 656 657
    case PROP_INVERTED:
      gtk_range_set_inverted (range, g_value_get_boolean (value));
      break;
658 659 660 661 662 663
    case PROP_LOWER_STEPPER_SENSITIVITY:
      gtk_range_set_lower_stepper_sensitivity (range, g_value_get_enum (value));
      break;
    case PROP_UPPER_STEPPER_SENSITIVITY:
      gtk_range_set_upper_stepper_sensitivity (range, g_value_get_enum (value));
      break;
664 665 666 667 668 669 670 671 672
    case PROP_SHOW_FILL_LEVEL:
      gtk_range_set_show_fill_level (range, g_value_get_boolean (value));
      break;
    case PROP_RESTRICT_TO_FILL_LEVEL:
      gtk_range_set_restrict_to_fill_level (range, g_value_get_boolean (value));
      break;
    case PROP_FILL_LEVEL:
      gtk_range_set_fill_level (range, g_value_get_double (value));
      break;
673 674 675
    case PROP_ROUND_DIGITS:
      gtk_range_set_round_digits (range, g_value_get_int (value));
      break;
676
    default:
Alexander Larsson's avatar
Alexander Larsson committed
677
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
678 679 680 681 682
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
683 684 685 686
gtk_range_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
687
{
688
  GtkRange *range = GTK_RANGE (object);
689
  GtkRangePrivate *priv = range->priv;
690

Alexander Larsson's avatar
Alexander Larsson committed
691
  switch (prop_id)
692
    {
693
    case PROP_ORIENTATION:
694
      g_value_set_enum (value, priv->orientation);
695
      break;
696
    case PROP_ADJUSTMENT:
697
      g_value_set_object (value, priv->adjustment);
698
      break;
699
    case PROP_INVERTED:
700
      g_value_set_boolean (value, priv->inverted);
701
      break;
702 703 704 705 706 707
    case PROP_LOWER_STEPPER_SENSITIVITY:
      g_value_set_enum (value, gtk_range_get_lower_stepper_sensitivity (range));
      break;
    case PROP_UPPER_STEPPER_SENSITIVITY:
      g_value_set_enum (value, gtk_range_get_upper_stepper_sensitivity (range));
      break;
708 709 710 711 712 713 714 715 716
    case PROP_SHOW_FILL_LEVEL:
      g_value_set_boolean (value, gtk_range_get_show_fill_level (range));
      break;
    case PROP_RESTRICT_TO_FILL_LEVEL:
      g_value_set_boolean (value, gtk_range_get_restrict_to_fill_level (range));
      break;
    case PROP_FILL_LEVEL:
      g_value_set_double (value, gtk_range_get_fill_level (range));
      break;
717 718 719
    case PROP_ROUND_DIGITS:
      g_value_set_int (value, gtk_range_get_round_digits (range));
      break;
720
    default:
Alexander Larsson's avatar
Alexander Larsson committed
721
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
722 723 724 725
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
726 727 728
static void
gtk_range_init (GtkRange *range)
{
729
  GtkRangePrivate *priv;
730

731
  range->priv = gtk_range_get_instance_private (range);
732 733
  priv = range->priv;

734
  gtk_widget_set_has_window (GTK_WIDGET (range), FALSE);
735

736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  priv->adjustment = NULL;
  priv->inverted = FALSE;
  priv->flippable = FALSE;
  priv->min_slider_size = 1;
  priv->has_stepper_a = FALSE;
  priv->has_stepper_b = FALSE;
  priv->has_stepper_c = FALSE;
  priv->has_stepper_d = FALSE;
  priv->need_recalc = TRUE;
  priv->round_digits = -1;
  priv->mouse_location = MOUSE_OUTSIDE;
  priv->mouse_x = -1;
  priv->mouse_y = -1;
  priv->grab_location = MOUSE_OUTSIDE;
  priv->lower_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->upper_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->lower_sensitive = TRUE;
  priv->upper_sensitive = TRUE;
755
  priv->has_origin = FALSE;
756 757 758 759
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
760

761 762
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));

763 764 765 766 767 768 769 770 771 772 773 774 775 776
  /* Note: Order is important here.
   * The ::drag-begin handler relies on the state set up by the
   * multipress ::pressed handler. Gestures are handling events
   * in the oppposite order in which they are added to their
   * widget.
   */
  priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (range));
  g_signal_connect (priv->drag_gesture, "drag-begin",
                    G_CALLBACK (gtk_range_drag_gesture_begin), range);
  g_signal_connect (priv->drag_gesture, "drag-update",
                    G_CALLBACK (gtk_range_drag_gesture_update), range);
  g_signal_connect (priv->drag_gesture, "drag-end",
                    G_CALLBACK (gtk_range_drag_gesture_end), range);

777
  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (range));
778
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
779 780 781 782 783 784 785 786 787
  g_signal_connect (priv->multipress_gesture, "pressed",
                    G_CALLBACK (gtk_range_multipress_gesture_pressed), range);
  g_signal_connect (priv->multipress_gesture, "released",
                    G_CALLBACK (gtk_range_multipress_gesture_released), range);

  priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (range));
  gtk_gesture_group (priv->drag_gesture, priv->long_press_gesture);
  g_signal_connect (priv->long_press_gesture, "pressed",
                    G_CALLBACK (gtk_range_long_press_gesture_pressed), range);
Elliot Lee's avatar
Elliot Lee committed
788 789
}

790 791 792 793
/**
 * gtk_range_get_adjustment:
 * @range: a #GtkRange
 * 
794
 * Get the #GtkAdjustment which is the “model” object for #GtkRange.
795 796 797 798
 * See gtk_range_set_adjustment() for details.
 * The return value does not have a reference added, so should not
 * be unreferenced.
 * 
799
 * Returns: (transfer none): a #GtkAdjustment
800
 **/
Elliot Lee's avatar
Elliot Lee committed
801 802 803
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
804
  GtkRangePrivate *priv;
805

Elliot Lee's avatar
Elliot Lee committed
806 807
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

808 809 810
  priv = range->priv;

  if (!priv->adjustment)
811 812
    gtk_range_set_adjustment (range, NULL);

813
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
814 815
}

816 817 818 819 820
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
821
 * Sets the adjustment to be used as the “model” object for this range
822 823 824 825 826 827 828
 * widget. The adjustment indicates the current range value, the
 * minimum and maximum range values, the step/page increments used
 * for keybindings and scrolling, and the page size. The page size
 * is normally 0 for #GtkScale and nonzero for #GtkScrollbar, and
 * indicates the size of the visible area of the widget being scrolled.
 * The page size affects the size of the scrollbar slider.
 **/
Elliot Lee's avatar
Elliot Lee committed
829 830 831 832
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
833
  GtkRangePrivate *priv;
834

Elliot Lee's avatar
Elliot Lee committed
835
  g_return_if_fail (GTK_IS_RANGE (range));
836 837 838

  priv = range->priv;

839
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
840
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
841 842
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
843

844
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
845
    {
846
      if (priv->adjustment)
847
	{
848
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
849 850
						gtk_range_adjustment_changed,
						range);
851
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
852 853
						gtk_range_adjustment_value_changed,
						range);
854
	  g_object_unref (priv->adjustment);
855
	}
856

857
      priv->adjustment = adjustment;
858
      g_object_ref_sink (adjustment);
859
      
Manish Singh's avatar
Manish Singh committed
860 861 862
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
863
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
864 865
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
866
      
867
      gtk_range_adjustment_changed (adjustment, range);
868
      g_object_notify (G_OBJECT (range), "adjustment");
Elliot Lee's avatar
Elliot Lee committed
869 870 871
    }
}

872 873 874 875 876 877 878 879 880 881
/**
 * gtk_range_set_inverted:
 * @range: a #GtkRange
 * @setting: %TRUE to invert the range
 *
 * Ranges normally move from lower to higher values as the
 * slider moves from top to bottom or left to right. Inverted
 * ranges have higher values at the top or on the right rather than
 * on the bottom or left.
 **/
882 883 884 885
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
886
  GtkRangePrivate *priv;
887

888
  g_return_if_fail (GTK_IS_RANGE (range));
889 890 891

  priv = range->priv;

892 893
  setting = setting != FALSE;

894
  if (setting != priv->inverted)
895
    {
896
      priv->inverted = setting;
897
      g_object_notify (G_OBJECT (range), "inverted");
898 899 900 901
      gtk_widget_queue_resize (GTK_WIDGET (range));
    }
}

902 903 904 905 906 907
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
908
 * Returns: %TRUE if the range is inverted
909
 **/
910 911 912 913 914
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

915
  return range->priv->inverted;
916 917
}

918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
/**
 * gtk_range_set_flippable:
 * @range: a #GtkRange
 * @flippable: %TRUE to make the range flippable
 *
 * If a range is flippable, it will switch its direction if it is
 * horizontal and its direction is %GTK_TEXT_DIR_RTL.
 *
 * See gtk_widget_get_direction().
 *
 * Since: 2.18
 **/
void
gtk_range_set_flippable (GtkRange *range,
                         gboolean  flippable)
{
934
  GtkRangePrivate *priv;
935

936 937
  g_return_if_fail (GTK_IS_RANGE (range));

938 939
  priv = range->priv;

940 941
  flippable = flippable ? TRUE : FALSE;

942
  if (flippable != priv->flippable)
943
    {
944
      priv->flippable = flippable;
945 946 947 948 949 950 951 952 953 954 955

      gtk_widget_queue_draw (GTK_WIDGET (range));
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
956
 * Returns: %TRUE if the range is flippable
957 958 959 960 961 962 963 964
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

965
  return range->priv->flippable;
966 967
}

968 969 970 971 972
/**
 * gtk_range_set_slider_size_fixed:
 * @range: a #GtkRange
 * @size_fixed: %TRUE to make the slider size constant
 *
973 974
 * Sets whether the range’s slider has a fixed size, or a size that
 * depends on its adjustment’s page size.
975 976 977 978 979 980 981 982 983
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_slider_size_fixed (GtkRange *range,
                                 gboolean  size_fixed)
{
984
  GtkRangePrivate *priv;
985

986 987
  g_return_if_fail (GTK_IS_RANGE (range));

988 989 990
  priv = range->priv;

  if (size_fixed != priv->slider_size_fixed)
991
    {
992
      priv->slider_size_fixed = size_fixed ? TRUE : FALSE;
993

994
      if (priv->adjustment && gtk_widget_get_mapped (GTK_WIDGET (range)))
995
        {
996 997
          priv->need_recalc = TRUE;
          gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
998 999
          gtk_widget_queue_draw (GTK_WIDGET (range));
        }
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
    }
}

/**
 * gtk_range_get_slider_size_fixed:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_slider_size_fixed().
 *
1011
 * Returns: whether the range’s slider has a fixed size.
1012 1013 1014 1015 1016 1017 1018 1019
 *
 * Since: 2.20
 **/
gboolean
gtk_range_get_slider_size_fixed (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1020
  return range->priv->slider_size_fixed;
1021 1022 1023 1024 1025
}

/**
 * gtk_range_set_min_slider_size:
 * @range: a #GtkRange
1026
 * @min_size: The slider’s minimum size
1027
 *
1028
 * Sets the minimum size of the range’s slider.
1029 1030 1031 1032 1033 1034 1035
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_min_slider_size (GtkRange *range,
1036
                               gint      min_size)
1037
{
1038
  GtkRangePrivate *priv;
1039

1040 1041 1042
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (min_size > 0);

1043 1044 1045
  priv = range->priv;

  if (min_size != priv->min_slider_size)
1046
    {
1047
      priv->min_slider_size = min_size;
1048

1049 1050 1051
      if (gtk_widget_is_drawable (GTK_WIDGET (range)))
        {
          priv->need_recalc = TRUE;
1052
          gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1053 1054
          gtk_widget_queue_draw (GTK_WIDGET (range));
        }
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
    }
}

/**
 * gtk_range_get_min_slider_size:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_min_slider_size().
 *
1066
 * Returns: The minimum size of the range’s slider.
1067 1068 1069 1070 1071 1072 1073 1074
 *
 * Since: 2.20
 **/
gint
gtk_range_get_min_slider_size (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1075
  return range->priv->min_slider_size;
1076 1077 1078 1079 1080
}

/**
 * gtk_range_get_range_rect:
 * @range: a #GtkRange
1081
 * @range_rect: (out): return location for the range rectangle
1082
 *
1083
 * This function returns the area that contains the range’s trough
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
 * and its steppers, in widget->window coordinates.
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_get_range_rect (GtkRange     *range,
                          GdkRectangle *range_rect)
{
1094
  GtkRangePrivate *priv;
1095

1096 1097 1098
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (range_rect != NULL);

1099 1100
  priv = range->priv;

1101
  gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1102

1103
  *range_rect = priv->range_rect;
1104 1105 1106 1107 1108
}

/**
 * gtk_range_get_slider_range:
 * @range: a #GtkRange
1109 1110 1111 1112
 * @slider_start: (out) (allow-none): return location for the slider's
 *     start, or %NULL
 * @slider_end: (out) (allow-none): return location for the slider's
 *     end, or %NULL
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
 *
 * This function returns sliders range along the long dimension,
 * in widget->window coordinates.
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_get_slider_range (GtkRange *range,
                            gint     *slider_start,
                            gint     *slider_end)
{
1126
  GtkRangePrivate *priv;
1127

1128 1129
  g_return_if_fail (GTK_IS_RANGE (range));

1130 1131
  priv = range->priv;

1132
  gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1133 1134

  if (slider_start)
1135
    *slider_start = priv->slider_start;
1136 1137

  if (slider_end)
1138
    *slider_end = priv->slider_end;
1139 1140
}

1141 1142 1143
/**
 * gtk_range_set_lower_stepper_sensitivity:
 * @range:       a #GtkRange
1144
 * @sensitivity: the lower stepper’s sensitivity policy.
1145 1146
 *
 * Sets the sensitivity policy for the stepper that points to the
1147
 * 'lower' end of the GtkRange’s adjustment.
1148
 *
Matthias Clasen's avatar
Matthias Clasen committed
1149
 * Since: 2.10
1150 1151 1152 1153 1154
 **/
void
gtk_range_set_lower_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1155
  GtkRangePrivate *priv;
1156

1157 1158
  g_return_if_fail (GTK_IS_RANGE (range));

1159 1160 1161
  priv = range->priv;

  if (priv->lower_sensitivity != sensitivity)
1162
    {
1163
      priv->lower_sensitivity = sensitivity;
1164

1165
      priv->need_recalc = TRUE;
1166
      gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1167
      gtk_widget_queue_draw (GTK_WIDGET (range));
1168

1169 1170 1171 1172 1173 1174 1175 1176 1177
      g_object_notify (G_OBJECT (range), "lower-stepper-sensitivity");
    }
}

/**
 * gtk_range_get_lower_stepper_sensitivity:
 * @range: a #GtkRange
 *
 * Gets the sensitivity policy for the stepper that points to the
1178
 * 'lower' end of the GtkRange’s adjustment.
1179
 *
1180
 * Returns: The lower stepper’s sensitivity policy.
1181 1182 1183 1184 1185 1186 1187 1188
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_lower_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1189
  return range->priv->lower_sensitivity;
1190 1191 1192 1193 1194
}

/**
 * gtk_range_set_upper_stepper_sensitivity:
 * @range:       a #GtkRange
1195
 * @sensitivity: the upper stepper’s sensitivity policy.
1196 1197
 *
 * Sets the sensitivity policy for the stepper that points to the
1198
 * 'upper' end of the GtkRange’s adjustment.
1199
 *
Matthias Clasen's avatar
Matthias Clasen committed
1200
 * Since: 2.10
1201 1202 1203 1204 1205
 **/
void
gtk_range_set_upper_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1206
  GtkRangePrivate *priv;
1207

1208 1209
  g_return_if_fail (GTK_IS_RANGE (range));

1210 1211 1212
  priv = range->priv;

  if (priv->upper_sensitivity != sensitivity)
1213
    {
1214
      priv->upper_sensitivity = sensitivity;
1215

1216
      priv->need_recalc = TRUE;
1217
      gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1218
      gtk_widget_queue_draw (GTK_WIDGET (range));
1219

1220 1221 1222 1223 1224 1225 1226 1227 1228
      g_object_notify (G_OBJECT (range), "upper-stepper-sensitivity");
    }
}

/**
 * gtk_range_get_upper_stepper_sensitivity:
 * @range: a #GtkRange
 *
 * Gets the sensitivity policy for the stepper that points to the
1229
 * 'upper' end of the GtkRange’s adjustment.
1230
 *
1231
 * Returns: The upper stepper’s sensitivity policy.
1232 1233 1234 1235 1236 1237 1238 1239
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_upper_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1240
  return range->priv->upper_sensitivity;
1241 1242
}

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
/**
 * gtk_range_set_increments:
 * @range: a #GtkRange
 * @step: step size
 * @page: page size
 *
 * Sets the step and page sizes for the range.
 * The step size is used when the user clicks the #GtkScrollbar
 * arrows or moves #GtkScale via arrow keys. The page size
 * is used for example when moving via Page Up or Page Down keys.
 **/
void
gtk_range_set_increments (GtkRange *range,
                          gdouble   step,
                          gdouble   page)
{
1259
  GtkAdjustment *adjustment;
1260

1261 1262
  g_return_if_fail (GTK_IS_RANGE (range));

1263
  adjustment = range->priv->adjustment;
1264

1265 1266 1267 1268 1269 1270 1271
  gtk_adjustment_configure (adjustment,
                            gtk_adjustment_get_value (adjustment),
                            gtk_adjustment_get_lower (adjustment),
                            gtk_adjustment_get_upper (adjustment),
                            step,
                            page,
                            gtk_adjustment_get_page_size (adjustment));
1272 1273 1274 1275 1276 1277 1278 1279 1280
}

/**
 * gtk_range_set_range:
 * @range: a #GtkRange
 * @min: minimum range value
 * @max: maximum range value
 * 
 * Sets the allowable values in the #GtkRange, and clamps the range
1281 1282
 * value to be between @min and @max. (If the range has a non-zero
 * page size, it is clamped between @min and @max - page-size.)
1283 1284 1285 1286 1287 1288
 **/
void
gtk_range_set_range (GtkRange *range,
                     gdouble   min,
                     gdouble   max)
{
1289
  GtkRangePrivate *priv;
1290
  GtkAdjustment *adjustment;
1291 1292 1293
  gdouble value;
  
  g_return_if_fail (GTK_IS_RANGE (range));
1294
  g_return_if_fail (min <= max);
1295

1296
  priv = range->priv;
1297
  adjustment = priv->adjustment;
1298

1299
  value = gtk_adjustment_get_value (adjustment);
1300
  if (priv->restrict_to_fill_level)
1301
    value = MIN (value, MAX (gtk_adjustment_get_lower (adjustment),
1302
                             priv->fill_level));
1303

1304 1305 1306 1307 1308 1309 1310
  gtk_adjustment_configure (adjustment,
                            value,
                            min,
                            max,
                            gtk_adjustment_get_step_increment (adjustment),
                            gtk_adjustment_get_page_increment (adjustment),
                            gtk_adjustment_get_page_size (adjustment));
1311 1312 1313 1314 1315 1316 1317 1318 1319
}

/**
 * gtk_range_set_value:
 * @range: a #GtkRange
 * @value: new value of the range
 *
 * Sets the current value of the range; if the value is outside the
 * minimum or maximum range values, it will be clamped to fit inside
Matthias Clasen's avatar
Matthias Clasen committed
1320 1321
 * them. The range emits the #GtkRange::value-changed signal if the 
 * value changes.
1322 1323 1324 1325 1326
 **/
void
gtk_range_set_value (GtkRange *range,
                     gdouble   value)
{
1327
  GtkRangePrivate *priv;