gtkrange.c 125 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
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20 21

/*
22
 * Modified by the GTK+ Team and others 1997-2004.  See the AUTHORS
23 24 25 26 27
 * 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/. 
 */

28
#include "config.h"
29

Elliot Lee's avatar
Elliot Lee committed
30
#include <stdio.h>
31
#include <math.h>
32

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

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


62 63
#define SCROLL_DELAY_FACTOR 5    /* Scroll repeat multiplier */
#define UPDATE_DELAY        300  /* Delay for queued update */
Elliot Lee's avatar
Elliot Lee committed
64

65
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
66

67 68 69 70 71 72 73 74 75 76 77
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;

78
struct _GtkRangePrivate
79 80 81 82 83 84
{
  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 */
85

86
  GtkRangeStepTimer *timer;
87

88 89 90 91 92 93
  GtkAdjustment     *adjustment;
  GtkSensitivityType lower_sensitivity;
  GtkSensitivityType upper_sensitivity;

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

103 104
  GQuark             slider_detail_quark;
  GQuark             stepper_detail_quark[4];
105

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

  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;
  gint  slide_initial_coordinate;
  gint  slider_start;                /* Slider range along the long dimension, in widget->window coords */
  gint  slider_end;
119

120 121 122 123 124 125 126 127 128 129 130 131 132
  guint repaint_id;

  /* Steppers are: < > ---- < >
   *               a b      c d
   */
  guint has_stepper_a          : 1;
  guint has_stepper_b          : 1;
  guint has_stepper_c          : 1;
  guint has_stepper_d          : 1;

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

  /* Stepper sensitivity */
138 139
  guint lower_sensitive        : 1;
  guint upper_sensitive        : 1;
140

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

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

  guint grab_button            : 8; /* 0 if none */
149
};
150

151

152 153 154 155 156 157 158 159 160
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,
161 162
  PROP_FILL_LEVEL,
  PROP_ROUND_DIGITS
163
};
164

165 166 167 168 169 170
enum {
  VALUE_CHANGED,
  ADJUST_BOUNDS,
  MOVE_SLIDER,
  CHANGE_VALUE,
  LAST_SIGNAL
171 172
};

173 174 175 176 177 178
typedef enum {
  STEPPER_A,
  STEPPER_B,
  STEPPER_C,
  STEPPER_D
} Stepper;
179

180 181 182 183 184 185 186 187
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);
188
static void gtk_range_destroy        (GtkWidget        *widget);
189 190 191 192 193 194 195 196
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);
197 198
static void gtk_range_size_allocate  (GtkWidget        *widget,
                                      GtkAllocation    *allocation);
199 200
static void gtk_range_hierarchy_changed (GtkWidget     *widget,
                                         GtkWidget     *previous_toplevel);
201 202
static void gtk_range_realize        (GtkWidget        *widget);
static void gtk_range_unrealize      (GtkWidget        *widget);
203 204
static void gtk_range_map            (GtkWidget        *widget);
static void gtk_range_unmap          (GtkWidget        *widget);
205 206
static gboolean gtk_range_draw       (GtkWidget        *widget,
                                      cairo_t          *cr);
207
static gboolean gtk_range_button_press   (GtkWidget        *widget,
208
                                      GdkEventButton   *event);
209
static gboolean gtk_range_button_release (GtkWidget        *widget,
210
                                      GdkEventButton   *event);
211
static gboolean gtk_range_motion_notify  (GtkWidget        *widget,
212
                                      GdkEventMotion   *event);
213
static gboolean gtk_range_enter_notify   (GtkWidget        *widget,
214
                                      GdkEventCrossing *event);
215
static gboolean gtk_range_leave_notify   (GtkWidget        *widget,
216
                                      GdkEventCrossing *event);
Matthias Clasen's avatar
Matthias Clasen committed
217 218
static gboolean gtk_range_grab_broken (GtkWidget          *widget,
				       GdkEventGrabBroken *event);
Matthias Clasen's avatar
Matthias Clasen committed
219 220
static void gtk_range_grab_notify    (GtkWidget          *widget,
				      gboolean            was_grabbed);
221 222
static void gtk_range_state_flags_changed  (GtkWidget      *widget,
                                            GtkStateFlags   previous_state);
223
static gboolean gtk_range_scroll_event   (GtkWidget        *widget,
224
                                      GdkEventScroll   *event);
