gtkrange.c 127 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 "gtkgesturelongpressprivate.h"
38
#include "gtkmain.h"
39
#include "gtkmarshalers.h"
40
#include "gtkorientableprivate.h"
41
#include "gtkprivate.h"
42
#include "gtkscale.h"
43
#include "gtkscrollbar.h"
44
#include "gtktypebuiltins.h"
45
#include "gtkwindow.h"
46
#include "gtkwidgetprivate.h"
47
#include "a11y/gtkrangeaccessible.h"
48 49 50 51 52 53 54

/**
 * 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
55
 * adjustment, e.g #GtkScale or #GtkScrollbar.
56 57 58
 *
 * Apart from signals for monitoring the parameters of the adjustment,
 * #GtkRange provides properties and methods for influencing the sensitivity
59 60
 * of the “steppers”. It also provides properties and methods for setting a
 * “fill level” on range widgets. See gtk_range_set_fill_level().
61 62 63
 */


64
#define TIMEOUT_INITIAL     500
Benjamin Otte's avatar
Benjamin Otte committed
65
#define TIMEOUT_REPEAT      250
66
#define AUTOSCROLL_FACTOR   20
Benjamin Otte's avatar
Benjamin Otte committed
67
#define SCROLL_EDGE_SIZE    15
Elliot Lee's avatar
Elliot Lee committed
68

69
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
70

71 72 73 74 75 76 77 78 79 80 81
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;

82
struct _GtkRangePrivate
83 84 85 86 87 88
{
  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 */
89

90
  GtkRangeStepTimer *timer;
91

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

  GdkRectangle       range_rect;     /* Area of entire stepper + trough assembly in widget->window coords */
97
  /* These are in widget->window coordinates */
98 99 100 101 102 103 104
  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;
105

106
  GtkOrientation     orientation;
107 108 109 110 111 112 113 114 115

  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;
116
  gint  slide_initial_coordinate_delta;
117

118 119 120 121 122 123 124 125 126 127
  /* 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;
128
  guint recalc_marks           : 1;
129 130
  guint slider_size_fixed      : 1;
  guint trough_click_forward   : 1;  /* trough click was on the forward side of slider */
131 132

  /* Stepper sensitivity */
133 134
  guint lower_sensitive        : 1;
  guint upper_sensitive        : 1;
135

136 137 138
  /* The range has an origin, should be drawn differently. Used by GtkScale */
  guint has_origin             : 1;

139 140
  /* Whether we're doing fine adjustment */
  guint zoom                   : 1;
141

142
  /* Fill level */
143
  guint show_fill_level        : 1;
144
  guint restrict_to_fill_level : 1;
145 146 147

  /* Whether dragging is ongoing */
  guint in_drag                : 1;
148 149 150 151 152 153 154

  GtkGesture *long_press_gesture;
  GtkGesture *multipress_gesture;
  GtkGesture *drag_gesture;

  GtkScrollType autoscroll_mode;
  guint autoscroll_id;
155
};
156

157

158 159 160 161 162 163 164 165
enum {
  PROP_0,
  PROP_ADJUSTMENT,
  PROP_INVERTED,
  PROP_LOWER_STEPPER_SENSITIVITY,
  PROP_UPPER_STEPPER_SENSITIVITY,
  PROP_SHOW_FILL_LEVEL,
  PROP_RESTRICT_TO_FILL_LEVEL,
166
  PROP_FILL_LEVEL,
167 168 169
  PROP_ROUND_DIGITS,
  PROP_ORIENTATION,
  LAST_PROP = PROP_ORIENTATION
170
};
171

172 173 174 175 176 177
enum {
  VALUE_CHANGED,
  ADJUST_BOUNDS,
  MOVE_SLIDER,
  CHANGE_VALUE,
  LAST_SIGNAL
178 179
};

180 181 182 183 184 185
typedef enum {
  STEPPER_A,
  STEPPER_B,
  STEPPER_C,
  STEPPER_D
} Stepper;
186

187 188 189 190 191 192 193 194
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);
195
static void gtk_range_destroy        (GtkWidget        *widget);
196 197 198 199 200 201 202 203
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);
204 205 206 207
static void gtk_range_size_allocate  (GtkWidget        *widget,
                                      GtkAllocation    *allocation);
