gtkscale.c 19.2 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3
 * Copyright (C) 2001 Red Hat, Inc.
Elliot Lee's avatar
Elliot Lee committed
4 5
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20 21

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

28
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
29
#include <math.h>
30
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
31
#include "gtkscale.h"
32
#include "gtkmarshalers.h"
33 34
#include "gdk/gdkkeysyms.h"
#include "gtkbindings.h"
35
#include "gtkprivate.h"
36
#include "gtkalias.h"
Elliot Lee's avatar
Elliot Lee committed
37

38 39 40 41 42 43 44

#define	MAX_DIGITS	(64)	/* don't change this,
				 * a) you don't need to and
				 * b) you might cause buffer owerflows in
				 *    unrelated code portions otherwise
				 */

45 46 47 48 49 50 51 52 53
#define GTK_SCALE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCALE, GtkScalePrivate))

typedef struct _GtkScalePrivate GtkScalePrivate;

struct _GtkScalePrivate
{
  PangoLayout *layout;
};

54
enum {
55 56 57 58
  PROP_0,
  PROP_DIGITS,
  PROP_DRAW_VALUE,
  PROP_VALUE_POS
59 60
};

Havoc Pennington's avatar
Havoc Pennington committed
61 62 63 64 65 66
enum {
  FORMAT_VALUE,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL];
Elliot Lee's avatar
Elliot Lee committed
67

68 69 70 71 72 73 74 75 76 77 78 79
static void gtk_scale_set_property     (GObject       *object,
                                        guint          prop_id,
                                        const GValue  *value,
                                        GParamSpec    *pspec);
static void gtk_scale_get_property     (GObject       *object,
                                        guint          prop_id,
                                        GValue        *value,
                                        GParamSpec    *pspec);
static void gtk_scale_style_set        (GtkWidget     *widget,
                                        GtkStyle      *previous);
static void gtk_scale_get_range_border (GtkRange      *range,
                                        GtkBorder     *border);
80 81 82
static void gtk_scale_finalize         (GObject       *object);
static void gtk_scale_screen_changed   (GtkWidget     *widget,
                                        GdkScreen     *old_screen);
Elliot Lee's avatar
Elliot Lee committed
83

Matthias Clasen's avatar
Matthias Clasen committed
84
G_DEFINE_ABSTRACT_TYPE (GtkScale, gtk_scale, GTK_TYPE_RANGE)
Elliot Lee's avatar
Elliot Lee committed
85

86
static gboolean
Havoc Pennington's avatar
Havoc Pennington committed
87 88 89 90 91 92
single_string_accumulator (GSignalInvocationHint *ihint,
                           GValue                *return_accu,
                           const GValue          *handler_return,
                           gpointer               dummy)
{
  gboolean continue_emission;
93
  const gchar *str;
Havoc Pennington's avatar
Havoc Pennington committed
94 95 96 97 98 99 100 101
  
  str = g_value_get_string (handler_return);
  g_value_set_string (return_accu, str);
  continue_emission = str == NULL;
  
  return continue_emission;
}

102

103 104 105
#define add_slider_binding(binding_set, keyval, mask, scroll)              \
  gtk_binding_entry_add_signal (binding_set, keyval, mask,                 \
                                I_("move_slider"), 1, \
106 107
                                GTK_TYPE_SCROLL_TYPE, scroll)

Elliot Lee's avatar
Elliot Lee committed
108 109 110
static void
gtk_scale_class_init (GtkScaleClass *class)
{
111
  GObjectClass   *gobject_class;
112
  GtkWidgetClass *widget_class;
Manish Singh's avatar
Manish Singh committed
113 114
  GtkRangeClass  *range_class;
  GtkBindingSet  *binding_set;
115
  
116
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
117
  range_class = (GtkRangeClass*) class;
118
  widget_class = (GtkWidgetClass*) class;
119
  
120 121
  gobject_class->set_property = gtk_scale_set_property;
  gobject_class->get_property = gtk_scale_get_property;
122
  gobject_class->finalize = gtk_scale_finalize;
123

124
  widget_class->style_set = gtk_scale_style_set;
125
  widget_class->screen_changed = gtk_scale_screen_changed;
126

127 128
  range_class->get_range_border = gtk_scale_get_range_border;
  
129
  signals[FORMAT_VALUE] =
130
    g_signal_new (I_("format_value"),
Manish Singh's avatar
Manish Singh committed
131
                  G_TYPE_FROM_CLASS (gobject_class),
132 133 134
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkScaleClass, format_value),
                  single_string_accumulator, NULL,
135
                  _gtk_marshal_STRING__DOUBLE,
136 137
                  G_TYPE_STRING, 1,
                  G_TYPE_DOUBLE);
