gtkrange.c 123 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3
 * Copyright (C) 2001 Red Hat, Inc.
Elliot Lee's avatar
Elliot Lee committed
4 5
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
16
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18 19

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

26
#include "config.h"
27

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

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

34
#include "gtkadjustmentprivate.h"
35
#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
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
Elliot Lee's avatar
Elliot Lee committed
72

73
typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
74

75 76 77 78 79 80 81 82 83 84 85
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;

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

94
  GtkRangeStepTimer *timer;
95

96 97 98 99 100
  GtkAdjustment     *adjustment;
  GtkSensitivityType lower_sensitivity;
  GtkSensitivityType upper_sensitivity;

  GdkWindow         *event_window;
101

102 103 104
  /* Steppers are: < > ---- < >
   *               a b      c d
   */
105
  GtkCssGadget *gadget;
106
  GtkCssGadget *contents_gadget;
107 108 109 110 111 112 113 114
  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;
115

116
  GtkOrientation     orientation;
117 118 119 120 121 122 123 124 125

  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;
126
  gint  slide_initial_coordinate_delta;
127

128 129 130 131
  guint flippable              : 1;
  guint inverted               : 1;
  guint slider_size_fixed      : 1;
  guint trough_click_forward   : 1;  /* trough click was on the forward side of slider */
132 133

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

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

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

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

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

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

  GtkScrollType autoscroll_mode;
  guint autoscroll_id;
156
};
157

158

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

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

181
typedef enum {
182 183 184 185
  STEPPER_A = MOUSE_STEPPER_A,
  STEPPER_B = MOUSE_STEPPER_B,
  STEPPER_C = MOUSE_STEPPER_C,
  STEPPER_D = MOUSE_STEPPER_D
186
} Stepper;
187

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

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


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

/* Range methods */
250

251
static void gtk_range_move_slider              (GtkRange         *range,
252 253 254
                                                GtkScrollType     scroll);

/* Internals */
255 256 257
static void          gtk_range_compute_slider_position  (GtkRange      *range,
                                                         gdouble        adjustment_value,
                                                         GdkRectangle  *slider_rect);
258
static gboolean      gtk_range_scroll                   (GtkRange      *range,
259
                                                         GtkScrollType  scroll);
260
static void          gtk_range_update_mouse_location    (GtkRange      *range);
261 262
static void          gtk_range_calc_slider              (GtkRange      *range);
static void          gtk_range_calc_stepper_sensitivity (GtkRange      *range);
263
static void          gtk_range_calc_marks               (GtkRange      *range);
264 265 266 267 268 269 270
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);
271
static void          gtk_range_queue_draw_location      (GtkRange      *range,
272
                                                         MouseLocation  location);
273 274 275
static gboolean      gtk_range_real_change_value        (GtkRange      *range,
                                                         GtkScrollType  scroll,
                                                         gdouble        value);
276 277
static gboolean      gtk_range_key_press                (GtkWidget     *range,
							 GdkEventKey   *event);
278 279
static void          gtk_range_state_flags_changed      (GtkWidget     *widget,
                                                         GtkStateFlags  previous_state);
280 281
static void          gtk_range_measure_trough           (GtkCssGadget   *gadget,
                                                         GtkOrientation  orientation,
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
                                                         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);
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
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
320

321
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET,
322
                                  G_ADD_PRIVATE (GtkRange)
323 324 325
                                  G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                         NULL))

326
static guint signals[LAST_SIGNAL];
327
static GParamSpec *properties[LAST_PROP];
Elliot Lee's avatar
Elliot Lee committed
328 329 330 331