static void gtk_range_realize        (GtkWidget        *widget);
static void gtk_range_unrealize      (GtkWidget        *widget);
208 209
static void gtk_range_map            (GtkWidget        *widget);
static void gtk_range_unmap          (GtkWidget        *widget);
210 211
static gboolean gtk_range_draw       (GtkWidget        *widget,
                                      cairo_t          *cr);
212 213 214 215 216 217 218 219 220 221 222

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);
223 224 225 226
static void gtk_range_drag_gesture_begin          (GtkGestureDrag       *gesture,
                                                   gdouble               offset_x,
                                                   gdouble               offset_y,
                                                   GtkRange             *range);
227 228 229 230 231 232 233 234 235 236 237 238 239 240
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);


241
static gboolean gtk_range_scroll_event   (GtkWidget        *widget,
242
                                      GdkEventScroll   *event);
243 244
static gboolean gtk_range_event       (GtkWidget       *widget,
                                       GdkEvent        *event);
245 246 247
static void update_slider_position   (GtkRange	       *range,
				      gint              mouse_x,
				      gint              mouse_y);
248
static void stop_scrolling           (GtkRange         *range);
249 250
static void add_autoscroll           (GtkRange         *range);
static void remove_autoscroll        (GtkRange         *range);
251 252

/* Range methods */
253

254
static void gtk_range_move_slider              (GtkRange         *range,
255 256 257
                                                GtkScrollType     scroll);

/* Internals */
258 259 260
static void          gtk_range_compute_slider_position  (GtkRange      *range,
                                                         gdouble        adjustment_value,
                                                         GdkRectangle  *slider_rect);
261
static gboolean      gtk_range_scroll                   (GtkRange      *range,
262
                                                         GtkScrollType  scroll);
263
static void          gtk_range_update_mouse_location    (GtkRange      *range);
264 265
static void          gtk_range_calc_slider              (GtkRange      *range);
static void          gtk_range_calc_stepper_sensitivity (GtkRange      *range);
266
static void          gtk_range_calc_layout              (GtkRange      *range);
267
static void          gtk_range_calc_marks               (GtkRange      *range);
268 269 270 271
static void          gtk_range_get_props                (GtkRange      *range,
                                                         gint          *slider_width,
                                                         gint          *stepper_size,
                                                         gint          *trough_border,
272
                                                         gint          *stepper_spacing,
273
                                                         gboolean      *trough_under_steppers,
274 275
							 gint          *arrow_displacement_x,
							 gint	       *arrow_displacement_y);
276 277 278 279 280 281 282 283
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,
284
                                                         gboolean      *has_steppers_ab,
285
                                                         gboolean      *has_steppers_cd);
286 287 288 289 290 291 292
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);
293
static void          gtk_range_queue_draw_location      (GtkRange      *range,
294
                                                         MouseLocation  location);
295 296 297
static gboolean      gtk_range_real_change_value        (GtkRange      *range,
                                                         GtkScrollType  scroll,
                                                         gdouble        value);
298 299
static gboolean      gtk_range_key_press                (GtkWidget     *range,
							 GdkEventKey   *event);
300

Elliot Lee's avatar
Elliot Lee committed
301

302
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET,
303
                                  G_ADD_PRIVATE (GtkRange)
304 305 306
                                  G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                         NULL))

307
static guint signals[LAST_SIGNAL];
308
static GParamSpec *properties[LAST_PROP];
Elliot Lee's avatar
Elliot Lee committed
309 310 311 312

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

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

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

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

  class->move_slider = gtk_range_move_slider;
336
  class->change_value = gtk_range_real_change_value;
337

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

  /**
   * GtkRange::adjust-bounds:
   * @range: the #GtkRange that received the signal
   * @value: the value before we clamp
357 358 359
   *
   * Emitted before clamping a value, to give the application a
   * chance to adjust the bounds.
360
   */
361
  signals[ADJUST_BOUNDS] =
362
    g_signal_new (I_("adjust-bounds"),
Manish Singh's avatar
Manish Singh committed
363
                  G_TYPE_FROM_CLASS (gobject_class),
364 365 366 367 368 369
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, adjust_bounds),
                  NULL, NULL,
                  _gtk_marshal_VOID__DOUBLE,
                  G_TYPE_NONE, 1,
                  G_TYPE_DOUBLE);
370

Matthias Clasen's avatar
Matthias Clasen committed
371 372
  /**
   * GtkRange::move-slider:
373
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
374 375 376 377
   * @step: how to move the slider
   *
   * Virtual function that moves the slider. Used for keybindings.
   */