138

139 140 141
  g_object_class_install_property (gobject_class,
                                   PROP_DIGITS,
                                   g_param_spec_int ("digits",
142 143
						     P_("Digits"),
						     P_("The number of decimal places that are displayed in the value"),
144 145 146
						     -1,
						     MAX_DIGITS,
						     1,
147
						     GTK_PARAM_READWRITE));
148 149 150
  
  g_object_class_install_property (gobject_class,
                                   PROP_DRAW_VALUE,
151
                                   g_param_spec_boolean ("draw-value",
152 153
							 P_("Draw Value"),
							 P_("Whether the current value is displayed as a string next to the slider"),
154
							 TRUE,
155
							 GTK_PARAM_READWRITE));
156 157 158
  
  g_object_class_install_property (gobject_class,
                                   PROP_VALUE_POS,
159
                                   g_param_spec_enum ("value-pos",
160 161
						      P_("Value Position"),
						      P_("The position in which the current value is displayed"),
162
						      GTK_TYPE_POSITION_TYPE,
163
						      GTK_POS_TOP,
164
						      GTK_PARAM_READWRITE));
165

166
  gtk_widget_class_install_style_property (widget_class,
167
					   g_param_spec_int ("slider-length",
168 169
							     P_("Slider Length"),
							     P_("Length of scale's slider"),
170 171 172
							     0,
							     G_MAXINT,
							     31,
173
							     GTK_PARAM_READABLE));
174 175

  gtk_widget_class_install_style_property (widget_class,
176
					   g_param_spec_int ("value-spacing",
177 178
							     P_("Value spacing"),
							     P_("Space between value text and the slider/trough area"),
179 180 181
							     0,
							     G_MAXINT,
							     2,
182
							     GTK_PARAM_READABLE));
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
  
  /* All bindings (even arrow keys) are on both h/v scale, because
   * blind users etc. don't care about scale orientation.
   */
  
  binding_set = gtk_binding_set_by_class (class);

  add_slider_binding (binding_set, GDK_Left, 0,
                      GTK_SCROLL_STEP_LEFT);

  add_slider_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_LEFT);

  add_slider_binding (binding_set, GDK_KP_Left, 0,
                      GTK_SCROLL_STEP_LEFT);

  add_slider_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_LEFT);

  add_slider_binding (binding_set, GDK_Right, 0,
                      GTK_SCROLL_STEP_RIGHT);

  add_slider_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_RIGHT);

  add_slider_binding (binding_set, GDK_KP_Right, 0,
                      GTK_SCROLL_STEP_RIGHT);

  add_slider_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_RIGHT);

  add_slider_binding (binding_set, GDK_Up, 0,
                      GTK_SCROLL_STEP_UP);

  add_slider_binding (binding_set, GDK_Up, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_UP);

  add_slider_binding (binding_set, GDK_KP_Up, 0,
                      GTK_SCROLL_STEP_UP);

  add_slider_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_UP);

  add_slider_binding (binding_set, GDK_Down, 0,
                      GTK_SCROLL_STEP_DOWN);

  add_slider_binding (binding_set, GDK_Down, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_DOWN);

  add_slider_binding (binding_set, GDK_KP_Down, 0,
                      GTK_SCROLL_STEP_DOWN);

  add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_DOWN);
   
238
  add_slider_binding (binding_set, GDK_Page_Up, GDK_CONTROL_MASK,
239
                      GTK_SCROLL_PAGE_LEFT);
240