225
static void gtk_range_style_updated  (GtkWidget        *widget);
226 227 228
static void update_slider_position   (GtkRange	       *range,
				      gint              mouse_x,
				      gint              mouse_y);
229
static void stop_scrolling           (GtkRange         *range);
230 231
static gboolean modify_allocation_for_window_grip (GtkWidget     *widget,
                                                   GtkAllocation *allocation);
232 233

/* Range methods */
234

235
static void gtk_range_move_slider              (GtkRange         *range,
236 237 238
                                                GtkScrollType     scroll);

/* Internals */
239
static gboolean      gtk_range_scroll                   (GtkRange      *range,
240 241
                                                         GtkScrollType  scroll);
static gboolean      gtk_range_update_mouse_location    (GtkRange      *range);
242 243
static void          gtk_range_calc_layout              (GtkRange      *range,
							 gdouble	adjustment_value);
244
static void          gtk_range_calc_marks               (GtkRange      *range);
245 246 247
static void          gtk_range_get_props                (GtkRange      *range,
                                                         gint          *slider_width,
                                                         gint          *stepper_size,
248
                                                         gint          *focus_width,
249
                                                         gint          *trough_border,
250
                                                         gint          *stepper_spacing,
251
                                                         gboolean      *trough_under_steppers,
252 253
							 gint          *arrow_displacement_x,
							 gint	       *arrow_displacement_y);
254 255 256
static void          gtk_range_calc_request             (GtkRange      *range,
                                                         gint           slider_width,
                                                         gint           stepper_size,
257
                                                         gint           focus_width,
258 259 260 261 262
                                                         gint           trough_border,
                                                         gint           stepper_spacing,
                                                         GdkRectangle  *range_rect,
                                                         GtkBorder     *border,
                                                         gint          *n_steppers_p,
263 264
                                                         gboolean      *has_steppers_ab,
                                                         gboolean      *has_steppers_cd,
265 266 267 268 269 270 271 272 273 274
                                                         gint          *slider_length_p);
static void          gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
                                                         gpointer       data);
static void          gtk_range_adjustment_changed       (GtkAdjustment *adjustment,
                                                         gpointer       data);
static void          gtk_range_add_step_timer           (GtkRange      *range,
                                                         GtkScrollType  step);
static void          gtk_range_remove_step_timer        (GtkRange      *range);
static GdkRectangle* get_area                           (GtkRange      *range,
                                                         MouseLocation  location);
275 276 277
static gboolean      gtk_range_real_change_value        (GtkRange      *range,
                                                         GtkScrollType  scroll,
                                                         gdouble        value);
278 279
static gboolean      gtk_range_key_press                (GtkWidget     *range,
							 GdkEventKey   *event);
280

Elliot Lee's avatar
Elliot Lee committed
281

282 283 284 285
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET,
                                  G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                         NULL))

286
static guint signals[LAST_SIGNAL];
Elliot Lee's avatar
Elliot Lee committed
287 288 289 290 291


static void
gtk_range_class_init (GtkRangeClass *class)
{
Alexander Larsson's avatar
Alexander Larsson committed
292
  GObjectClass   *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
293 294
  GtkWidgetClass *widget_class;

Alexander Larsson's avatar
Alexander Larsson committed
295
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
296 297
  widget_class = (GtkWidgetClass*) class;

Alexander Larsson's avatar
Alexander Larsson committed
298 299
  gobject_class->set_property = gtk_range_set_property;
  gobject_class->get_property = gtk_range_get_property;
300

301
  widget_class->destroy = gtk_range_destroy;
302 303
  widget_class->get_preferred_width = gtk_range_get_preferred_width;
  widget_class->get_preferred_height = gtk_range_get_preferred_height;
304
  widget_class->size_allocate = gtk_range_size_allocate;
305
  widget_class->hierarchy_changed = gtk_range_hierarchy_changed;
306
  widget_class->realize = gtk_range_realize;
307
  widget_class->unrealize = gtk_range_unrealize;
308 309
  widget_class->map = gtk_range_map;
  widget_class->unmap = gtk_range_unmap;
310
  widget_class->draw = gtk_range_draw;
Elliot Lee's avatar
Elliot Lee committed
311 312 313
  widget_class->button_press_event = gtk_range_button_press;
  widget_class->button_release_event = gtk_range_button_release;
  widget_class->motion_notify_event = gtk_range_motion_notify;
314
  widget_class->scroll_event = gtk_range_scroll_event;
Elliot Lee's avatar
Elliot Lee committed
315 316
  widget_class->enter_notify_event = gtk_range_enter_notify;
  widget_class->leave_notify_event = gtk_range_leave_notify;
Matthias Clasen's avatar
Matthias Clasen committed
317
  widget_class->grab_broken_event = gtk_range_grab_broken;
Matthias Clasen's avatar
Matthias Clasen committed
318
  widget_class->grab_notify = gtk_range_grab_notify;
319 320
  widget_class->state_flags_changed = gtk_range_state_flags_changed;
  widget_class->style_updated = gtk_range_style_updated;
321
  widget_class->key_press_event = gtk_range_key_press;
322 323

  class->move_slider = gtk_range_move_slider;
324
  class->change_value = gtk_range_real_change_value;
325

326 327
  class->slider_detail = "slider";
  class->stepper_detail = "stepper";
328

Matthias Clasen's avatar
Matthias Clasen committed
329 330
  /**
   * GtkRange::value-changed:
331
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
332 333 334
   *
   * Emitted when the range value changes.
   */
335
  signals[VALUE_CHANGED] =
336
    g_signal_new (I_("value-changed"),
Manish Singh's avatar
Manish Singh committed
337
                  G_TYPE_FROM_CLASS (gobject_class),
338 339 340
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, value_changed),
                  NULL, NULL,
341
                  _gtk_marshal_VOID__VOID,
342
                  G_TYPE_NONE, 0);