378
  signals[MOVE_SLIDER] =
379
    g_signal_new (I_("move-slider"),
Manish Singh's avatar
Manish Singh committed
380
                  G_TYPE_FROM_CLASS (gobject_class),
381 382 383
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkRangeClass, move_slider),
                  NULL, NULL,
384
                  _gtk_marshal_VOID__ENUM,
385 386
                  G_TYPE_NONE, 1,
                  GTK_TYPE_SCROLL_TYPE);
387 388 389

  /**
   * GtkRange::change-value:
390
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
391 392
   * @scroll: the type of scroll action that was performed
   * @value: the new value resulting from the scroll action
393
   *
394
   * The #GtkRange::change-value signal is emitted when a scroll action is
395 396 397 398 399 400 401 402
   * 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
403 404 405
   * 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.
406 407
   *
   * It is not possible to use delayed update policies in an overridden
408
   * #GtkRange::change-value handler.
409
   *
410 411 412
   * Returns: %TRUE to prevent other handlers from being invoked for
   *     the signal, %FALSE to propagate the signal further
   *
413 414 415
   * Since: 2.6
   */
  signals[CHANGE_VALUE] =
416
    g_signal_new (I_("change-value"),
417 418 419 420 421 422 423 424
                  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
425

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
  g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");

  properties[PROP_ADJUSTMENT] =
      g_param_spec_object ("adjustment",
                           P_("Adjustment"),
                           P_("The GtkAdjustment that contains the current value of this range object"),
                           GTK_TYPE_ADJUSTMENT,
                           GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT);

  properties[PROP_INVERTED] =
      g_param_spec_boolean ("inverted",
                            P_("Inverted"),
                            P_("Invert direction slider moves to increase range value"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  properties[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,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  properties[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,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
457

458 459 460
  /**
   * GtkRange:show-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
461
   * The show-fill-level property controls whether fill level indicator
462 463 464 465 466
   * graphics are displayed on the trough. See
   * gtk_range_set_show_fill_level().
   *
   * Since: 2.12
   **/
467 468 469 470 471 472
  properties[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,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
473 474 475 476

  /**
   * GtkRange:restrict-to-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
477
   * The restrict-to-fill-level property controls whether slider
478
   * movement is restricted to an upper boundary set by the
Matthias Clasen's avatar
Matthias Clasen committed
479
   * fill level. See gtk_range_set_restrict_to_fill_level().
480 481 482
   *
   * Since: 2.12
   **/
483 484 485 486 487 488
  properties[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,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
489 490 491 492 493 494 495 496 497

  /**
   * GtkRange:fill-level:
   *
   * The fill level (e.g. prebuffering of a network stream).
   * See gtk_range_set_fill_level().
   *
   * Since: 2.12
   **/
498 499 500 501 502 503 504
  properties[PROP_FILL_LEVEL] =
      g_param_spec_double ("fill-level",
                           P_("Fill Level"),
                           P_("The fill level."),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           G_MAXDOUBLE,
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
505

506 507 508 509 510 511 512 513
  /**
   * GtkRange:round-digits:
   *
   * The number of digits to round the value to when
   * it changes, or -1. See #GtkRange::change-value.
   *
   * Since: 2.24
   */
514 515 516 517 518 519 520 521 522
  properties[PROP_ROUND_DIGITS] =
      g_param_spec_int ("round-digits",
                        P_("Round Digits"),
                        P_("The number of digits to round the value to."),
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, LAST_PROP, properties);
523

524
  gtk_widget_class_install_style_property (widget_class,
525
					   g_param_spec_int ("slider-width",
526 527
							     P_("Slider Width"),
							     P_("Width of scrollbar or scale thumb"),
528 529
							     0,
							     G_MAXINT,
530
							     14,
531
							     GTK_PARAM_READABLE));
532
  gtk_widget_class_install_style_property (widget_class,
533
					   g_param_spec_int ("trough-border",
534 535
                                                             P_("Trough Border"),
                                                             P_("Spacing between thumb/steppers and outer trough bevel"),
536 537 538
                                                             0,
                                                             G_MAXINT,
                                                             1,
539
                                                             GTK_PARAM_READABLE));
540
  gtk_widget_class_install_style_property (widget_class,
541
					   g_param_spec_int ("stepper-size",
542 543
							     P_("Stepper Size"),
							     P_("Length of step buttons at ends"),
544 545
							     0,
							     G_MAXINT,
546
							     14,
547
							     GTK_PARAM_READABLE));
548 549 550 551 552 553
  /**
   * 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.
   */
554
  gtk_widget_class_install_style_property (widget_class,
555
					   g_param_spec_int ("stepper-spacing",
556 557
							     P_("Stepper Spacing"),
							     P_("Spacing between step buttons and thumb"),
558
                                                             0,
559
							     G_MAXINT,
560
							     0,
561
							     GTK_PARAM_READABLE));
562
  gtk_widget_class_install_style_property (widget_class,
563
					   g_param_spec_int ("arrow-displacement-x",
564 565
							     P_("Arrow X Displacement"),
							     P_("How far in the x direction to move the arrow when the button is depressed"),
566 567 568
							     G_MININT,
							     G_MAXINT,
							     0,
569
							     GTK_PARAM_READABLE));
570
  gtk_widget_class_install_style_property (widget_class,
571
					   g_param_spec_int ("arrow-displacement-y",
572 573
							     P_("Arrow Y Displacement"),
							     P_("How far in the y direction to move the arrow when the button is depressed"),
574 575 576
							     G_MININT,
							     G_MAXINT,
							     0,
577
							     GTK_PARAM_READABLE));
578

579 580 581 582
  /**
   * GtkRange:trough-under-steppers:
   *
   * Whether to draw the trough across the full length of the range or
583
   * to exclude the steppers and their spacing.
584 585 586 587 588 589
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boolean ("trough-under-steppers",
                                                                 P_("Trough Under Steppers"),
590
                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
591 592
                                                                 TRUE,
                                                                 GTK_PARAM_READABLE));
593

594 595 596 597 598 599 600 601 602 603 604 605 606 607
  /**
   * 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));

608
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
609 610
}

611
static void
Alexander Larsson's avatar
Alexander Larsson committed
612 613 614 615
gtk_range_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
616
{
617
  GtkRange *range = GTK_RANGE (object);
618
  GtkRangePrivate *priv = range->priv;
619

Alexander Larsson's avatar
Alexander Larsson committed
620
  switch (prop_id)
621
    {
622
    case PROP_ORIENTATION:
623 624 625
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
626

627 628 629 630
          _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));
          gtk_widget_queue_resize (GTK_WIDGET (range));
          g_object_notify_by_pspec (object, pspec);
        }
631
      break;
632 633 634
    case PROP_ADJUSTMENT:
      gtk_range_set_adjustment (range, g_value_get_object (value));
      break;
635 636 637
    case PROP_INVERTED:
      gtk_range_set_inverted (range, g_value_get_boolean (value));
      break;
638 639 640 641 642 643
    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;
644 645 646 647 648 649 650 651 652
    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;
653 654 655
    case PROP_ROUND_DIGITS:
      gtk_range_set_round_digits (range, g_value_get_int (value));
      break;
656
    default:
Alexander Larsson's avatar
Alexander Larsson committed
657
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
658 659 660 661 662
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
663 664 665 666
gtk_range_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
667
{
668
  GtkRange *range = GTK_RANGE (object);
669
  GtkRangePrivate *priv = range->priv;
670

Alexander Larsson's avatar
Alexander Larsson committed
671
  switch (prop_id)
672
    {
673
    case PROP_ORIENTATION:
674
      g_value_set_enum (value, priv->orientation);
675
      break;
676
    case PROP_ADJUSTMENT:
677
      g_value_set_object (value, priv->adjustment);
678
      break;
679
    case PROP_INVERTED:
680
      g_value_set_boolean (value, priv->inverted);
681
      break;
682 683 684 685 686 687
    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;
688 689 690 691 692 693 694 695 696
    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;
697 698 699
    case PROP_ROUND_DIGITS:
      g_value_set_int (value, gtk_range_get_round_digits (range));
      break;
700
    default:
Alexander Larsson's avatar
Alexander Larsson committed
701
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
702 703 704 705
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
706 707 708
static void
gtk_range_init (GtkRange *range)
{
709
  GtkRangePrivate *priv;
710

711
  range->priv = gtk_range_get_instance_private (range);
712 713
  priv = range->priv;

714
  gtk_widget_set_has_window (GTK_WIDGET (range), FALSE);
715

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
  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->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;
734
  priv->has_origin = FALSE;
735 736 737 738
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
739

740 741
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));

742 743 744 745 746 747 748
  /* 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));
749
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
750 751 752 753 754 755 756
  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);

757
  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (range));
758
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
759 760 761 762 763 764
  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));
765
  g_object_set (priv->long_press_gesture, "delay-factor", 2.0, NULL);
766 767 768
  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
769 770
}

771 772 773 774
/**
 * gtk_range_get_adjustment:
 * @range: a #GtkRange
 * 
775
 * Get the #GtkAdjustment which is the “model” object for #GtkRange.
776 777 778 779
 * See gtk_range_set_adjustment() for details.
 * The return value does not have a reference added, so should not
 * be unreferenced.
 * 
780
 * Returns: (transfer none): a #GtkAdjustment
781
 **/
Elliot Lee's avatar
Elliot Lee committed
782 783 784
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
785
  GtkRangePrivate *priv;
786

Elliot Lee's avatar
Elliot Lee committed
787 788
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

789 790 791
  priv = range->priv;

  if (!priv->adjustment)
792 793
    gtk_range_set_adjustment (range, NULL);

794
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
795 796
}

797 798 799 800 801
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
802
 * Sets the adjustment to be used as the “model” object for this range
803 804 805 806 807 808 809
 * 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
810 811 812 813
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
814
  GtkRangePrivate *priv;
815

Elliot Lee's avatar
Elliot Lee committed
816
  g_return_if_fail (GTK_IS_RANGE (range));
817 818 819

  priv = range->priv;

820
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
821
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
822 823
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
824

825
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
826
    {
827
      if (priv->adjustment)
828
	{
829
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
830 831
						gtk_range_adjustment_changed,
						range);
832
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
833 834
						gtk_range_adjustment_value_changed,
						range);
835
	  g_object_unref (priv->adjustment);
836
	}
837

838
      priv->adjustment = adjustment;
839
      g_object_ref_sink (adjustment);
840
      
Manish Singh's avatar
Manish Singh committed
841 842 843
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
844
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
845 846
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
847
      
848
      gtk_range_adjustment_changed (adjustment, range);
849
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_ADJUSTMENT]);
Elliot Lee's avatar
Elliot Lee committed
850 851 852
    }
}

853 854 855 856 857 858 859 860 861 862
/**
 * 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.
 **/
863 864 865 866
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
867
  GtkRangePrivate *priv;
868

869
  g_return_if_fail (GTK_IS_RANGE (range));
870 871 872

  priv = range->priv;

873 874
  setting = setting != FALSE;

875
  if (setting != priv->inverted)
876
    {
877
      priv->inverted = setting;
878
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_INVERTED]);
879 880 881 882
      gtk_widget_queue_resize (GTK_WIDGET (range));
    }
}