241
  add_slider_binding (binding_set, GDK_KP_Page_Up, GDK_CONTROL_MASK,
242 243 244 245
                      GTK_SCROLL_PAGE_LEFT);  

  add_slider_binding (binding_set, GDK_Page_Up, 0,
                      GTK_SCROLL_PAGE_UP);
246

247 248 249
  add_slider_binding (binding_set, GDK_KP_Page_Up, 0,
                      GTK_SCROLL_PAGE_UP);
  
250
  add_slider_binding (binding_set, GDK_Page_Down, GDK_CONTROL_MASK,
251
                      GTK_SCROLL_PAGE_RIGHT);
252

253
  add_slider_binding (binding_set, GDK_KP_Page_Down, GDK_CONTROL_MASK,
254 255 256 257
                      GTK_SCROLL_PAGE_RIGHT);

  add_slider_binding (binding_set, GDK_Page_Down, 0,
                      GTK_SCROLL_PAGE_DOWN);
258

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  add_slider_binding (binding_set, GDK_KP_Page_Down, 0,
                      GTK_SCROLL_PAGE_DOWN);

  /* Logical bindings (vs. visual bindings above) */

  add_slider_binding (binding_set, GDK_plus, 0,
                      GTK_SCROLL_STEP_FORWARD);  

  add_slider_binding (binding_set, GDK_minus, 0,
                      GTK_SCROLL_STEP_BACKWARD);  

  add_slider_binding (binding_set, GDK_plus, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_FORWARD);  

  add_slider_binding (binding_set, GDK_minus, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_BACKWARD);


  add_slider_binding (binding_set, GDK_KP_Add, 0,
                      GTK_SCROLL_STEP_FORWARD);  

  add_slider_binding (binding_set, GDK_KP_Subtract, 0,
                      GTK_SCROLL_STEP_BACKWARD);  

  add_slider_binding (binding_set, GDK_KP_Add, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_FORWARD);  

  add_slider_binding (binding_set, GDK_KP_Subtract, GDK_CONTROL_MASK,
                      GTK_SCROLL_PAGE_BACKWARD);
  
  
290 291 292 293 294 295 296 297 298 299 300
  add_slider_binding (binding_set, GDK_Home, 0,
                      GTK_SCROLL_START);

  add_slider_binding (binding_set, GDK_KP_Home, 0,
                      GTK_SCROLL_START);

  add_slider_binding (binding_set, GDK_End, 0,
                      GTK_SCROLL_END);

  add_slider_binding (binding_set, GDK_KP_End, 0,
                      GTK_SCROLL_END);
301 302

  g_type_class_add_private (gobject_class, sizeof (GtkScalePrivate));
Elliot Lee's avatar
Elliot Lee committed
303 304
}