static void
gtk_range_class_init (GtkRangeClass *class)
{
Alexander Larsson's avatar
Alexander Larsson committed
332
  GObjectClass   *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
333 334
  GtkWidgetClass *widget_class;

Alexander Larsson's avatar
Alexander Larsson committed
335
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
336 337
  widget_class = (GtkWidgetClass*) class;

Alexander Larsson's avatar
Alexander Larsson committed
338 339
  gobject_class->set_property = gtk_range_set_property;
  gobject_class->get_property = gtk_range_get_property;
340

341
  widget_class->destroy = gtk_range_destroy;
342 343
  widget_class->get_preferred_width = gtk_range_get_preferred_width;
  widget_class->get_preferred_height = gtk_range_get_preferred_height;
344 345
  widget_class->size_allocate = gtk_range_size_allocate;
  widget_class->realize = gtk_range_realize;
346
  widget_class->unrealize = gtk_range_unrealize;
347 348
  widget_class->map = gtk_range_map;
  widget_class->unmap = gtk_range_unmap;
349
  widget_class->draw = gtk_range_draw;
350
  widget_class->event = gtk_range_event;
351
  widget_class->scroll_event = gtk_range_scroll_event;
352
  widget_class->key_press_event = gtk_range_key_press;
353
  widget_class->state_flags_changed = gtk_range_state_flags_changed;
354 355

  class->move_slider = gtk_range_move_slider;
356
  class->change_value = gtk_range_real_change_value;
357

Matthias Clasen's avatar
Matthias Clasen committed
358 359
  /**
   * GtkRange::value-changed:
360
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
361 362 363
   *
   * Emitted when the range value changes.
   */
364
  signals[VALUE_CHANGED] =
365
    g_signal_new (I_("value-changed"),
Manish Singh's avatar
Manish Singh committed
366
                  G_TYPE_FROM_CLASS (gobject_class),
367 368 369
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, value_changed),
                  NULL, NULL,
370
                  _gtk_marshal_VOID__VOID,
371
                  G_TYPE_NONE, 0);
372 373 374 375 376

  /**
   * GtkRange::adjust-bounds:
   * @range: the #GtkRange that received the signal
   * @value: the value before we clamp
377 378 379
   *
   * Emitted before clamping a value, to give the application a
   * chance to adjust the bounds.
380
   */
381
  signals[ADJUST_BOUNDS] =
382
    g_signal_new (I_("adjust-bounds"),
Manish Singh's avatar
Manish Singh committed
383
                  G_TYPE_FROM_CLASS (gobject_class),
384 385 386 387 388 389
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkRangeClass, adjust_bounds),
                  NULL, NULL,
                  _gtk_marshal_VOID__DOUBLE,
                  G_TYPE_NONE, 1,
                  G_TYPE_DOUBLE);
390

Matthias Clasen's avatar
Matthias Clasen committed
391 392
  /**
   * GtkRange::move-slider:
393
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
394 395 396 397
   * @step: how to move the slider
   *
   * Virtual function that moves the slider. Used for keybindings.
   */
398
  signals[MOVE_SLIDER] =
399
    g_signal_new (I_("move-slider"),
Manish Singh's avatar
Manish Singh committed
400
                  G_TYPE_FROM_CLASS (gobject_class),
401 402 403
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkRangeClass, move_slider),
                  NULL, NULL,
404
                  _gtk_marshal_VOID__ENUM,
405 406
                  G_TYPE_NONE, 1,
                  GTK_TYPE_SCROLL_TYPE);
407 408 409

  /**
   * GtkRange::change-value:
410
   * @range: the #GtkRange that received the signal
Matthias Clasen's avatar
Matthias Clasen committed
411 412
   * @scroll: the type of scroll action that was performed
   * @value: the new value resulting from the scroll action
413
   *
414
   * The #GtkRange::change-value signal is emitted when a scroll action is
415 416 417 418 419 420 421 422
   * 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
423 424 425
   * 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.
426 427
   *
   * It is not possible to use delayed update policies in an overridden
428
   * #GtkRange::change-value handler.
429
   *
430 431 432
   * Returns: %TRUE to prevent other handlers from being invoked for
   *     the signal, %FALSE to propagate the signal further
   *
433 434 435
   * Since: 2.6
   */
  signals[CHANGE_VALUE] =
436
    g_signal_new (I_("change-value"),
437 438 439 440 441 442 443 444
                  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
445

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
  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);