883 884 885 886 887 888
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
889
 * Returns: %TRUE if the range is inverted
890
 **/
891 892 893 894 895
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

896
  return range->priv->inverted;
897 898
}

899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
/**
 * 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)
{
915
  GtkRangePrivate *priv;
916

917 918
  g_return_if_fail (GTK_IS_RANGE (range));

919 920
  priv = range->priv;

921 922
  flippable = flippable ? TRUE : FALSE;

923
  if (flippable != priv->flippable)
924
    {
925
      priv->flippable = flippable;
926 927 928 929 930 931 932 933 934 935 936

      gtk_widget_queue_draw (GTK_WIDGET (range));
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
937
 * Returns: %TRUE if the range is flippable
938 939 940 941 942 943 944 945
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

946
  return range->priv->flippable;
947 948
}

949 950 951 952 953
/**
 * gtk_range_set_slider_size_fixed:
 * @range: a #GtkRange
 * @size_fixed: %TRUE to make the slider size constant
 *
954 955
 * Sets whether the range’s slider has a fixed size, or a size that
 * depends on its adjustment’s page size.
956 957 958 959 960 961 962 963 964
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_slider_size_fixed (GtkRange *range,
                                 gboolean  size_fixed)
{
965
  GtkRangePrivate *priv;
966

967 968
  g_return_if_fail (GTK_IS_RANGE (range));

969 970 971
  priv = range->priv;

  if (size_fixed != priv->slider_size_fixed)
972
    {
973
      priv->slider_size_fixed = size_fixed ? TRUE : FALSE;
974

975
      if (priv->adjustment && gtk_widget_get_mapped (GTK_WIDGET (range)))
976
        gtk_range_calc_slider (range);
977 978 979 980 981 982 983 984 985 986 987
    }
}

/**
 * gtk_range_get_slider_size_fixed:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_slider_size_fixed().
 *
988
 * Returns: whether the range’s slider has a fixed size.
989 990 991 992 993 994 995 996
 *
 * Since: 2.20
 **/
