gtkrange.c 128 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 166
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,
167 168
  PROP_FILL_LEVEL,
  PROP_ROUND_DIGITS
169
};
170

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

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

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

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


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

/* Range methods */
252

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

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

Elliot Lee's avatar
Elliot Lee committed
300

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

306
static guint signals[LAST_SIGNAL];
Elliot Lee's avatar
Elliot Lee committed
307 308 309 310 311


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

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

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

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

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

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

  /**
   * GtkRange::adjust-bounds:
   * @range: the #GtkRange that received the signal
   * @value: the value before we clamp
356 357 358
   *
   * Emitted before clamping a value, to give the application a
   * chance to adjust the bounds.
359
   */
360
  signals[ADJUST_BOUNDS] =
361
    g_signal_new (I_("adjust-bounds"),
Manish Singh's avatar
Manish Singh committed
362
                  G_TYPE_FROM_CLASS (gobject_class),
363 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);
  
Matthias Clasen's avatar
Matthias Clasen committed
370 371
  /**
   * GtkRange::move-slider:
372
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
373 374 375 376
   * @step: how to move the slider
   *
   * Virtual function that moves the slider. Used for keybindings.
   */
377
  signals[MOVE_SLIDER] =
378
    g_signal_new (I_("move-slider"),
Manish Singh's avatar
Manish Singh committed
379
                  G_TYPE_FROM_CLASS (gobject_class),
380 381 382
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkRangeClass, move_slider),
                  NULL, NULL,
383
                  _gtk_marshal_VOID__ENUM,
384 385
                  G_TYPE_NONE, 1,
                  GTK_TYPE_SCROLL_TYPE);
386 387 388

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

425 426 427 428
  g_object_class_override_property (gobject_class,
                                    PROP_ORIENTATION,
                                    "orientation");