477

478 479 480
  /**
   * GtkRange:show-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
481
   * The show-fill-level property controls whether fill level indicator
482 483 484 485 486
   * graphics are displayed on the trough. See
   * gtk_range_set_show_fill_level().
   *
   * Since: 2.12
   **/
487 488 489 490 491 492
  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);
493 494 495 496

  /**
   * GtkRange:restrict-to-fill-level:
   *
Matthias Clasen's avatar
Matthias Clasen committed
497
   * The restrict-to-fill-level property controls whether slider
498
   * movement is restricted to an upper boundary set by the
Matthias Clasen's avatar
Matthias Clasen committed
499
   * fill level. See gtk_range_set_restrict_to_fill_level().
500 501 502
   *
   * Since: 2.12
   **/
503 504 505 506 507 508
  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);
509 510 511 512 513 514 515 516 517

  /**
   * GtkRange:fill-level:
   *
   * The fill level (e.g. prebuffering of a network stream).
   * See gtk_range_set_fill_level().
   *
   * Since: 2.12
   **/
518 519 520 521 522 523 524
  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);
525

526 527 528 529 530 531 532 533
  /**
   * GtkRange:round-digits:
   *
   * The number of digits to round the value to when
   * it changes, or -1. See #GtkRange::change-value.
   *
   * Since: 2.24
   */
534 535 536 537 538 539 540 541 542
  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);
543

544 545 546 547 548 549 550 551
  /**
   * GtkRange:slider-width:
   *
   * Width of scrollbar or scale thumb.
   *
   * Depreacated: 3.20: Use the min-height/min-width CSS properties on the
   *   slider element. The value of this style property is ignored.
   */