gboolean
gtk_range_get_slider_size_fixed (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

997
  return range->priv->slider_size_fixed;
998 999 1000 1001 1002
}

/**
 * gtk_range_set_min_slider_size:
 * @range: a #GtkRange
1003
 * @min_size: The slider’s minimum size
1004
 *
1005
 * Sets the minimum size of the range’s slider.
1006 1007 1008 1009 1010 1011 1012
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_min_slider_size (GtkRange *range,
1013
                               gint      min_size)
1014
{
1015
  GtkRangePrivate *priv;
1016

1017 1018 1019
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (min_size > 0);

1020 1021 1022
  priv = range->priv;

  if (min_size != priv->min_slider_size)
1023
    {
1024
      priv->min_slider_size = min_size;
1025

1026
      gtk_widget_queue_resize (GTK_WIDGET (range));
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
    }
}

/**
 * gtk_range_get_min_slider_size:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_min_slider_size().
 *
1038
 * Returns: The minimum size of the range’s slider.
1039 1040 1041 1042 1043 1044 1045 1046
 *
 * Since: 2.20
 **/
gint
gtk_range_get_min_slider_size (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1047
  return range->priv->min_slider_size;
1048 1049 1050 1051 1052
}

/**
 * gtk_range_get_range_rect:
 * @range: a #GtkRange
1053
 * @range_rect: (out): return location for the range rectangle
1054
 *
1055
 * This function returns the area that contains the range’s trough
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
 * 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)
{
1066
  GtkRangePrivate *priv;
1067

1068 1069 1070
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (range_rect != NULL);

1071 1072
  priv = range->priv;

1073
  gtk_range_calc_layout (range);
1074

1075
  *range_rect = priv->range_rect;
1076 1077 1078 1079 1080
}

/**
 * gtk_range_get_slider_range:
 * @range: a #GtkRange
1081 1082 1083 1084
 * @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
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
 *
 * 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)
{
1098
  GtkRangePrivate *priv;
1099

1100 1101
  g_return_if_fail (GTK_IS_RANGE (range));

1102 1103
  priv = range->priv;

1104
  gtk_range_calc_layout (range);
1105

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
    {
      if (slider_start)
        *slider_start = priv->slider.y;
      if (slider_end)
        *slider_end = priv->slider.y + priv->slider.height;
    }
  else
    {
      if (slider_start)
        *slider_start = priv->slider.x;
      if (slider_end)
        *slider_end = priv->slider.x + priv->slider.width;
    }
1120 1121
}

1122 1123 1124
/**
 * gtk_range_set_lower_stepper_sensitivity:
 * @range:       a #GtkRange
1125
 * @sensitivity: the lower stepper’s sensitivity policy.
1126 1127
 *
 * Sets the sensitivity policy for the stepper that points to the
1128
 * 'lower' end of the GtkRange’s adjustment.
1129
 *
Matthias Clasen's avatar
Matthias Clasen committed
1130
 * Since: 2.10
1131 1132 1133 1134 1135
 **/