429 430 431
  g_object_class_install_property (gobject_class,
                                   PROP_ADJUSTMENT,
                                   g_param_spec_object ("adjustment",
432 433
							P_("Adjustment"),
							P_("The GtkAdjustment that contains the current value of this range object"),
434
                                                        GTK_TYPE_ADJUSTMENT,
435
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
436

437 438 439
  g_object_class_install_property (gobject_class,
                                   PROP_INVERTED,
                                   g_param_spec_boolean ("inverted",
440 441
							P_("Inverted"),
							P_("Invert direction slider moves to increase range value"),
442
                                                         FALSE,
443
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
444 445 446 447 448 449 450 451

  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,
452
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
453 454 455 456 457 458 459 460

  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,
461
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
462

463 464 465
  /**
   * GtkRange:show-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
466
   * The show-fill-level property controls whether fill level indicator
467 468 469 470 471 472 473 474 475 476 477
   * 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,
478
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
479 480 481 482

  /**
   * GtkRange:restrict-to-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
483
   * The restrict-to-fill-level property controls whether slider
484
   * movement is restricted to an upper boundary set by the
Matthias Clasen's avatar
Matthias Clasen committed
485
   * fill level. See gtk_range_set_restrict_to_fill_level().
486 487 488 489 490 491 492 493 494
   *
   * 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,
495
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

  /**
   * 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,
513
                                                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
514

515 516 517 518 519 520 521 522 523 524 525 526
  /**
   * 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
527
                                                     P_("The number of digits to round the value to."),
528 529
                                                     -1, G_MAXINT, -1,
                                                     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
530

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

586 587 588 589
  /**
   * GtkRange:trough-under-steppers:
   *
   * Whether to draw the trough across the full length of the range or
590
   * to exclude the steppers and their spacing.
591 592 593 594 595 596
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boolean ("trough-under-steppers",
                                                                 P_("Trough Under Steppers"),
597
                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
598 599
                                                                 TRUE,
                                                                 GTK_PARAM_READABLE));
600

601 602 603 604 605 606 607 608 609 610 611 612 613 614
  /**
   * 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));

615
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
616 617
}

618
static void
Alexander Larsson's avatar
Alexander Larsson committed
619 620 621 622
gtk_range_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
623
{
624
  GtkRange *range = GTK_RANGE (object);
625
  GtkRangePrivate *priv = range->priv;
626

Alexander Larsson's avatar
Alexander Larsson committed
627
  switch (prop_id)
628
    {
629
    case PROP_ORIENTATION:
630 631 632
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
633

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

static void
Alexander Larsson's avatar
Alexander Larsson committed
670 671 672 673
gtk_range_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
674
{
675
  GtkRange *range = GTK_RANGE (object);
676
  GtkRangePrivate *priv = range->priv;
677

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

Elliot Lee's avatar
Elliot Lee committed
713 714 715
static void
gtk_range_init (GtkRange *range)
{
716
  GtkRangePrivate *priv;
717

718
  range->priv = gtk_range_get_instance_private (range);
719 720
  priv = range->priv;

721
  gtk_widget_set_has_window (GTK_WIDGET (range), FALSE);
722

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
  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;
741
  priv->has_origin = FALSE;
742 743 744 745
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
746

747 748
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));

749 750 751 752 753 754 755
  /* 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));
756
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
757 758 759 760 761 762 763
  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);

764
  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (range));
765
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
766 767 768 769 770 771
  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));
772
  g_object_set (priv->long_press_gesture, "delay-factor", 2.0, NULL);
773 774 775
  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
776 777
}

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

Elliot Lee's avatar
Elliot Lee committed
794 795
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

796 797 798
  priv = range->priv;

  if (!priv->adjustment)
799 800
    gtk_range_set_adjustment (range, NULL);

801
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
802 803
}

804 805 806 807 808
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
809
 * Sets the adjustment to be used as the “model” object for this range
810 811 812 813 814 815 816
 * 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
817 818 819 820
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
821
  GtkRangePrivate *priv;
822

Elliot Lee's avatar
Elliot Lee committed
823
  g_return_if_fail (GTK_IS_RANGE (range));
824 825 826

  priv = range->priv;

827
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
828
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
829 830
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
831

832
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
833
    {
834
      if (priv->adjustment)
835
	{
836
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
837 838
						gtk_range_adjustment_changed,
						range);
839
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
840 841
						gtk_range_adjustment_value_changed,
						range);
842
	  g_object_unref (priv->adjustment);
843
	}
844

845
      priv->adjustment = adjustment;
846
      g_object_ref_sink (adjustment);
847
      
Manish Singh's avatar
Manish Singh committed
848 849 850
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
851
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
852 853
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
854
      
855
      gtk_range_adjustment_changed (adjustment, range);
856
      g_object_notify (G_OBJECT (range), "adjustment");
Elliot Lee's avatar
Elliot Lee committed
857 858 859
    }
}

860 861 862 863 864 865 866 867 868 869
/**
 * 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.
 **/
870 871 872 873
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
874
  GtkRangePrivate *priv;
875

876
  g_return_if_fail (GTK_IS_RANGE (range));
877 878 879

  priv = range->priv;

880 881
  setting = setting != FALSE;

882
  if (setting != priv->inverted)
883
    {
884
      priv->inverted = setting;
885
      g_object_notify (G_OBJECT (range), "inverted");
886 887 888 889
      gtk_widget_queue_resize (GTK_WIDGET (range));
    }
}

890 891 892 893 894 895
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
896
 * Returns: %TRUE if the range is inverted
897
 **/
898 899 900 901 902
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

903
  return range->priv->inverted;
904 905
}

906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
/**
 * 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)
{
922
  GtkRangePrivate *priv;
923

924 925
  g_return_if_fail (GTK_IS_RANGE (range));

926 927
  priv = range->priv;

928 929
  flippable = flippable ? TRUE : FALSE;

930
  if (flippable != priv->flippable)
931
    {
932
      priv->flippable = flippable;
933 934 935 936 937 938 939 940 941 942 943

      gtk_widget_queue_draw (GTK_WIDGET (range));
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
944
 * Returns: %TRUE if the range is flippable
945 946 947 948 949 950 951 952
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

953
  return range->priv->flippable;
954 955
}

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

974 975
  g_return_if_fail (GTK_IS_RANGE (range));

976 977 978
  priv = range->priv;

  if (size_fixed != priv->slider_size_fixed)
979
    {
980
      priv->slider_size_fixed = size_fixed ? TRUE : FALSE;
981

982
      if (priv->adjustment && gtk_widget_get_mapped (GTK_WIDGET (range)))
983
        gtk_range_calc_slider (range);
984 985 986 987 988 989 990 991 992 993 994
    }
}

/**
 * gtk_range_get_slider_size_fixed:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_slider_size_fixed().
 *
995
 * Returns: whether the range’s slider has a fixed size.
996 997 998 999 1000 1001 1002 1003
 *
 * Since: 2.20
 **/
gboolean
gtk_range_get_slider_size_fixed (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1004
  return range->priv->slider_size_fixed;
1005 1006 1007 1008 1009
}

/**
 * gtk_range_set_min_slider_size:
 * @range: a #GtkRange
1010
 * @min_size: The slider’s minimum size
1011
 *
1012
 * Sets the minimum size of the range’s slider.
1013 1014 1015 1016 1017 1018 1019
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_min_slider_size (GtkRange *range,
1020
                               gint      min_size)
1021
{
1022
  GtkRangePrivate *priv;
1023

1024 1025 1026
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (min_size > 0);

1027 1028 1029
  priv = range->priv;

  if (min_size != priv->min_slider_size)
1030
    {
1031
      priv->min_slider_size = min_size;
1032

1033
      gtk_widget_queue_resize (GTK_WIDGET (range));
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
    }
}

/**
 * gtk_range_get_min_slider_size:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_min_slider_size().
 *
1045
 * Returns: The minimum size of the range’s slider.
1046 1047 1048 1049 1050 1051 1052 1053
 *
 * Since: 2.20
 **/
gint
gtk_range_get_min_slider_size (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1054
  return range->priv->min_slider_size;
1055 1056 1057 1058 1059
}

/**
 * gtk_range_get_range_rect:
 * @range: a #GtkRange
1060
 * @range_rect: (out): return location for the range rectangle
1061
 *
1062
 * This function returns the area that contains the range’s trough
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
 * 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)
{
1073
  GtkRangePrivate *priv;
1074

1075 1076 1077
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (range_rect != NULL);

1078 1079
  priv = range->priv;

1080
  gtk_range_calc_layout (range);
1081

1082
  *range_rect = priv->range_rect;
1083 1084 1085 1086 1087
}

/**
 * gtk_range_get_slider_range:
 * @range: a #GtkRange
1088 1089 1090 1091
 * @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
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
 *
 * 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)
{
1105
  GtkRangePrivate *priv;
1106

1107 1108
  g_return_if_fail (GTK_IS_RANGE (range));

1109 1110
  priv = range->priv;

1111
  gtk_range_calc_layout (range);
1112

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
  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;
    }
1127 1128
}

1129 1130 1131
/**
 * gtk_range_set_lower_stepper_sensitivity:
 * @range:       a #GtkRange
1132
 * @sensitivity: the lower stepper’s sensitivity policy.
1133 1134
 *
 * Sets the sensitivity policy for the stepper that points to the
1135
 * 'lower' end of the GtkRange’s adjustment.
1136
 *
Matthias Clasen's avatar
Matthias Clasen committed
1137
 * Since: 2.10
1138 1139 1140 1141 1142
 **/
void
gtk_range_set_lower_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1143
  GtkRangePrivate *priv;
1144

1145 1146
  g_return_if_fail (GTK_IS_RANGE (range));

1147 1148 1149
  priv = range->priv;

  if (priv->lower_sensitivity != sensitivity)
1150
    {
1151
      priv->lower_sensitivity = sensitivity;
1152

1153
      gtk_range_calc_stepper_sensitivity (range);
1154

1155 1156 1157 1158 1159 1160 1161 1162 1163
      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
1164
 * 'lower' end of the GtkRange’s adjustment.
1165
 *
1166
 * Returns: The lower stepper’s sensitivity policy.
1167 1168 1169 1170 1171 1172 1173 1174
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_lower_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1175
  return range->priv->lower_sensitivity;
1176 1177 1178 1179 1180
}

/**
 * gtk_range_set_upper_stepper_sensitivity:
 * @range:       a #GtkRange
1181
 * @sensitivity: the upper stepper’s sensitivity policy.
1182 1183
 *
 * Sets the sensitivity policy for the stepper that points to the
1184
 * 'upper' end of the GtkRange’s adjustment.
1185
 *
Matthias Clasen's avatar
Matthias Clasen committed
1186
 * Since: 2.10
1187 1188 1189 1190 1191
 **/
void
gtk_range_set_upper_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1192
  GtkRangePrivate *priv;
1193

1194 1195
  g_return_if_fail (GTK_IS_RANGE (range));

1196 1197 1198
  priv = range->priv;

  if (priv->upper_sensitivity != sensitivity)
1199
    {
1200
      priv->upper_sensitivity = sensitivity;
1201

1202
      gtk_range_calc_stepper_sensitivity (range);
1203

1204 1205 1206 1207 1208 1209 1210 1211 1212
      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
1213
 * 'upper' end of the GtkRange’s adjustment.
1214
 *
1215
 * Returns: The upper stepper’s sensitivity policy.
1216 1217 1218 1219 1220 1221 1222 1223
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_upper_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1224
  return range->priv->upper_sensitivity;
1225 1226
}

1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
/**
 * 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)
{
1243
  GtkAdjustment *adjustment;
1244

1245 1246
  g_return_if_fail (GTK_IS_RANGE (range));

1247
  adjustment = range->priv->adjustment;
1248

1249 1250 1251 1252 1253 1254 1255
  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));
1256 1257 1258 1259 1260 1261 1262 1263 1264
}

/**
 * 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
1265 1266
 * 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.)
1267 1268 1269 1270 1271 1272
 **/
void
gtk_range_set_range (GtkRange *range,
                     gdouble   min,
                     gdouble   max)
{
1273
  GtkRangePrivate *priv;
1274
  GtkAdjustment *adjustment;
1275 1276 1277
  gdouble value;
  
  g_return_if_fail (GTK_IS_RANGE (range));
1278
  g_return_if_fail (min <= max);
1279

1280
  priv = range->priv;
1281
  adjustment = priv->adjustment;
1282

1283
  value = gtk_adjustment_get_value (adjustment);
1284
  if (priv->restrict_to_fill_level)
1285
    value = MIN (value, MAX (gtk_adjustment_get_lower (adjustment),
1286
                             priv->fill_level));
1287

1288 1289 1290 1291 1292 1293 1294
  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));
1295 1296 1297 1298 1299 1300 1301 1302 1303
}

/**
 * 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
1304 1305
 * them. The range emits the #GtkRange::value-changed signal if the 
 * value changes.
1306 1307 1308 1309 1310
 **/
void
gtk_range_set_value (GtkRange *range,
                     gdouble   value)
{
1311
  GtkRangePrivate *priv;
1312

1313
  g_return_if_fail (GTK_IS_RANGE (range));
1314

1315 1316 1317
  priv = range->priv;

  if (priv->restrict_to_fill_level)
1318
    value = MIN (value, MAX (gtk_adjustment_get_lower (priv->adjustment),
1319
                             priv->fill_level));
1320

1321
  gtk_adjustment_set_value (priv->adjustment, value);
1322 1323 1324 1325 1326 1327 1328 1329
}

/**
 * gtk_range_get_value:
 * @range: a #GtkRange
 * 
 * Gets the current value of the range.
 * 
1330
 * Returns: current value of the range.
1331 1332 1333 1334 1335 1336
 **/
gdouble
gtk_range_get_value (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE