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
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"
Matthias Clasen's avatar
Matthias Clasen committed
32
#include "gtkrangeprivate.h"
33

34
#include "gtkadjustmentprivate.h"
35
#include "gtkboxgadgetprivate.h"
36 37
#include "gtkbuiltiniconprivate.h"
#include "gtkcsscustomgadgetprivate.h"
38 39
#include "gtkcolorscaleprivate.h"
#include "gtkintl.h"
40
#include "gtkgesturelongpressprivate.h"
41
#include "gtkmain.h"
42
#include "gtkmarshalers.h"
43
#include "gtkorientableprivate.h"
44
#include "gtkprivate.h"
45
#include "gtkscale.h"
46
#include "gtkscrollbar.h"
47
#include "gtktypebuiltins.h"
48
#include "gtkwindow.h"
49
#include "gtkwidgetprivate.h"
50
#include "a11y/gtkrangeaccessible.h"
51
#include "gtkcssstylepropertyprivate.h"
52 53 54 55 56 57 58

/**
 * 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
59
 * adjustment, e.g #GtkScale or #GtkScrollbar.
60 61 62
 *
 * Apart from signals for monitoring the parameters of the adjustment,
 * #GtkRange provides properties and methods for influencing the sensitivity
William Jon McCann's avatar
William Jon McCann committed
63 64
 * of the “steppers”. It also provides properties and methods for setting a
 * “fill level” on range widgets. See gtk_range_set_fill_level().
65 66 67
 */


68
#define TIMEOUT_INITIAL     500
Benjamin Otte's avatar
Benjamin Otte committed
69
#define TIMEOUT_REPEAT      250
70
#define AUTOSCROLL_FACTOR   20
Benjamin Otte's avatar
Benjamin Otte committed
71
#define SCROLL_EDGE_SIZE    15
72
#define MARK_SNAP_LENGTH    12
Elliot Lee's avatar
Elliot Lee committed
73

74
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
75

76
struct _GtkRangePrivate
77
{
78
  GtkCssGadget *mouse_location;
79
  /* last mouse coords we got, or G_MININT if mouse is outside the range */
80 81
  gint  mouse_x;
  gint  mouse_y;
82
  GtkCssGadget *grab_location;   /* "grabbed" mouse location, NULL for no grab */
83

84
  GtkRangeStepTimer *timer;
85

86 87 88 89 90
  GtkAdjustment     *adjustment;
  GtkSensitivityType lower_sensitivity;
  GtkSensitivityType upper_sensitivity;

  GdkWindow         *event_window;
91

92 93 94
  /* Steppers are: < > ---- < >
   *               a b      c d
   */
95
  GtkCssGadget *gadget;
96
  GtkCssGadget *contents_gadget;
97 98 99 100 101 102 103 104
  GtkCssGadget *stepper_a_gadget;
  GtkCssGadget *stepper_b_gadget;
  GtkCssGadget *stepper_c_gadget;
  GtkCssGadget *stepper_d_gadget;
  GtkCssGadget *trough_gadget;
  GtkCssGadget *fill_gadget;
  GtkCssGadget *highlight_gadget;
  GtkCssGadget *slider_gadget;
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
  guint flippable              : 1;
  guint inverted               : 1;
  guint slider_size_fixed      : 1;
121
  guint slider_use_min_size    : 1;
122
  guint trough_click_forward   : 1;  /* trough click was on the forward side of slider */
123 124

  /* Stepper sensitivity */
125 126
  guint lower_sensitive        : 1;
  guint upper_sensitive        : 1;
127

128 129 130
  /* The range has an origin, should be drawn differently. Used by GtkScale */
  guint has_origin             : 1;

131 132
  /* Whether we're doing fine adjustment */
  guint zoom                   : 1;
133

134
  /* Fill level */
135
  guint show_fill_level        : 1;
136
  guint restrict_to_fill_level : 1;
137 138 139

  /* Whether dragging is ongoing */
  guint in_drag                : 1;
140 141 142 143 144 145 146

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

  GtkScrollType autoscroll_mode;
  guint autoscroll_id;
147
};
148

149

150 151 152 153 154 155 156 157
enum {
  PROP_0,
  PROP_ADJUSTMENT,
  PROP_INVERTED,
  PROP_LOWER_STEPPER_SENSITIVITY,
  PROP_UPPER_STEPPER_SENSITIVITY,
  PROP_SHOW_FILL_LEVEL,
  PROP_RESTRICT_TO_FILL_LEVEL,
158
  PROP_FILL_LEVEL,
159 160 161
  PROP_ROUND_DIGITS,
  PROP_ORIENTATION,
  LAST_PROP = PROP_ORIENTATION
162
};
163

164 165 166 167 168 169
enum {
  VALUE_CHANGED,
  ADJUST_BOUNDS,
  MOVE_SLIDER,
  CHANGE_VALUE,
  LAST_SIGNAL
170 171 172 173 174 175 176 177 178 179
};

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);
180
static void gtk_range_destroy        (GtkWidget        *widget);
181 182 183 184 185 186 187 188
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);
189 190 191 192
static void gtk_range_size_allocate  (GtkWidget        *widget,
                                      GtkAllocation    *allocation);
static void gtk_range_realize        (GtkWidget        *widget);
static void gtk_range_unrealize      (GtkWidget        *widget);
193 194
static void gtk_range_map            (GtkWidget        *widget);
static void gtk_range_unmap          (GtkWidget        *widget);
Benjamin Otte's avatar
Benjamin Otte committed
195 196
static gboolean gtk_range_draw       (GtkWidget        *widget,
                                      cairo_t          *cr);
197 198 199 200 201 202 203 204 205 206 207

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);
208 209 210 211
static void gtk_range_drag_gesture_begin          (GtkGestureDrag       *gesture,
                                                   gdouble               offset_x,
                                                   gdouble               offset_y,
                                                   GtkRange             *range);
212 213 214 215 216 217 218 219 220 221
static void gtk_range_drag_gesture_update         (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);


Matthias Clasen's avatar
Matthias Clasen committed
222
static gboolean gtk_range_scroll_event   (GtkWidget        *widget,
223
                                      GdkEventScroll   *event);
224 225
static gboolean gtk_range_event       (GtkWidget       *widget,
                                       GdkEvent        *event);
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 void add_autoscroll           (GtkRange         *range);
static void remove_autoscroll        (GtkRange         *range);
232 233

/* Range methods */
234

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

/* Internals */
239 240 241
static void          gtk_range_compute_slider_position  (GtkRange      *range,
                                                         gdouble        adjustment_value,
                                                         GdkRectangle  *slider_rect);
242
static gboolean      gtk_range_scroll                   (GtkRange      *range,
243
                                                         GtkScrollType  scroll);
244
static void          gtk_range_update_mouse_location    (GtkRange      *range);
245 246
static void          gtk_range_calc_slider              (GtkRange      *range);
static void          gtk_range_calc_stepper_sensitivity (GtkRange      *range);
247
static void          gtk_range_calc_marks               (GtkRange      *range);
248 249 250 251 252 253 254
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);
255 256 257
static gboolean      gtk_range_real_change_value        (GtkRange      *range,
                                                         GtkScrollType  scroll,
                                                         gdouble        value);
258 259
static gboolean      gtk_range_key_press                (GtkWidget     *range,
							 GdkEventKey   *event);
260 261
static void          gtk_range_state_flags_changed      (GtkWidget     *widget,
                                                         GtkStateFlags  previous_state);
262 263
static void          gtk_range_direction_changed        (GtkWidget     *widget,
                                                         GtkTextDirection  previous_direction);
264 265
static void          gtk_range_measure_trough           (GtkCssGadget   *gadget,
                                                         GtkOrientation  orientation,
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
                                                         gint            for_size,
                                                         gint           *minimum,
                                                         gint           *natural,
                                                         gint           *minimum_baseline,
                                                         gint           *natural_baseline,
                                                         gpointer        user_data);
static void          gtk_range_allocate_trough          (GtkCssGadget        *gadget,
                                                         const GtkAllocation *allocation,
                                                         int                  baseline,
                                                         GtkAllocation       *out_clip,
                                                         gpointer             data);
static gboolean      gtk_range_render_trough            (GtkCssGadget *gadget,
                                                         cairo_t      *cr,
                                                         int           x,
                                                         int           y,
                                                         int           width,
                                                         int           height,
                                                         gpointer      user_data);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
static void          gtk_range_measure                  (GtkCssGadget   *gadget,
                                                         GtkOrientation  orientation,
                                                         gint            for_size,
                                                         gint           *minimum,
                                                         gint           *natural,
                                                         gint           *minimum_baseline,
                                                         gint           *natural_baseline,
                                                         gpointer        user_data);
static void          gtk_range_allocate                 (GtkCssGadget        *gadget,
                                                         const GtkAllocation *allocation,
                                                         int                  baseline,
                                                         GtkAllocation       *out_clip,
                                                         gpointer             data);
static gboolean      gtk_range_render                   (GtkCssGadget *gadget,
                                                         cairo_t      *cr,
                                                         int           x,
                                                         int           y,
                                                         int           width,
                                                         int           height,
                                                         gpointer      user_data);
Elliot Lee's avatar
Elliot Lee committed
304

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

310
static guint signals[LAST_SIGNAL];
311
static GParamSpec *properties[LAST_PROP];
Elliot Lee's avatar
Elliot Lee committed
312 313 314 315

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

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

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

325
  widget_class->destroy = gtk_range_destroy;
326 327
  widget_class->get_preferred_width = gtk_range_get_preferred_width;
  widget_class->get_preferred_height = gtk_range_get_preferred_height;
328 329
  widget_class->size_allocate = gtk_range_size_allocate;
  widget_class->realize = gtk_range_realize;
330
  widget_class->unrealize = gtk_range_unrealize;
331 332
  widget_class->map = gtk_range_map;
  widget_class->unmap = gtk_range_unmap;
Benjamin Otte's avatar
Benjamin Otte committed
333
  widget_class->draw = gtk_range_draw;
334
  widget_class->event = gtk_range_event;
335
  widget_class->scroll_event = gtk_range_scroll_event;
336
  widget_class->key_press_event = gtk_range_key_press;
337
  widget_class->state_flags_changed = gtk_range_state_flags_changed;
338
  widget_class->direction_changed = gtk_range_direction_changed;
339 340

  class->move_slider = gtk_range_move_slider;
341
  class->change_value = gtk_range_real_change_value;