void
gtk_range_set_lower_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1136
  GtkRangePrivate *priv;
1137

1138 1139
  g_return_if_fail (GTK_IS_RANGE (range));

1140 1141 1142
  priv = range->priv;

  if (priv->lower_sensitivity != sensitivity)
1143
    {
1144
      priv->lower_sensitivity = sensitivity;
1145

1146
      gtk_range_calc_stepper_sensitivity (range);
1147

1148
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_LOWER_STEPPER_SENSITIVITY]);
1149 1150 1151 1152 1153 1154 1155 1156
    }
}

/**
 * gtk_range_get_lower_stepper_sensitivity:
 * @range: a #GtkRange
 *
 * Gets the sensitivity policy for the stepper that points to the
1157
 * 'lower' end of the GtkRange’s adjustment.
1158
 *
1159
 * Returns: The lower stepper’s sensitivity policy.
1160 1161 1162 1163 1164 1165 1166 1167
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_lower_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1168
  return range->priv->lower_sensitivity;
1169 1170 1171 1172 1173
}

/**
 * gtk_range_set_upper_stepper_sensitivity:
 * @range:       a #GtkRange
1174
 * @sensitivity: the upper stepper’s sensitivity policy.
1175 1176
 *
 * Sets the sensitivity policy for the stepper that points to the
1177
 * 'upper' end of the GtkRange’s adjustment.
1178
 *
Matthias Clasen's avatar
Matthias Clasen committed
1179
 * Since: 2.10
1180 1181 1182 1183 1184
 **/
void
gtk_range_set_upper_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1185
  GtkRangePrivate *priv;
1186

1187 1188
  g_return_if_fail (GTK_IS_RANGE (range));

1189 1190 1191
  priv = range->priv;

  if (priv->upper_sensitivity != sensitivity)
1192
    {
1193
      priv->upper_sensitivity = sensitivity;
1194

1195
      gtk_range_calc_stepper_sensitivity (range);
1196

1197
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_UPPER_STEPPER_SENSITIVITY]);
1198 1199 1200 1201 1202 1203 1204 1205
    }
}

/**
 * gtk_range_get_upper_stepper_sensitivity:
 * @range: a #GtkRange
 *
 * Gets the sensitivity policy for the stepper that points to the
1206
 * 'upper' end of the GtkRange’s adjustment.
1207
 *
1208
 * Returns: The upper stepper’s sensitivity policy.
1209 1210 1211 1212 1213 1214 1215 1216
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_upper_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1217
  return range->priv->upper_sensitivity;
1218 1219
}

1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
/**
 * 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)
{
1236
  GtkAdjustment *adjustment;
1237

1238 1239
  g_return_if_fail (GTK_IS_RANGE (range));

1240
  adjustment = range->priv->adjustment;
1241

1242 1243 1244 1245 1246 1247 1248
  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));
1249 1250 1251 1252 1253 1254 1255 1256 1257
}

/**
 * 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
1258 1259
 * 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.)
1260 1261 1262 1263 1264 1265
 **/
void
gtk_range_set_range (GtkRange *range,
                     gdouble   min,
                     gdouble   max)
{
1266
  GtkRangePrivate *priv;
1267
  GtkAdjustment *adjustment;
1268 1269 1270
  gdouble value;
  
  g_return_if_fail (GTK_IS_RANGE (range));
1271
  g_return_if_fail (min <= max);
1272

1273
  priv = range->priv;
1274
  adjustment = priv->adjustment;
1275

1276
  value = gtk_adjustment_get_value (adjustment);
1277
  if (priv->restrict_to_fill_level)
1278
    value = MIN (value, MAX (gtk_adjustment_get_lower (adjustment),
1279
                             priv->fill_level));
1280

1281 1282 1283 1284 1285 1286 1287
  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));
1288 1289 1290 1291 1292 1293 1294 1295 1296
}

/**
 * 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
1297 1298
 * them. The range emits the #GtkRange::value-changed signal if the 
 * value changes.
1299 1300 1301 1302 1303
 **/
void
gtk_range_set_value (GtkRange *range,
                     gdouble   value)
{
1304
  GtkRangePrivate *priv;
1305

1306
  g_return_if_fail (GTK_IS_RANGE (range));
1307

1308 1309 1310
  priv = range->priv;

  if (priv->restrict_to_fill_level)
1311
    value = MIN (value, MAX (gtk_adjustment_get_lower (priv->adjustment),
1312
                             priv->fill_level));
1313

1314
  gtk_adjustment_set_value (priv->adjustment, value);
1315 1316 1317 1318 1319 1320 1321 1322
}

/**
 * gtk_range_get_value:
 * @range: a #GtkRange
 * 
 * Gets the current value of the range.
 * 
1323
 * Returns: current value of the range.
1324 1325 1326 1327 1328 1329
 **/
gdouble
gtk_range_get_value (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), 0.0);

1330
  return gtk_adjustment_get_value (range->priv->adjustment);
1331 1332
}

1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
/**
 * gtk_range_set_show_fill_level:
 * @range:           A #GtkRange
 * @show_fill_level: Whether a fill level indicator graphics is shown.
 *
 * Sets whether a graphical fill level is show on the trough. See
 * gtk_range_set_fill_level() for a general description of the fill
 * level concept.
 *
 * Since: 2.12
 **/
void
gtk_range_set_show_fill_level (GtkRange *range,
                               gboolean  show_fill_level)
{
1348
  GtkRangePrivate *priv;
1349