343 344 345 346 347

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

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

417 418 419 420
  g_object_class_override_property (gobject_class,
                                    PROP_ORIENTATION,
                                    "orientation");

421 422 423
  g_object_class_install_property (gobject_class,
                                   PROP_ADJUSTMENT,
                                   g_param_spec_object ("adjustment",
424 425
							P_("Adjustment"),
							P_("The GtkAdjustment that contains the current value of this range object"),
426
                                                        GTK_TYPE_ADJUSTMENT,
427
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
428

429 430 431
  g_object_class_install_property (gobject_class,
                                   PROP_INVERTED,
                                   g_param_spec_boolean ("inverted",
432 433
							P_("Inverted"),
							P_("Invert direction slider moves to increase range value"),
434
                                                         FALSE,
435
                                                         GTK_PARAM_READWRITE));
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454

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

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

455 456 457
  /**
   * GtkRange:show-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
458
   * The show-fill-level property controls whether fill level indicator
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
   * 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,
                                                         GTK_PARAM_READWRITE));

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

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

507 508 509 510 511 512 513 514 515 516 517 518
  /**
   * 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
519
                                                     P_("The number of digits to round the value to."),
520 521 522 523 524
                                                     -1,
                                                     G_MAXINT,
                                                     -1,
                                                     GTK_PARAM_READWRITE));

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

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

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

609
  g_type_class_add_private (class, sizeof (GtkRangePrivate));
610 611

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
612 613
}

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

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

628 629 630 631 632
      priv->slider_detail_quark = 0;
      priv->stepper_detail_quark[0] = 0;
      priv->stepper_detail_quark[1] = 0;
      priv->stepper_detail_quark[2] = 0;
      priv->stepper_detail_quark[3] = 0;
633

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

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

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

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

  range->priv = G_TYPE_INSTANCE_GET_PRIVATE (range,
                                             GTK_TYPE_RANGE,
718
                                             GtkRangePrivate);
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 741 742
  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  priv->adjustment = NULL;
  priv->inverted = FALSE;
  priv->flippable = FALSE;
  priv->min_slider_size = 1;
  priv->has_stepper_a = FALSE;
  priv->has_stepper_b = FALSE;
  priv->has_stepper_c = FALSE;
  priv->has_stepper_d = FALSE;
  priv->need_recalc = TRUE;
  priv->round_digits = -1;
  priv->mouse_location = MOUSE_OUTSIDE;
  priv->mouse_x = -1;
  priv->mouse_y = -1;
  priv->grab_location = MOUSE_OUTSIDE;
  priv->grab_button = 0;
  priv->lower_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->upper_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->lower_sensitive = TRUE;
  priv->upper_sensitive = TRUE;
743
  priv->has_origin = FALSE;
744 745 746 747
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
Elliot Lee's avatar
Elliot Lee committed
748 749
}

750 751 752 753 754 755 756 757 758
/**
 * gtk_range_get_adjustment:
 * @range: a #GtkRange
 * 
 * Get the #GtkAdjustment which is the "model" object for #GtkRange.
 * See gtk_range_set_adjustment() for details.
 * The return value does not have a reference added, so should not
 * be unreferenced.
 * 
759
 * Return value: (transfer none): a #GtkAdjustment
760
 **/
Elliot Lee's avatar
Elliot Lee committed
761 762 763
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
764
  GtkRangePrivate *priv;
765

Elliot Lee's avatar
Elliot Lee committed
766 767
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

768 769 770
  priv = range->priv;

  if (!priv->adjustment)
771 772
    gtk_range_set_adjustment (range, NULL);

773
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
774 775
}

776 777 778 779 780 781 782 783 784 785 786 787 788
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
 * Sets the adjustment to be used as the "model" object for this range
 * 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
789 790 791 792
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
793
  GtkRangePrivate *priv;
794

Elliot Lee's avatar
Elliot Lee committed
795
  g_return_if_fail (GTK_IS_RANGE (range));
796 797 798

  priv = range->priv;

799
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
800
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
801 802
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
803

804
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
805
    {
806
      if (priv->adjustment)
807
	{
808
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
809 810
						gtk_range_adjustment_changed,
						range);
811
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
812 813
						gtk_range_adjustment_value_changed,
						range);
814
	  g_object_unref (priv->adjustment);
815
	}