552
  gtk_widget_class_install_style_property (widget_class,
553
					   g_param_spec_int ("slider-width",
554 555
							     P_("Slider Width"),
							     P_("Width of scrollbar or scale thumb"),
556 557
							     0,
							     G_MAXINT,
558
							     14,
559 560 561 562 563 564 565 566 567
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  /**
   * GtkRange:trough-border:
   *
   * Spacing between thumb/steppers and outer trough bevel.
   *
   * Depreacated: 3.20: Use the margin/padding CSS properties on the through and
   *   stepper elements. The value of this style property is ignored.
   */
568
  gtk_widget_class_install_style_property (widget_class,
569
					   g_param_spec_int ("trough-border",
570 571
                                                             P_("Trough Border"),
                                                             P_("Spacing between thumb/steppers and outer trough bevel"),
572 573 574
                                                             0,
                                                             G_MAXINT,
                                                             1,
575 576 577 578 579 580 581 582 583
                                                             GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  /**
   * GtkRange:stepper-size:
   *
   * Length of step buttons at ends.
   *
   * Depreacated: 3.20: Use the min-height/min-width CSS properties on the
   *   stepper elements. The value of this style property is ignored.
   */
584
  gtk_widget_class_install_style_property (widget_class,
585
					   g_param_spec_int ("stepper-size",
586 587
							     P_("Stepper Size"),
							     P_("Length of step buttons at ends"),
588 589
							     0,
							     G_MAXINT,
590
							     14,
591
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
592 593 594 595 596
  /**
   * 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.
597 598 599
   *
   * Depreacated: 3.20: Use the margin CSS property on the stepper elements.
   *   The value of this style property is ignored.
600
   */
601
  gtk_widget_class_install_style_property (widget_class,
602
					   g_param_spec_int ("stepper-spacing",
603 604
							     P_("Stepper Spacing"),
							     P_("Spacing between step buttons and thumb"),
605
                                                             0,
606
							     G_MAXINT,
607
							     0,
608
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
609 610 611 612 613 614 615 616

  /**
   * 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.
   */
617
  gtk_widget_class_install_style_property (widget_class,
618
					   g_param_spec_int ("arrow-displacement-x",
619 620
							     P_("Arrow X Displacement"),
							     P_("How far in the x direction to move the arrow when the button is depressed"),
621 622 623
							     G_MININT,
							     G_MAXINT,
							     0,
624
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
625 626 627 628 629 630 631 632

  /**
   * 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.
   */
633
  gtk_widget_class_install_style_property (widget_class,
634
					   g_param_spec_int ("arrow-displacement-y",
635 636
							     P_("Arrow Y Displacement"),
							     P_("How far in the y direction to move the arrow when the button is depressed"),
637 638 639
							     G_MININT,
							     G_MAXINT,
							     0,
640
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
641

642 643 644 645
  /**
   * GtkRange:trough-under-steppers:
   *
   * Whether to draw the trough across the full length of the range or
646
   * to exclude the steppers and their spacing.
647 648
   *
   * Since: 2.10
649 650 651
   *
   * Deprecated: 3.20: The value of this style property is ignored, and the
   *   widget will behave as if it was set to %TRUE.
652 653 654 655
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boolean ("trough-under-steppers",
                                                                 P_("Trough Under Steppers"),
656
                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
657
                                                                 TRUE,
658
                                                                 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
659

660 661 662 663 664 665
  /**
   * GtkRange:arrow-scaling:
   *
   * The arrow size proportion relative to the scroll button size.
   *
   * Since: 2.14
666 667 668
   *
   * Deprecated: 3.20: Use min-width/min-height on the "button" node instead.
   *   The value of this style property is ignored.
669 670 671 672 673 674
   */
  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,
675
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
676

677
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
678 679
}

680 681 682 683 684 685 686 687
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));
688
  gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->contents_gadget), orientation);
689 690

  if (orientation == GTK_ORIENTATION_VERTICAL)
691
    gtk_box_gadget_set_gadget_expand (GTK_BOX_GADGET (priv->contents_gadget),
692
                                      priv->trough_gadget, FALSE, TRUE);
693
  else
694
    gtk_box_gadget_set_gadget_expand (GTK_BOX_GADGET (priv->contents_gadget),
695
                                      priv->trough_gadget, TRUE, FALSE);
696 697
}

698
static void
Alexander Larsson's avatar
Alexander Larsson committed
699 700 701 702
gtk_range_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
703
{
704
  GtkRange *range = GTK_RANGE (object);
705
  GtkRangePrivate *priv = range->priv;
706

Alexander Larsson's avatar
Alexander Larsson committed
707
  switch (prop_id)
708
    {
709
    case PROP_ORIENTATION:
710 711 712
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
713
          gtk_range_sync_orientation (range);
714 715 716
          gtk_widget_queue_resize (GTK_WIDGET (range));
          g_object_notify_by_pspec (object, pspec);
        }
717
      break;
718 719 720
    case PROP_ADJUSTMENT:
      gtk_range_set_adjustment (range, g_value_get_object (value));
      break;
721 722 723
    case PROP_INVERTED:
      gtk_range_set_inverted (range, g_value_get_boolean (value));
      break;
724 725 726 727 728 729
    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;
730 731 732 733 734 735 736 737 738
    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;
739 740 741
    case PROP_ROUND_DIGITS:
      gtk_range_set_round_digits (range, g_value_get_int (value));
      break;
742
    default:
Alexander Larsson's avatar
Alexander Larsson committed
743
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
744 745 746 747 748
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
749 750 751 752
gtk_range_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
753
{
754
  GtkRange *range = GTK_RANGE (object);
755
  GtkRangePrivate *priv = range->priv;
756

Alexander Larsson's avatar
Alexander Larsson committed
757
  switch (prop_id)
758
    {
759
    case PROP_ORIENTATION:
760
      g_value_set_enum (value, priv->orientation);
761
      break;
762
    case PROP_ADJUSTMENT:
763
      g_value_set_object (value, priv->adjustment);
764
      break;
765
    case PROP_INVERTED:
766
      g_value_set_boolean (value, priv->inverted);
767
      break;
768 769 770 771 772 773
    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;
774 775 776 777 778 779 780 781 782
    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;
783 784 785
    case PROP_ROUND_DIGITS:
      g_value_set_int (value, gtk_range_get_round_digits (range));
      break;
786
    default:
Alexander Larsson's avatar
Alexander Larsson committed
787
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
788 789 790 791
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
792 793 794
static void
gtk_range_init (GtkRange *range)
{
795
  GtkRangePrivate *priv;
796
  GtkCssNode *widget_node;
797

798
  range->priv = gtk_range_get_instance_private (range);
799 800
  priv = range->priv;

801
  gtk_widget_set_has_window (GTK_WIDGET (range), FALSE);
802

803 804 805 806 807 808 809
  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  priv->adjustment = NULL;
  priv->inverted = FALSE;
  priv->flippable = FALSE;
  priv->min_slider_size = 1;
  priv->round_digits = -1;
  priv->mouse_location = MOUSE_OUTSIDE;
810 811
  priv->mouse_x = G_MININT;
  priv->mouse_y = G_MININT;
812 813 814 815 816
  priv->grab_location = MOUSE_OUTSIDE;
  priv->lower_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->upper_sensitivity = GTK_SENSITIVITY_AUTO;
  priv->lower_sensitive = TRUE;
  priv->upper_sensitive = TRUE;
817
  priv->has_origin = FALSE;
818 819 820 821
  priv->show_fill_level = FALSE;
  priv->restrict_to_fill_level = TRUE;
  priv->fill_level = G_MAXDOUBLE;
  priv->timer = NULL;
822

823 824
  _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));

825
  widget_node = gtk_widget_get_css_node (GTK_WIDGET (range));
826 827 828 829 830 831 832 833 834
  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);
835 836 837 838
  priv->trough_gadget = gtk_css_custom_gadget_new ("trough",
                                                   GTK_WIDGET (range),
                                                   NULL, NULL,
                                                   gtk_range_measure_trough,
839 840
                                                   gtk_range_allocate_trough,
                                                   gtk_range_render_trough,
841
                                                   NULL, NULL);
842 843
  gtk_css_gadget_set_state (priv->trough_gadget,
                            gtk_css_node_get_state (widget_node));
844
  gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->contents_gadget), -1, priv->trough_gadget,
845
                                TRUE, FALSE, GTK_ALIGN_CENTER);
846 847 848 849

  priv->slider_gadget = gtk_builtin_icon_new ("slider",
                                              GTK_WIDGET (range),
                                              priv->trough_gadget, NULL);
850 851
  gtk_css_gadget_set_state (priv->slider_gadget,
                            gtk_css_node_get_state (widget_node));
852

853 854 855 856 857 858 859
  /* 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));
860
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
861 862 863 864 865
  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);

866
  priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (range));
867
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
868
  gtk_gesture_group (priv->drag_gesture, priv->multipress_gesture);
869 870 871 872 873 874
  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));
875
  g_object_set (priv->long_press_gesture, "delay-factor", 2.0, NULL);
876 877 878
  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
879 880
}

881 882 883 884
/**
 * gtk_range_get_adjustment:
 * @range: a #GtkRange
 * 
885
 * Get the #GtkAdjustment which is the “model” object for #GtkRange.
886 887 888 889
 * See gtk_range_set_adjustment() for details.
 * The return value does not have a reference added, so should not
 * be unreferenced.
 * 
890
 * Returns: (transfer none): a #GtkAdjustment
891
 **/
Elliot Lee's avatar
Elliot Lee committed
892 893 894
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
895
  GtkRangePrivate *priv;
896

Elliot Lee's avatar
Elliot Lee committed
897 898
  g_return_val_if_fail (GTK_IS_RANGE (range), NULL);

899 900 901
  priv = range->priv;

  if (!priv->adjustment)
902 903
    gtk_range_set_adjustment (range, NULL);

904
  return priv->adjustment;
Elliot Lee's avatar
Elliot Lee committed
905 906
}

907 908 909 910 911
/**
 * gtk_range_set_adjustment:
 * @range: a #GtkRange
 * @adjustment: a #GtkAdjustment
 *
912
 * Sets the adjustment to be used as the “model” object for this range
913 914 915 916 917 918 919
 * 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
920 921 922 923
void
gtk_range_set_adjustment (GtkRange      *range,
			  GtkAdjustment *adjustment)
{
924
  GtkRangePrivate *priv;
925

Elliot Lee's avatar
Elliot Lee committed
926
  g_return_if_fail (GTK_IS_RANGE (range));
927 928 929

  priv = range->priv;

930
  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
931
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
932 933
  else
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
934

935
  if (priv->adjustment != adjustment)
Elliot Lee's avatar
Elliot Lee committed
936
    {
937
      if (priv->adjustment)
938
	{
939
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
940 941
						gtk_range_adjustment_changed,
						range);
942
	  g_signal_handlers_disconnect_by_func (priv->adjustment,
Manish Singh's avatar
Manish Singh committed
943 944
						gtk_range_adjustment_value_changed,
						range);
945
	  g_object_unref (priv->adjustment);
946
	}
947

948
      priv->adjustment = adjustment;
949
      g_object_ref_sink (adjustment);
950
      
Manish Singh's avatar
Manish Singh committed
951 952 953
      g_signal_connect (adjustment, "changed",
			G_CALLBACK (gtk_range_adjustment_changed),
			range);
954
      g_signal_connect (adjustment, "value-changed",
Manish Singh's avatar
Manish Singh committed
955 956
			G_CALLBACK (gtk_range_adjustment_value_changed),
			range);
957
      
958
      gtk_range_adjustment_changed (adjustment, range);
959
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_ADJUSTMENT]);
Elliot Lee's avatar
Elliot Lee committed
960 961 962
    }
}

963
static void
964 965 966
update_stepper_state (GtkRange     *range,
                      Stepper       stepper,
                      GtkCssGadget *gadget)
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
{
  GtkRangePrivate *priv = range->priv;
  GtkStateFlags state;
  gboolean arrow_sensitive;

  state = gtk_widget_get_state_flags (GTK_WIDGET (range));

  if ((!priv->inverted && (stepper == STEPPER_A ||
                           stepper == STEPPER_C)) ||
      (priv->inverted && (stepper == STEPPER_B ||
                          stepper == STEPPER_D)))
    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
    {
      if (priv->grab_location == (MouseLocation)stepper)
        state |= GTK_STATE_FLAG_ACTIVE;
      if (priv->mouse_location == (MouseLocation)stepper)
        state |= GTK_STATE_FLAG_PRELIGHT;
    }

996
  gtk_css_gadget_set_state (gadget, state);
997 998 999 1000 1001 1002 1003
}

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

1004 1005 1006 1007 1008 1009 1010 1011
  if (priv->stepper_a_gadget)
    update_stepper_state (range, STEPPER_A, priv->stepper_a_gadget);
  if (priv->stepper_b_gadget)
    update_stepper_state (range, STEPPER_B, priv->stepper_b_gadget);
  if (priv->stepper_c_gadget)
    update_stepper_state (range, STEPPER_C, priv->stepper_c_gadget);
  if (priv->stepper_d_gadget)
    update_stepper_state (range, STEPPER_D, priv->stepper_d_gadget);
1012 1013
}

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/**
 * 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.
 **/
1024 1025 1026 1027
void
gtk_range_set_inverted (GtkRange *range,
                        gboolean  setting)
{
1028
  GtkRangePrivate *priv;
1029

1030
  g_return_if_fail (GTK_IS_RANGE (range));
1031 1032 1033

  priv = range->priv;

1034 1035
  setting = setting != FALSE;

1036
  if (setting != priv->inverted)
1037
    {
1038
      priv->inverted = setting;
1039 1040

      update_steppers_state (range);
1041
      gtk_widget_queue_resize (GTK_WIDGET (range));
1042 1043

      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_INVERTED]);
1044 1045 1046
    }
}

1047 1048 1049 1050 1051 1052
/**
 * gtk_range_get_inverted:
 * @range: a #GtkRange
 * 
 * Gets the value set by gtk_range_set_inverted().
 * 
1053
 * Returns: %TRUE if the range is inverted
1054
 **/
1055 1056 1057 1058 1059
gboolean
gtk_range_get_inverted (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1060
  return range->priv->inverted;
1061 1062
}

1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
/**
 * 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)
{
1079
  GtkRangePrivate *priv;
1080

1081 1082
  g_return_if_fail (GTK_IS_RANGE (range));

1083 1084
  priv = range->priv;

1085 1086
  flippable = flippable ? TRUE : FALSE;

1087
  if (flippable != priv->flippable)
1088
    {
1089
      priv->flippable = flippable;
1090

1091
      gtk_widget_queue_allocate (GTK_WIDGET (range));
1092 1093 1094 1095 1096 1097 1098 1099 1100
    }
}

/**
 * gtk_range_get_flippable:
 * @range: a #GtkRange
 *
 * Gets the value set by gtk_range_set_flippable().
 *
1101
 * Returns: %TRUE if the range is flippable
1102 1103 1104 1105 1106 1107 1108 1109
 *
 * Since: 2.18
 **/
gboolean
gtk_range_get_flippable (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1110
  return range->priv->flippable;
1111 1112
}

1113 1114 1115 1116 1117
/**
 * gtk_range_set_slider_size_fixed:
 * @range: a #GtkRange
 * @size_fixed: %TRUE to make the slider size constant
 *
1118 1119
 * Sets whether the range’s slider has a fixed size, or a size that
 * depends on its adjustment’s page size.
1120 1121 1122 1123 1124 1125 1126 1127 1128
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_slider_size_fixed (GtkRange *range,
                                 gboolean  size_fixed)
{
1129
  GtkRangePrivate *priv;
1130

1131 1132
  g_return_if_fail (GTK_IS_RANGE (range));

1133 1134 1135
  priv = range->priv;

  if (size_fixed != priv->slider_size_fixed)
1136
    {
1137
      priv->slider_size_fixed = size_fixed ? TRUE : FALSE;
1138

1139
      if (priv->adjustment && gtk_widget_get_mapped (GTK_WIDGET (range)))
1140
        gtk_css_gadget_queue_allocate (priv->slider_gadget);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    }
}

/**
 * gtk_range_get_slider_size_fixed:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_slider_size_fixed().
 *
1152
 * Returns: whether the range’s slider has a fixed size.
1153 1154 1155 1156 1157 1158 1159 1160
 *
 * Since: 2.20
 **/
gboolean
gtk_range_get_slider_size_fixed (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1161
  return range->priv->slider_size_fixed;
1162 1163 1164 1165 1166
}

/**
 * gtk_range_set_min_slider_size:
 * @range: a #GtkRange
1167
 * @min_size: The slider’s minimum size
1168
 *
1169
 * Sets the minimum size of the range’s slider.
1170 1171 1172 1173 1174 1175 1176
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * Since: 2.20
 **/
void
gtk_range_set_min_slider_size (GtkRange *range,
1177
                               gint      min_size)
1178
{
1179
  GtkRangePrivate *priv;
1180

1181 1182 1183
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (min_size > 0);

1184 1185 1186
  priv = range->priv;

  if (min_size != priv->min_slider_size)
1187
    {
1188
      priv->min_slider_size = min_size;
1189

1190
      gtk_widget_queue_resize (GTK_WIDGET (range));
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    }
}

/**
 * gtk_range_get_min_slider_size:
 * @range: a #GtkRange
 *
 * This function is useful mainly for #GtkRange subclasses.
 *
 * See gtk_range_set_min_slider_size().
 *
1202
 * Returns: The minimum size of the range’s slider.
1203 1204 1205 1206 1207 1208 1209 1210
 *
 * Since: 2.20
 **/
gint
gtk_range_get_min_slider_size (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);

1211
  return range->priv->min_slider_size;
1212 1213
}

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
static void
measure_one_gadget (GtkCssGadget *gadget,
                    int          *width_out,
                    int          *height_out)
{
  gtk_css_gadget_get_preferred_size (gadget,
                                     GTK_ORIENTATION_HORIZONTAL, -1,
                                     width_out, NULL,
                                     NULL, NULL);
  gtk_css_gadget_get_preferred_size (gadget,
                                     GTK_ORIENTATION_VERTICAL, -1,
                                     height_out, NULL,
                                     NULL, NULL);
}

1229 1230 1231
/**
 * gtk_range_get_range_rect:
 * @range: a #GtkRange
1232
 * @range_rect: (out): return location for the range rectangle
1233
 *
1234
 * This function returns the area that contains the range’s trough
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
 * 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)
{
1245
  GtkRangePrivate *priv;
1246

1247 1248 1249
  g_return_if_fail (GTK_IS_RANGE (range));
  g_return_if_fail (range_rect != NULL);

1250 1251
  priv = range->priv;

1252
  gtk_css_gadget_get_margin_box (priv->contents_gadget, range_rect);
1253 1254 1255 1256 1257
}

/**
 * gtk_range_get_slider_range:
 * @range: a #GtkRange
1258 1259 1260 1261
 * @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
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
 *
 * 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)
{
1275
  GtkRangePrivate *priv;
1276
  GtkAllocation slider_alloc;
1277

1278 1279
  g_return_if_fail (GTK_IS_RANGE (range));

1280 1281
  priv = range->priv;

1282
  gtk_css_gadget_get_border_box (priv->slider_gadget, &slider_alloc);
1283

1284 1285 1286
  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
    {
      if (slider_start)
1287
        *slider_start = slider_alloc.y;
1288
      if (slider_end)
1289
        *slider_end = slider_alloc.y + slider_alloc.height;
1290 1291 1292 1293
    }
  else
    {
      if (slider_start)
1294
        *slider_start = slider_alloc.x;
1295
      if (slider_end)
1296
        *slider_end = slider_alloc.x + slider_alloc.width;
1297
    }
1298 1299
}

1300 1301 1302
/**
 * gtk_range_set_lower_stepper_sensitivity:
 * @range:       a #GtkRange
1303
 * @sensitivity: the lower stepper’s sensitivity policy.
1304 1305
 *
 * Sets the sensitivity policy for the stepper that points to the
1306
 * 'lower' end of the GtkRange’s adjustment.
1307
 *
Matthias Clasen's avatar
Matthias Clasen committed
1308
 * Since: 2.10
1309 1310 1311 1312 1313
 **/
void
gtk_range_set_lower_stepper_sensitivity (GtkRange           *range,
                                         GtkSensitivityType  sensitivity)
{
1314
  GtkRangePrivate *priv;
1315

1316 1317
  g_return_if_fail (GTK_IS_RANGE (range));

1318 1319 1320
  priv = range->priv;

  if (priv->lower_sensitivity != sensitivity)
1321
    {
1322
      priv->lower_sensitivity = sensitivity;
1323

1324
      gtk_range_calc_stepper_sensitivity (range);
1325

1326
      g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_LOWER_STEPPER_SENSITIVITY]);
1327 1328 1329 1330 1331 1332 1333 1334
    }
}

/**
 * gtk_range_get_lower_stepper_sensitivity:
 * @range: a #GtkRange
 *
 * Gets the sensitivity policy for the stepper that points to the
1335
 * 'lower' end of the GtkRange’s adjustment.
1336
 *
1337
 * Returns: The lower stepper’s sensitivity policy.
1338 1339 1340 1341 1342 1343 1344 1345
 *
 * Since: 2.10
 **/
GtkSensitivityType
gtk_range_get_lower_stepper_sensitivity (GtkRange *range)
{
  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_SENSITIVITY_AUTO);

1346
  return range->priv->lower_sensitivity;
1347 1348 1349