342

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

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

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

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

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
  g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");

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

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

  properties[PROP_LOWER_STEPPER_SENSITIVITY] =
      g_param_spec_enum ("lower-stepper-sensitivity",
                         P_("Lower stepper sensitivity"),
                         P_("The sensitivity policy for the stepper that points to the adjustment's lower side"),
                         GTK_TYPE_SENSITIVITY_TYPE,
                         GTK_SENSITIVITY_AUTO,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  properties[PROP_UPPER_STEPPER_SENSITIVITY] =
      g_param_spec_enum ("upper-stepper-sensitivity",
                         P_("Upper stepper sensitivity"),
                         P_("The sensitivity policy for the stepper that points to the adjustment's upper side"),
                         GTK_TYPE_SENSITIVITY_TYPE,
                         GTK_SENSITIVITY_AUTO,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
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
   * graphics are displayed on the trough. See
   * gtk_range_set_show_fill_level().
   *
   * Since: 2.12
   **/
472 473 474 475 476 477
  properties[PROP_SHOW_FILL_LEVEL] =
      g_param_spec_boolean ("show-fill-level",
                            P_("Show Fill Level"),
                            P_("Whether to display a fill level indicator graphics on trough."),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
478 479 480 481

  /**
   * GtkRange:restrict-to-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
482
   * The restrict-to-fill-level property controls whether slider
483
   * movement is restricted to an upper boundary set by the
Matthias Clasen's avatar
Matthias Clasen committed
484
   * fill level. See gtk_range_set_restrict_to_fill_level().
485 486 487
   *
   * Since: 2.12
   **/
488 489 490 491 492 493
  properties[PROP_RESTRICT_TO_FILL_LEVEL] =
      g_param_spec_boolean ("restrict-to-fill-level",
                            P_("Restrict to Fill Level"),
                            P_("Whether to restrict the upper boundary to the fill level."),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
494 495 496 497 498 499 500 501 502

  /**
   * GtkRange:fill-level:
   *
   * The fill level (e.g. prebuffering of a network stream).
   * See gtk_range_set_fill_level().
   *
   * Since: 2.12
   **/
503 504 505 506 507 508 509
  properties[PROP_FILL_LEVEL] =
      g_param_spec_double ("fill-level",
                           P_("Fill Level"),
                           P_("The fill level."),
                           -G_MAXDOUBLE, G_MAXDOUBLE,
                           G_MAXDOUBLE,
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
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
   */
519 520 521 522 523 524 525 526 527
  properties[PROP_ROUND_DIGITS] =
      g_param_spec_int ("round-digits",
                        P_("Round Digits"),
                        P_("The number of digits to round the value to."),
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, LAST_PROP, properties);
528

529 530 531 532 533
  /**
   * GtkRange:slider-width:
   *
   * Width of scrollbar or scale thumb.
   *
Timm Bäder's avatar
Timm Bäder committed
534
   * Deprecated: 3.20: Use the min-height/min-width CSS properties on the
535 536
   *   slider element. The value of this style property is ignored.
   */
537
  gtk_widget_class_install_style_property (widget_class,
538
					   g_param_spec_int ("slider-width",
539 540
							     P_("Slider Width"),
							     P_("Width of scrollbar or scale thumb"),
541 542
							     0,
							     G_MAXINT,
543
							     14,
544 545 546 547 548 549
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  /**
   * GtkRange:trough-border:
   *
   * Spacing between thumb/steppers and outer trough bevel.
   *
Timm Bäder's avatar
Timm Bäder committed
550
   * Deprecated: 3.20: Use the margin/padding CSS properties on the trough and
551 552
   *   stepper elements. The value of this style property is ignored.
   */
553
  gtk_widget_class_install_style_property (widget_class,
554
					   g_param_spec_int ("trough-border",
555 556
                                                             P_("Trough Border"),
                                                             P_("Spacing between thumb/steppers and outer trough bevel"),
557 558 559
                                                             0,
                                                             G_MAXINT,
                                                             1,
560 561 562 563 564 565
                                                             GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  /**
   * GtkRange:stepper-size:
   *
   * Length of step buttons at ends.
   *
Timm Bäder's avatar
Timm Bäder committed
566
   * Deprecated: 3.20: Use the min-height/min-width CSS properties on the
567 568
   *   stepper elements. The value of this style property is ignored.
   */
569
  gtk_widget_class_install_style_property (widget_class,
570
					   g_param_spec_int ("stepper-size",
571 572
							     P_("Stepper Size"),
							     P_("Length of step buttons at ends"),
573 574
							     0,
							     G_MAXINT,
575
							     14,
576
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
577 578 579 580 581
  /**
   * 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.
582
   *
Timm Bäder's avatar
Timm Bäder committed
583
   * Deprecated: 3.20: Use the margin CSS property on the stepper elements.
584
   *   The value of this style property is ignored.
585
   */
586
  gtk_widget_class_install_style_property (widget_class,
587
					   g_param_spec_int ("stepper-spacing",
588 589
							     P_("Stepper Spacing"),
							     P_("Spacing between step buttons and thumb"),
590
                                                             0,
591
							     G_MAXINT,
592
							     0,
593
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
594 595 596 597 598 599 600 601

  /**
   * GtkRange:arrow-displacement-x:
   *
   * How far in the x direction to move the arrow when the button is depressed.
   *
   * Deprecated: 3.20: The value of this style property is ignored.
   */
602
  gtk_widget_class_install_style_property (widget_class,
603
					   g_param_spec_int ("arrow-displacement-x",
604 605
							     P_("Arrow X Displacement"),
							     P_("How far in the x direction to move the arrow when the button is depressed"),
606 607 608
							     G_MININT,
							     G_MAXINT,
							     0,
609
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
610 611 612 613 614 615 616 617

  /**
   * GtkRange:arrow-displacement-y:
   *
   * How far in the y direction to move the arrow when the button is depressed.
   *
   * Deprecated: 3.20: The value of this style property is ignored.
   */
618
  gtk_widget_class_install_style_property (widget_class,
619
					   g_param_spec_int ("arrow-displacement-y",
620 621
							     P_("Arrow Y Displacement"),
							     P_("How far in the y direction to move the arrow when the button is depressed"),
622 623 624
							     G_MININT,
							     G_MAXINT,
							     0,
625
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
626

627 628 629 630
  /**
   * GtkRange:trough-under-steppers:
   *
   * Whether to draw the trough across the full length of the range or
631
   * to exclude the steppers and their spacing.
632 633
   *
   * Since: 2.10
634 635 636
   *
   * Deprecated: 3.20: The value of this style property is ignored, and the
   *   widget will behave as if it was set to %TRUE.
637 638 639 640
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boolean ("trough-under-steppers",
                                                                 P_("Trough Under Steppers"),
641
                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
642
                                                                 TRUE,
643
                                                                 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
644

645 646 647 648 649 650
  /**
   * GtkRange:arrow-scaling:
   *
   * The arrow size proportion relative to the scroll button size.
   *
   * Since: 2.14
651 652 653
   *
   * Deprecated: 3.20: Use min-width/min-height on the "button" node instead.
   *   The value of this style property is ignored.
654 655 656 657 658 659
   */
  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,
660
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
661

662
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
663 664
}

665 666 667 668 669 670 671 672
static void
gtk_range_sync_orientation (GtkRange *range)
{
  GtkRangePrivate *priv = range->priv;
  GtkOrientation orientation;

  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));
673
  gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->contents_gadget), orientation);
674 675

  if (orientation == GTK_ORIENTATION_VERTICAL)
676
    gtk_box_gadget_set_gadget_expand (GTK_BOX_GADGET (priv->contents_gadget),
677
                                      priv->trough_gadget, FALSE, TRUE);
678
  else
679
    gtk_box_gadget_set_gadget_expand (GTK_BOX_GADGET (priv->contents_gadget),
680
                                      priv->trough_gadget, TRUE, FALSE);
681 682
}

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

Alexander Larsson's avatar
Alexander Larsson committed
692
  switch (prop_id)
693
    {
694
    case PROP_ORIENTATION:
695 696 697
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
698
          gtk_range_sync_orientation (range);
699 700 701
          gtk_widget_queue_resize (GTK_WIDGET (range));
          g_object_notify_by_pspec (object, pspec);
        }
702
      break;
703 704 705
    case PROP_ADJUSTMENT:
      gtk_range_set_adjustment (range, g_value_get_object (value));
      break;
Havoc Pennington's avatar
Havoc Pennington committed
706 707 708
    case PROP_INVERTED:
      gtk_range_set_inverted (range, g_value_get_boolean (value));
      break;
709 710 711 712 713 714
    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;
715 716 717 718 719 720 721 722 723
    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;
724 725 726
    case PROP_ROUND_DIGITS:
      gtk_range_set_round_digits (range, g_value_get_int (value));
      break;
727
    default:
Alexander Larsson's avatar
Alexander Larsson committed
728
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
729 730 731 732 733
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
734 735 736 737
gtk_range_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
738
{
739
  GtkRange *range = GTK_RANGE (object);
740
  GtkRangePrivate *priv = range->priv;
741

Alexander Larsson's avatar
Alexander Larsson committed
742
  switch (prop_id)
743
    {
744
    case PROP_ORIENTATION:
745
      g_value_set_enum (value, priv->orientation);
746
      break;
747
    case PROP_ADJUSTMENT:
748
      g_value_set_object (value, priv->adjustment);
749
      break;
Havoc Pennington's avatar
Havoc Pennington committed
750
    case PROP_INVERTED:
751
      g_value_set_boolean (value, priv->inverted);
Havoc Pennington's avatar
Havoc Pennington committed
752
      break;
753 754 755 756 757 758
    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;
759 760 761 762 763 764 765 766 767
    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;
768 769 770
    case PROP_ROUND_DIGITS:
      g_value_set_int (value, gtk_range_get_round_digits (range));
      break;
771
    default:
Alexander Larsson's avatar
Alexander Larsson committed
772
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773 774 775 776
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
777 778 779
static void
gtk_range_init (GtkRange *range)
{
780
  GtkRangePrivate *priv;
781
  GtkCssNode *widget_node;
782

783
  range->priv = gtk_range_get_instance_private (range);
784 785
  priv = range->priv;

786
  gtk_widget_set_has_window (GTK_WIDGET (range), FALSE);
787

788 789 790 791 792 793
  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  priv->adjustment = NULL;
  priv->inverted = FALSE;
  priv->flippable = FALSE;
  priv->min_slider_size = 1;
  priv->round_digits = -1;
794 795
  priv->mouse_x = G_MININT;
  priv->mouse_y = G_MININT;
796 797 798 799
  priv->lower_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->upper_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->lower_sensitive = TRUE;
  priv->upper_sensitive = TRUE;
800
  priv->has_origin = FALSE;
801 802 803 804
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
805

806 807
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));

808
  widget_node = gtk_widget_get_css_node (GTK_WIDGET (range));
809 810 811 812 813 814 815 816 817
  priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
                                                     GTK_WIDGET (range),
                                                     gtk_range_measure,
                                                     gtk_range_allocate,
                                                     gtk_range_render,
                                                     NULL, NULL);
  priv->contents_gadget = gtk_box_gadget_new ("contents",
                                              GTK_WIDGET (range),
                                              priv->gadget, NULL);
818 819 820 821
  priv->trough_gadget = gtk_css_custom_gadget_new ("trough",
                                                   GTK_WIDGET (range),
                                                   NULL, NULL,
                                                   gtk_range_measure_trough,
822 823
                                                   gtk_range_allocate_trough,
                                                   gtk_range_render_trough,
824
                                                   NULL, NULL);
825 826
  gtk_css_gadget_set_state (priv->trough_gadget,
                            gtk_css_node_get_state (widget_node));
827
  gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->contents_gadget), -1, priv->trough_gadget,
828
                                TRUE, FALSE, GTK_ALIGN_CENTER);
829 830 831 832

  priv->slider_gadget = gtk_builtin_icon_new ("slider",
                                              GTK_WIDGET (range),
                                              priv->trough_gadget, NULL);
833 834
  gtk_css_gadget_set_state (priv->slider_gadget,
                            gtk_css_node_get_state (widget_node));
835

836 837 838 839 840 841 842
  /* 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));
843
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
844 845 846 847 848
  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);

849
  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (range));
850
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
851
  gtk_gesture_group (priv->drag_gesture, priv->multipress_gesture);
852 853 854 855 856 857
  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));
858
  g_object_set (priv->long_press_gesture, "delay-factor", 2.0, NULL);
859 860 861
  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
862 863
}

864 865 866 867
/**
 * gtk_range_get_adjustment:
 * @range: a #GtkRange
 * 
William Jon McCann's avatar
William Jon McCann committed
868
 * Get the #GtkAdjustment which is the “model” object for #GtkRange.
869 870 871 872
 * See gtk_range_set_adjustment() for details.
 * The return value does not have a reference added, so should not
 * be unreferenced.
 * 
873
 * Returns: (transfer none): a #GtkAdjustment
874
 **/
Elliot Lee's avatar
Elliot Lee committed
875 876 877
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
878
  GtkRangePrivate *priv;
879

Elliot Lee's avatar
Elliot Lee committed
880 881
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

882 883 884
  priv = range->priv;

  if (!priv->adjustment)
885 886
    gtk_range_set_adjustment (range, NULL);

887
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
888 889
}

890 891 892 893 894
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
William Jon McCann's avatar
William Jon McCann committed
895
 * Sets the adjustment to be used as the “model” object for this range
896 897 898 899 900 901 902
 * 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
903 904 905 906
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
907
  GtkRangePrivate *priv;
908

Elliot Lee's avatar
Elliot Lee committed
909
  g_return_if_fail (GTK_IS_RANGE (range));
910 911 912

  priv = range->priv;

913
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
914
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
915 916
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
917

918
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
919
    {
920
      if (priv->adjustment)
921
	{
922
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
923 924
						gtk_range_adjustment_changed,
						range);
925
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
926 927
						gtk_range_adjustment_value_changed,
						range);
928
	  g_object_unref (priv->adjustment);
929
	}
930

931
      priv->adjustment = adjustment;
932
      g_object_ref_sink (adjustment);
933
      
Manish Singh's avatar
Manish Singh committed
934 935 936
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
937
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
938 939
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
940
      
941
      gtk_range_adjustment_changed (adjustment, range);
942
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_ADJUSTMENT]);
Elliot Lee's avatar
Elliot Lee committed
943 944 945
    }
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
static gboolean
should_invert (GtkRange *range)
{
  GtkRangePrivate *priv = range->priv;

  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
    return
      (priv->inverted && !priv->flippable) ||
      (priv->inverted && priv->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
      (!priv->inverted && priv->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
  else
    return priv->inverted;
}

static void
update_highlight_position (GtkRange *range)
{
  GtkRangePrivate *priv = range->priv;

  if (!priv->highlight_gadget)
    return;

  if (should_invert (range))
    {
      gtk_css_gadget_remove_class (priv->highlight_gadget, GTK_STYLE_CLASS_TOP);
      gtk_css_gadget_add_class (priv->highlight_gadget, GTK_STYLE_CLASS_BOTTOM);
    }
  else
    {
      gtk_css_gadget_remove_class (priv->highlight_gadget, GTK_STYLE_CLASS_BOTTOM);
      gtk_css_gadget_add_class (priv->highlight_gadget, GTK_STYLE_CLASS_TOP);
    }
}

static void
update_fill_position (GtkRange *range)
{
  GtkRangePrivate *priv = range->priv;

  if (!priv->fill_gadget)
    return;

  if (should_invert (range))
    {
      gtk_css_gadget_remove_class (priv->fill_gadget, GTK_STYLE_CLASS_TOP);
      gtk_css_gadget_add_class (priv->fill_gadget, GTK_STYLE_CLASS_BOTTOM);
    }
  else
    {
      gtk_css_gadget_remove_class (priv->fill_gadget, GTK_STYLE_CLASS_BOTTOM);
      gtk_css_gadget_add_class (priv->fill_gadget, GTK_STYLE_CLASS_TOP);
    }
}

1000
static void
1001 1002
update_stepper_state (GtkRange     *range,
                      GtkCssGadget *gadget)
1003 1004 1005 1006 1007 1008 1009
{
  GtkRangePrivate *priv = range->priv;
  GtkStateFlags state;
  gboolean arrow_sensitive;

  state = gtk_widget_get_state_flags (GTK_WIDGET (range));

1010 1011 1012 1013
  if ((!priv->inverted &&
       (gadget == priv->stepper_a_gadget || gadget == priv->stepper_c_gadget)) ||
      (priv->inverted &&
       (gadget == priv->stepper_b_gadget || gadget == priv->stepper_d_gadget)))
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    arrow_sensitive = priv->lower_sensitive;
  else
    arrow_sensitive = priv->upper_sensitive;

  state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT);

  if ((state & GTK_STATE_FLAG_INSENSITIVE) || !arrow_sensitive)
    {
      state |= GTK_STATE_FLAG_INSENSITIVE;
    }
  else
    {
1026
      if (priv->grab_location == gadget)
1027
        state |= GTK_STATE_FLAG_ACTIVE;
1028
      if (priv->mouse_location == gadget)
1029 1030 1031
        state |= GTK_STATE_FLAG_PRELIGHT;
    }

1032
  gtk_css_gadget_set_state (gadget, state);
1033 1034 1035 1036 1037 1038 1039
}

static void
update_steppers_state (GtkRange *range)
{
  GtkRangePrivate *priv = range->priv;

1040
  if (priv->stepper_a_gadget)
1041
    update_stepper_state (range, priv->stepper_a_gadget);
1042
  if (priv->stepper_b_gadget)
1043
    update_stepper_state (range, priv->stepper_b_gadget);
1044
  if (priv->stepper_c_gadget)
1045
    update_stepper_state (range, priv->stepper_c_gadget);
1046
  if (priv->stepper_d_gadget)
1047
    update_stepper_state (range, priv->stepper_d_gadget);
1048 1049
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
/**
 * 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.
 **/
1060 1061 1062 1063
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
1064
  GtkRangePrivate *priv;
1065

1066
  g_return_if_fail (GTK_IS_RANGE (range));
1067 1068 1069

  priv = range->priv;

1070 1071
  setting = setting != FALSE;

1072
  if (setting != priv->inverted)
1073
    {
1074
      priv->inverted = setting;
1075 1076

      update_steppers_state (range);
1077 1078 1079
      update_fill_position (range);
      update_highlight_position (range);

1080
      gtk_widget_queue_resize (GTK_WIDGET (range));
1081 1082

      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_INVERTED]);
1083 1084 1085
    }
}

1086 1087 1088 1089 1090 1091
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
1092
 * Returns: %TRUE if the range is inverted
1093
 **/
1094 1095 1096 1097 1098
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1099
  return range->priv->inverted;
1100 1101
}

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
/**
 * 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)
{
1118
  GtkRangePrivate *priv;
1119

1120 1121
  g_return_if_fail (GTK_IS_RANGE (range));

1122 1123
  priv = range->priv;

1124 1125
  flippable = flippable ? TRUE : FALSE;

1126
  if (flippable != priv->flippable)
1127
    {
1128
      priv->flippable = flippable;
1129 1130
      update_fill_position (range);
      update_highlight_position (range);
1131

1132
      gtk_widget_queue_allocate (GTK_WIDGET (range));
1133 1134 1135 1136 1137 1138 1139 1140 1141
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
1142
 * Returns: %TRUE if the range is flippable
1143 1144 1145 1146 1147 1148 1149 1150
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1151
  return range->priv->flippable;
1152 1153
}

1154