816

817
      priv->adjustment = adjustment;
818
      g_object_ref_sink (adjustment);
819
      
Manish Singh's avatar
Manish Singh committed
820 821 822
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
823
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
824 825
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
826
      
827
      gtk_range_adjustment_changed (adjustment, range);
828
      g_object_notify (G_OBJECT (range), "adjustment");
Elliot Lee's avatar
Elliot Lee committed
829 830 831
    }
}

832 833 834 835 836 837 838 839 840 841
/**
 * 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.
 **/
842 843 844 845
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
846
  GtkRangePrivate *priv;
847

848
  g_return_if_fail (GTK_IS_RANGE (range));
849 850 851

  priv = range->priv;

852 853
  setting = setting != FALSE;

854
  if (setting != priv->inverted)
855
    {
856
      priv->inverted = setting;
857
      g_object_notify (G_OBJECT (range), "inverted");
858 859 860 861
      gtk_widget_queue_resize (GTK_WIDGET (range));
    }
}

862 863 864 865 866 867 868 869
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
 * Return value: %TRUE if the range is inverted
 **/
870 871 872 873 874
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

875
  return range->priv->inverted;
876 877
}

878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
/**
 * 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)
{
894
  GtkRangePrivate *priv;
895

896 897
  g_return_if_fail (GTK_IS_RANGE (range));

898 899
  priv = range->priv;

900 901
  flippable = flippable ? TRUE : FALSE;

902
  if (flippable != priv->flippable)
903
    {
904
      priv->flippable = flippable;
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924

      gtk_widget_queue_draw (GTK_WIDGET (range));
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
 * Return value: %TRUE if the range is flippable
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

925
  return range->priv->flippable;
926 927
}

928 929 930 931 932 933
/**
 * gtk_range_set_slider_size_fixed:
 * @range: a #GtkRange
 * @size_fixed: %TRUE to make the slider size constant
 *
 * Sets whether the range's slider has a fixed size, or a size that
934
 * depends on its adjustment's page size.
935 936 937 938 939 940 941 942 943
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_slider_size_fixed (GtkRange *range,
                                 gboolean  size_fixed)
{
944
  GtkRangePrivate *priv;
945

946 947
  g_return_if_fail (GTK_IS_RANGE (range));

948 949 950
  priv = range->priv;

  if (size_fixed != priv->slider_size_fixed)
951
    {
952
      priv->slider_size_fixed = size_fixed ? TRUE : FALSE;
953

954
      if (priv->adjustment && gtk_widget_get_mapped (GTK_WIDGET (range)))
955
        {
956 957
          priv->need_recalc = TRUE;
          gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
958 959
          gtk_widget_queue_draw (GTK_WIDGET (range));
        }
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
    }
}

/**
 * gtk_range_get_slider_size_fixed:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_slider_size_fixed().
 *
 * Return value: whether the range's slider has a fixed size.
 *
 * Since: 2.20
 **/
gboolean
gtk_range_get_slider_size_fixed (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

980
  return range->priv->slider_size_fixed;
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
}