305
static void
306 307 308 309
gtk_scale_set_property (GObject      *object,
			guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
310 311 312 313 314
{
  GtkScale *scale;

  scale = GTK_SCALE (object);

315
  switch (prop_id)
316
    {
317 318
    case PROP_DIGITS:
      gtk_scale_set_digits (scale, g_value_get_int (value));
319
      break;
320 321
    case PROP_DRAW_VALUE:
      gtk_scale_set_draw_value (scale, g_value_get_boolean (value));
322
      break;
323 324
    case PROP_VALUE_POS:
      gtk_scale_set_value_pos (scale, g_value_get_enum (value));
325 326
      break;
    default:
327
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328 329 330 331 332
      break;
    }
}

static void
333 334 335 336
gtk_scale_get_property (GObject      *object,
			guint         prop_id,
			GValue       *value,
			GParamSpec   *pspec)
337 338 339 340 341
{
  GtkScale *scale;

  scale = GTK_SCALE (object);

342
  switch (prop_id)
343
    {
344
    case PROP_DIGITS:
345
      g_value_set_int (value, scale->digits);
346
      break;
347 348
    case PROP_DRAW_VALUE:
      g_value_set_boolean (value, scale->draw_value);
349
      break;
350 351
    case PROP_VALUE_POS:
      g_value_set_enum (value, scale->value_pos);
352 353
      break;
    default:
354
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355 356 357 358
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
359 360
static void
gtk_scale_init (GtkScale *scale)
361 362 363
{
  GtkRange *range;

364 365 366
  range = GTK_RANGE (scale);
  
  GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS);
367

368 369 370 371 372
  range->slider_size_fixed = TRUE;
  range->has_stepper_a = FALSE;
  range->has_stepper_b = FALSE;
  range->has_stepper_c = FALSE;
  range->has_stepper_d = FALSE;
373
  
374 375
  scale->draw_value = TRUE;
  scale->value_pos = GTK_POS_TOP;
376 377
  scale->digits = 1;
  range->round_digits = scale->digits;
378 379
}

Elliot Lee's avatar
Elliot Lee committed
380 381 382 383
void
gtk_scale_set_digits (GtkScale *scale,
		      gint      digits)
{
384 385
  GtkRange *range;
  
Elliot Lee's avatar
Elliot Lee committed
386 387
  g_return_if_fail (GTK_IS_SCALE (scale));

388 389
  range = GTK_RANGE (scale);
  
390
  digits = CLAMP (digits, -1, MAX_DIGITS);
391

392
  if (scale->digits != digits)
Elliot Lee's avatar
Elliot Lee committed
393
    {
394 395 396
      scale->digits = digits;
      if (scale->draw_value)
	range->round_digits = digits;
397
      
398
      _gtk_scale_clear_layout (scale);
399
      gtk_widget_queue_resize (GTK_WIDGET (scale));
400 401

      g_object_notify (G_OBJECT (scale), "digits");
Elliot Lee's avatar
Elliot Lee committed
402 403 404
    }
}

405 406 407 408 409
gint
gtk_scale_get_digits (GtkScale *scale)
{
  g_return_val_if_fail (GTK_IS_SCALE (scale), -1);

410
  return scale->digits;
411 412
}

Elliot Lee's avatar
Elliot Lee committed
413 414
void
gtk_scale_set_draw_value (GtkScale *scale,
415
			  gboolean  draw_value)
Elliot Lee's avatar
Elliot Lee committed
416 417 418
{
  g_return_if_fail (GTK_IS_SCALE (scale));

419 420
  draw_value = draw_value != FALSE;

Elliot Lee's avatar
Elliot Lee committed
421 422
  if (scale->draw_value != draw_value)
    {
423
      scale->draw_value = draw_value;
424 425 426 427
      if (draw_value)
	GTK_RANGE (scale)->round_digits = scale->digits;
      else
	GTK_RANGE (scale)->round_digits = -1;
Elliot Lee's avatar
Elliot Lee committed
428

429 430
      _gtk_scale_clear_layout (scale);

431
      gtk_widget_queue_resize (GTK_WIDGET (scale));
432

433
      g_object_notify (G_OBJECT (scale), "draw-value");
Elliot Lee's avatar
Elliot Lee committed
434 435 436
    }
}

437 438 439 440 441 442 443 444
gboolean
gtk_scale_get_draw_value (GtkScale *scale)
{
  g_return_val_if_fail (GTK_IS_SCALE (scale), FALSE);

  return scale->draw_value;
}

Elliot Lee's avatar
Elliot Lee committed
445 446 447 448 449 450 451 452 453 454
void
gtk_scale_set_value_pos (GtkScale        *scale,
			 GtkPositionType  pos)
{
  g_return_if_fail (GTK_IS_SCALE (scale));

  if (scale->value_pos != pos)
    {
      scale->value_pos = pos;

455
      _gtk_scale_clear_layout (scale);
Elliot Lee's avatar
Elliot Lee committed
456 457
      if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale))
	gtk_widget_queue_resize (GTK_WIDGET (scale));
458

459
      g_object_notify (G_OBJECT (scale), "value-pos");
Elliot Lee's avatar
Elliot Lee committed
460 461 462
    }
}

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
GtkPositionType
gtk_scale_get_value_pos (GtkScale *scale)
{
  g_return_val_if_fail (GTK_IS_SCALE (scale), 0);

  return scale->value_pos;
}

static void
gtk_scale_get_range_border (GtkRange  *range,
                            GtkBorder *border)
{
  GtkWidget *widget;
  GtkScale *scale;
  gint w, h;
  
  widget = GTK_WIDGET (range);
  scale = GTK_SCALE (range);

  _gtk_scale_get_value_size (scale, &w, &h);

  border->left = 0;
  border->right = 0;
  border->top = 0;
  border->bottom = 0;

  if (scale->draw_value)
    {
      gint value_spacing;
492
      gtk_widget_style_get (widget, "value-spacing", &value_spacing, NULL);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

      switch (scale->value_pos)
        {
        case GTK_POS_LEFT:
          border->left += w + value_spacing;
          break;
        case GTK_POS_RIGHT:
          border->right += w + value_spacing;
          break;
        case GTK_POS_TOP:
          border->top += h + value_spacing;
          break;
        case GTK_POS_BOTTOM:
          border->bottom += h + value_spacing;
          break;
        }
    }
}

/* FIXME this could actually be static at the moment. */
513
void
514 515 516
_gtk_scale_get_value_size (GtkScale *scale,
                           gint     *width,
                           gint     *height)
Elliot Lee's avatar
Elliot Lee committed
517 518 519
{
  GtkRange *range;

520
  g_return_if_fail (GTK_IS_SCALE (scale));
Elliot Lee's avatar
Elliot Lee committed
521 522 523

  if (scale->draw_value)
    {
524 525
      PangoLayout *layout;
      PangoRectangle logical_rect;
Havoc Pennington's avatar
Havoc Pennington committed
526
      gchar *txt;
527
      
Elliot Lee's avatar
Elliot Lee committed
528 529
      range = GTK_RANGE (scale);

530
      layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
531

Havoc Pennington's avatar
Havoc Pennington committed
532 533 534 535
      txt = _gtk_scale_format_value (scale, range->adjustment->lower);
      pango_layout_set_text (layout, txt, -1);
      g_free (txt);
      
536
      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
Elliot Lee's avatar
Elliot Lee committed
537

538
      if (width)
539
	*width = logical_rect.width;
540
      if (height)
Havoc Pennington's avatar
Havoc Pennington committed
541 542 543 544 545
	*height = logical_rect.height;

      txt = _gtk_scale_format_value (scale, range->adjustment->upper);
      pango_layout_set_text (layout, txt, -1);
      g_free (txt);
546
      
547
      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
548 549

      if (width)
550
	*width = MAX (*width, logical_rect.width);
551
      if (height)
552
	*height = MAX (*height, logical_rect.height);
553

Manish Singh's avatar
Manish Singh committed
554
      g_object_unref (layout);
Elliot Lee's avatar
Elliot Lee committed
555
    }
556 557 558 559 560 561 562 563 564 565
  else
    {
      if (width)
	*width = 0;
      if (height)
	*height = 0;
    }

}

566 567 568
static void
gtk_scale_style_set (GtkWidget *widget,
                     GtkStyle  *previous)
569
{
570 571
  gint slider_length;
  GtkRange *range;
572

573
  range = GTK_RANGE (widget);
574
  
575
  gtk_widget_style_get (widget,
576
                        "slider-length", &slider_length,
577 578 579 580
                        NULL);
  
  range->min_slider_size = slider_length;
  
581 582
  _gtk_scale_clear_layout (GTK_SCALE (widget));

Matthias Clasen's avatar
Matthias Clasen committed
583
  (* GTK_WIDGET_CLASS (gtk_scale_parent_class)->style_set) (widget, previous);
Elliot Lee's avatar
Elliot Lee committed
584 585
}

586 587 588 589 590 591
static void
gtk_scale_screen_changed (GtkWidget *widget,
                          GdkScreen *old_screen)
{
  _gtk_scale_clear_layout (GTK_SCALE (widget));
}
Elliot Lee's avatar
Elliot Lee committed
592

Havoc Pennington's avatar
Havoc Pennington committed
593 594 595 596 597
/**
 * _gtk_scale_format_value:
 * @scale: a #GtkScale
 * @value: adjustment value
 * 
Matthias Clasen's avatar
Matthias Clasen committed
598 599
 * Emits #GtkScale::format-value signal to format the value, 
 * if no user signal handlers, falls back to a default format.
Havoc Pennington's avatar
Havoc Pennington committed
600 601 602 603 604 605 606 607 608
 * 
 * Return value: formatted value
 **/
gchar*
_gtk_scale_format_value (GtkScale *scale,
                         gdouble   value)
{
  gchar *fmt = NULL;

Manish Singh's avatar
Manish Singh committed
609
  g_signal_emit (scale,
Havoc Pennington's avatar
Havoc Pennington committed
610 611 612 613 614 615 616 617
                 signals[FORMAT_VALUE],
                 0,
                 value,
                 &fmt);

  if (fmt)
    return fmt;
  else
618 619
    /* insert a LRM, to prevent -20 to come out as 20- in RTL locales */
    return g_strdup_printf ("\342\200\216%0.*f", scale->digits, value);
Havoc Pennington's avatar
Havoc Pennington committed
620
}
621 622 623 624

static void
gtk_scale_finalize (GObject *object)
{
625
  GtkScale *scale = GTK_SCALE (object);
626 627 628

  _gtk_scale_clear_layout (scale);

Matthias Clasen's avatar
Matthias Clasen committed
629
  G_OBJECT_CLASS (gtk_scale_parent_class)->finalize (object);
630 631 632 633 634 635
}

/**
 * gtk_scale_get_layout:
 * @scale: A #GtkScale
 *
Matthias Clasen's avatar
Matthias Clasen committed
636 637 638
 * Gets the #PangoLayout used to display the scale. 
 * The returned object is owned by the scale so does 
 * not need to be freed by the caller. 
639
 *
Matthias Clasen's avatar
Matthias Clasen committed
640 641
 * Return value: the #PangoLayout for this scale, or %NULL 
 *    if the #GtkScale:draw-value property is %FALSE.
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
 *   
 * Since: 2.4
 **/
PangoLayout *
gtk_scale_get_layout (GtkScale *scale)
{
  GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
  gchar *txt;

  g_return_val_if_fail (GTK_IS_SCALE (scale), NULL);

  if (!priv->layout)
    {
      if (scale->draw_value)
	priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
    }

  if (scale->draw_value) 
    {
      txt = _gtk_scale_format_value (scale,
				     GTK_RANGE (scale)->adjustment->value);
      pango_layout_set_text (priv->layout, txt, -1);
      g_free (txt);
    }

  return priv->layout;
}

/**
 * gtk_scale_get_layout_offsets:
 * @scale: a #GtkScale
 * @x: location to store X offset of layout, or %NULL
 * @y: location to store Y offset of layout, or %NULL
 *
Matthias Clasen's avatar
Matthias Clasen committed
676 677
 * Obtains the coordinates where the scale will draw the 
 * #PangoLayout representing the text in the scale. Remember
678 679 680
 * when using the #PangoLayout function you need to convert to
 * and from pixels using PANGO_PIXELS() or #PANGO_SCALE. 
 *
Matthias Clasen's avatar
Matthias Clasen committed
681 682
 * If the #GtkScale:draw-value property is %FALSE, the return 
 * values are undefined.
683 684 685 686 687 688 689 690
 *
 * Since: 2.4
 **/
void 
gtk_scale_get_layout_offsets (GtkScale *scale,
                              gint     *x,
                              gint     *y)
{
691 692
  gint local_x = 0; 
  gint local_y = 0;
693

694
  g_return_if_fail (GTK_IS_SCALE (scale));
695 696 697 698 699 700 701 702 703 704 705

  if (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets)
    (GTK_SCALE_GET_CLASS (scale)->get_layout_offsets) (scale, &local_x, &local_y);

  if (x)
    *x = local_x;
  
  if (y)
    *y = local_y;
}

706 707
void
_gtk_scale_clear_layout (GtkScale *scale)
708 709 710 711 712 713 714 715 716 717 718 719
{
  GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);

  g_return_if_fail (GTK_IS_SCALE (scale));

  if (priv->layout)
    {
      g_object_unref (priv->layout);
      priv->layout = NULL;
    }
}

720 721
#define __GTK_SCALE_C__
#include "gtkaliasdef.c"