/**
 * gtk_range_set_min_slider_size:
 * @range: a #GtkRange
 * @min_size: The slider's minimum size
 *
 * Sets the minimum size of the range's slider.
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_min_slider_size (GtkRange *range,
996
                               gint      min_size)
997
{
998
  GtkRangePrivate *priv;
999

1000 1001 1002
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (min_size > 0);

1003 1004 1005
  priv = range->priv;

  if (min_size != priv->min_slider_size)
1006
    {
1007
      priv->min_slider_size = min_size;
1008

1009 1010 1011
      if (gtk_widget_is_drawable (GTK_WIDGET (range)))
        {
          priv->need_recalc = TRUE;
1012
          gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1013 1014
          gtk_widget_queue_draw (GTK_WIDGET (range));
        }
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
    }
}

/**
 * gtk_range_get_min_slider_size:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_min_slider_size().
 *
 * Return value: The minimum size of the range's slider.
 *
 * Since: 2.20
 **/
gint
gtk_range_get_min_slider_size (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1035
  return range->priv->min_slider_size;
1036 1037 1038 1039 1040
}

/**
 * gtk_range_get_range_rect:
 * @range: a #GtkRange
1041
 * @range_rect: (out): return location for the range rectangle
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
 *
 * This function returns the area that contains the range's trough
 * 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)
{
1054
  GtkRangePrivate *priv;
1055

1056 1057 1058
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (range_rect != NULL);

1059 1060
  priv = range->priv;

1061
  gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1062

1063
  *range_rect = priv->range_rect;
1064 1065 1066 1067 1068
}

/**
 * gtk_range_get_slider_range:
 * @range: a #GtkRange
1069 1070 1071 1072
 * @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
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
 *
 * 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)
{
1086
  GtkRangePrivate *priv;
1087

1088 1089
  g_return_if_fail (GTK_IS_RANGE (range));

1090 1091
  priv = range->priv;

1092
  gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1093 1094

  if (slider_start)
1095
    *slider_start = priv->slider_start;
1096 1097

  if (slider_end)
1098
    *slider_end = priv->slider_end;
1099 1100
}

1101 1102 1103 1104 1105 1106 1107 1108
/**
 * gtk_range_set_lower_stepper_sensitivity:
 * @range:       a #GtkRange
 * @sensitivity: the lower stepper's sensitivity policy.
 *
 * Sets the sensitivity policy for the stepper that points to the
 * 'lower' end of the GtkRange's adjustment.
 *
Matthias Clasen's avatar
Matthias Clasen committed
1109
 * Since: 2.10
1110 1111 1112 1113 1114
 **/
void
gtk_range_set_lower_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1115
  GtkRangePrivate *priv;
1116

1117 1118
  g_return_if_fail (GTK_IS_RANGE (range));

1119 1120 1121
  priv = range->priv;

  if (priv->lower_sensitivity != sensitivity)
1122
    {
1123
      priv->lower_sensitivity = sensitivity;
1124

1125
      priv->need_recalc = TRUE;
1126
      gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1127
      gtk_widget_queue_draw (GTK_WIDGET (range));
1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
      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
 * 'lower' end of the GtkRange's adjustment.
 *
 * Return value: The lower stepper's sensitivity policy.
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_lower_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1149
  return range->priv->lower_sensitivity;
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
}

/**
 * gtk_range_set_upper_stepper_sensitivity:
 * @range:       a #GtkRange
 * @sensitivity: the upper stepper's sensitivity policy.
 *
 * Sets the sensitivity policy for the stepper that points to the
 * 'upper' end of the GtkRange's adjustment.
 *
Matthias Clasen's avatar
Matthias Clasen committed
1160
 * Since: 2.10
1161 1162 1163 1164 1165
 **/
void
gtk_range_set_upper_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1166
  GtkRangePrivate *priv;
1167

1168 1169
  g_return_if_fail (GTK_IS_RANGE (range));

1170 1171 1172
  priv = range->priv;

  if (priv->upper_sensitivity != sensitivity)
1173
    {
1174
      priv->upper_sensitivity = sensitivity;
1175

1176
      priv->need_recalc = TRUE;
1177
      gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
1178
      gtk_widget_queue_draw (GTK_WIDGET (range));
1179

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
      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
 * 'upper' end of the GtkRange's adjustment.
 *
 * Return value: The upper stepper's sensitivity policy.
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_upper_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1200
  return range->priv->upper_sensitivity;
1201 1202
}

1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
/**
 * 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)
{
1219
  GtkAdjustment *adjustment;
1220

1221 1222
  g_return_if_fail (GTK_IS_RANGE (range));

1223
  adjustment = range->priv->adjustment;
1224

1225 1226 1227 1228 1229 1230 1231
  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));
1232 1233 1234 1235 1236 1237 1238 1239 1240
}

/**
 * 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
1241 1242
 * 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.)
1243 1244 1245 1246 1247 1248
 **/
void
gtk_range_set_range (GtkRange *range,
                     gdouble   min,
                     gdouble   max)
{
1249
  GtkRangePrivate *priv;
1250
  GtkAdjustment *adjustment;
1251 1252 1253
  gdouble value;
  
  g_return_if_fail (GTK_IS_RANGE (range));
1254
  g_return_if_fail (min <= max);
1255

1256
  priv = range->priv;
1257
  adjustment = priv->adjustment;
1258

1259
  value = gtk_adjustment_get_value (adjustment);
1260
  if (priv->restrict_to_fill_level)
1261
    value = MIN (value, MAX (gtk_adjustment_get_lower (adjustment),
1262
                             priv->fill_level));
1263

1264 1265 1266 1267 1268 1269 1270
  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));
1271 1272 1273 1274 1275 1276 1277 1278 1279
}

/**
 * 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
1280 1281
 * them. The range emits the #GtkRange::value-changed signal if the 
 * value changes.
1282 1283 1284 1285 1286
 **/
void
gtk_range_set_value (GtkRange *range,
                     gdouble   value)
{
1287
  GtkRangePrivate *priv;
1288

1289
  g_return_if_fail (GTK_IS_RANGE (range));
1290

1291 1292 1293
  priv = range->priv;

  if (priv->restrict_to_fill_level)
1294
    value = MIN (value, MAX (gtk_adjustment_get_lower (priv->adjustment),
1295
                             priv->fill_level));
1296

1297
  gtk_adjustment_set_value (priv->adjustment, value);
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
}

/**
 * gtk_range_get_value:
 * @range: a #GtkRange
 * 
 * Gets the current value of the range.
 * 
 * Return value: current value of the range.
 **/
gdouble
gtk_range_get_value (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), 0.0);

1313
  return gtk_adjustment_get_value (range->priv->adjustment);
1314 1315
}

1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
/**
 * 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)
{
1331
  GtkRangePrivate *priv;
1332

1333 1334
  g_return_if_fail (GTK_IS_RANGE (range));

1335 1336
  priv = range->priv;

1337 1338
  show_fill_level = show_fill_level ? TRUE : FALSE;

1339
  if (show_fill_level != priv->show_fill_level)
1340
    {
1341
      priv->show_fill_level = show_fill_level;
1342 1343 1344 1345 1346 1347 1348 1349 1350
      g_object_notify (G_OBJECT (range), "show-fill-level");
      gtk_widget_queue_draw (GTK_WIDGET (range));
    }
}

/**
 * gtk_range_get_show_fill_level:
 * @range: A #GtkRange
 *
Matthias Clasen's avatar
Matthias Clasen committed
1351 1352 1353
 * Gets whether the range displays the fill level graphically.
 *
 * Return value: %TRUE if @range shows the fill level.
1354 1355 1356 1357 1358 1359 1360 1361
 *
 * Since: 2.12
 **/
gboolean
gtk_range_get_show_fill_level (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1362
  return range->priv->show_fill_level;
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
}

/**
 * gtk_range_set_restrict_to_fill_level:
 * @range:                  A #GtkRange
 * @restrict_to_fill_level: Whether the fill level restricts slider movement.
 *
 * Sets whether the slider is restricted to the fill level. See
 * gtk_range_set_fill_level() for a general description of the fill
 * level concept.
 *
 * Since: 2.12
 **/
void
gtk_range_set_restrict_to_fill_level (GtkRange *range,
                                      gboolean  restrict_to_fill_level)
{
1380
  GtkRangePrivate *priv;
1381

1382 1383
  g_return_if_fail (GTK_IS_RANGE (range));

1384 1385
  priv = range->priv;

1386 1387
  restrict_to_fill_level = restrict_to_fill_level ? TRUE : FALSE;

1388
  if (restrict_to_fill_level != priv->restrict_to_fill_level)
1389
    {
1390
      priv->restrict_to_fill_level = restrict_to_fill_level;