]> Pileus Git - ~andy/gtk/blob - gtk/gtkscale.c
Use pango_layout_get_pixel_extents() to remove a large number of '/
[~andy/gtk] / gtk / gtkscale.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <math.h>
28 #include "gtkcontainer.h"
29 #include "gtkscale.h"
30
31 enum {
32   ARG_0,
33   ARG_DIGITS,
34   ARG_DRAW_VALUE,
35   ARG_VALUE_POS
36 };
37
38
39 static void gtk_scale_class_init      (GtkScaleClass *klass);
40 static void gtk_scale_init            (GtkScale      *scale);
41 static void gtk_scale_set_arg         (GtkObject     *object,
42                                        GtkArg        *arg,
43                                        guint          arg_id);
44 static void gtk_scale_get_arg         (GtkObject     *object,
45                                        GtkArg        *arg,
46                                        guint          arg_id);
47 static void gtk_scale_map             (GtkWidget     *widget);
48 static void gtk_scale_unmap           (GtkWidget     *widget);
49
50 static void gtk_scale_draw_background (GtkRange      *range);
51
52
53 static GtkRangeClass *parent_class = NULL;
54
55
56 GtkType
57 gtk_scale_get_type (void)
58 {
59   static GtkType scale_type = 0;
60
61   if (!scale_type)
62     {
63       static const GtkTypeInfo scale_info =
64       {
65         "GtkScale",
66         sizeof (GtkScale),
67         sizeof (GtkScaleClass),
68         (GtkClassInitFunc) gtk_scale_class_init,
69         (GtkObjectInitFunc) gtk_scale_init,
70         /* reserved_1 */ NULL,
71         /* reserved_2 */ NULL,
72         (GtkClassInitFunc) NULL,
73       };
74
75       scale_type = gtk_type_unique (GTK_TYPE_RANGE, &scale_info);
76     }
77
78   return scale_type;
79 }
80
81 static void
82 gtk_scale_class_init (GtkScaleClass *class)
83 {
84   GtkObjectClass *object_class;
85   GtkWidgetClass *widget_class;
86   GtkRangeClass *range_class;
87
88   object_class = (GtkObjectClass*) class;
89   range_class = (GtkRangeClass*) class;
90   widget_class = (GtkWidgetClass*) class;
91   
92   parent_class = gtk_type_class (GTK_TYPE_RANGE);
93   
94   gtk_object_add_arg_type ("GtkScale::digits",
95                            GTK_TYPE_INT,
96                            GTK_ARG_READWRITE,
97                            ARG_DIGITS);
98   gtk_object_add_arg_type ("GtkScale::draw_value",
99                            GTK_TYPE_BOOL,
100                            GTK_ARG_READWRITE,
101                            ARG_DRAW_VALUE);
102   gtk_object_add_arg_type ("GtkScale::value_pos",
103                            GTK_TYPE_POSITION_TYPE,
104                            GTK_ARG_READWRITE,
105                            ARG_VALUE_POS);
106
107   object_class->set_arg = gtk_scale_set_arg;
108   object_class->get_arg = gtk_scale_get_arg;
109
110   widget_class->map = gtk_scale_map;
111   widget_class->unmap = gtk_scale_unmap;
112   
113   range_class->draw_background = gtk_scale_draw_background;
114
115   class->slider_length = 31;
116   class->value_spacing = 2;
117   class->draw_value = NULL;
118 }
119
120 static void
121 gtk_scale_set_arg (GtkObject      *object,
122                    GtkArg         *arg,
123                    guint           arg_id)
124 {
125   GtkScale *scale;
126
127   scale = GTK_SCALE (object);
128
129   switch (arg_id)
130     {
131     case ARG_DIGITS:
132       gtk_scale_set_digits (scale, GTK_VALUE_INT (*arg));
133       break;
134     case ARG_DRAW_VALUE:
135       gtk_scale_set_draw_value (scale, GTK_VALUE_BOOL (*arg));
136       break;
137     case ARG_VALUE_POS:
138       gtk_scale_set_value_pos (scale, GTK_VALUE_ENUM (*arg));
139       break;
140     default:
141       break;
142     }
143 }
144
145 static void
146 gtk_scale_get_arg (GtkObject      *object,
147                    GtkArg         *arg,
148                    guint           arg_id)
149 {
150   GtkScale *scale;
151
152   scale = GTK_SCALE (object);
153
154   switch (arg_id)
155     {
156     case ARG_DIGITS:
157       GTK_VALUE_INT (*arg) = GTK_RANGE (scale)->digits;
158       break;
159     case ARG_DRAW_VALUE:
160       GTK_VALUE_BOOL (*arg) = scale->draw_value;
161       break;
162     case ARG_VALUE_POS:
163       GTK_VALUE_ENUM (*arg) = scale->value_pos;
164       break;
165     default:
166       arg->type = GTK_TYPE_INVALID;
167       break;
168     }
169 }
170
171 static void
172 gtk_scale_init (GtkScale *scale)
173 {
174   GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS);
175   GTK_WIDGET_SET_FLAGS (scale, GTK_NO_WINDOW);
176   GTK_RANGE (scale)->digits = 1;
177   scale->draw_value = TRUE;
178   scale->value_pos = GTK_POS_TOP;
179 }
180
181 static void
182 gtk_scale_map (GtkWidget *widget)
183 {
184   GtkRange *range;
185
186   g_return_if_fail (widget != NULL);
187   g_return_if_fail (GTK_IS_SCALE (widget));
188
189   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
190   range = GTK_RANGE (widget);
191
192   gdk_window_show (range->trough);
193 }
194
195 static void
196 gtk_scale_unmap (GtkWidget *widget)
197 {
198   GtkRange *range;
199
200   g_return_if_fail (widget != NULL);
201   g_return_if_fail (GTK_IS_SCALE (widget));
202
203   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
204   range = GTK_RANGE (widget);
205
206   if (GTK_WIDGET_NO_WINDOW (widget))
207      gtk_widget_queue_clear (widget);
208
209   gdk_window_hide (range->trough);
210 }
211
212 void
213 gtk_scale_set_digits (GtkScale *scale,
214                       gint      digits)
215 {
216   g_return_if_fail (scale != NULL);
217   g_return_if_fail (GTK_IS_SCALE (scale));
218
219   digits = CLAMP (digits, -1, 16);
220
221   if (GTK_RANGE (scale)->digits != digits)
222     {
223       GTK_RANGE (scale)->digits = digits;
224
225       gtk_widget_queue_resize (GTK_WIDGET (scale));
226     }
227 }
228
229 void
230 gtk_scale_set_draw_value (GtkScale *scale,
231                           gboolean  draw_value)
232 {
233   g_return_if_fail (scale != NULL);
234   g_return_if_fail (GTK_IS_SCALE (scale));
235
236   draw_value = draw_value != FALSE;
237
238   if (scale->draw_value != draw_value)
239     {
240       scale->draw_value = draw_value;
241
242       gtk_widget_queue_resize (GTK_WIDGET (scale));
243     }
244 }
245
246 void
247 gtk_scale_set_value_pos (GtkScale        *scale,
248                          GtkPositionType  pos)
249 {
250   g_return_if_fail (scale != NULL);
251   g_return_if_fail (GTK_IS_SCALE (scale));
252
253   if (scale->value_pos != pos)
254     {
255       scale->value_pos = pos;
256
257       if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale))
258         gtk_widget_queue_resize (GTK_WIDGET (scale));
259     }
260 }
261
262 void
263 gtk_scale_get_value_size (GtkScale *scale,
264                           gint     *width,
265                           gint     *height)
266 {
267   GtkRange *range;
268
269   g_return_if_fail (scale != NULL);
270   g_return_if_fail (GTK_IS_SCALE (scale));
271
272   if (scale->draw_value)
273     {
274       PangoLayout *layout;
275       PangoRectangle logical_rect;
276       gchar buffer[128];
277       gfloat value;
278       gint digits;
279       gint i, j;
280       
281       range = GTK_RANGE (scale);
282
283       layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale));
284
285       value = ABS (range->adjustment->lower);
286       if (value == 0) value = 1;
287       digits = log10 (value) + 1;
288       if (digits > 13)
289         digits = 13;
290
291       i = 0;
292       if (range->adjustment->lower < 0)
293         buffer[i++] = '-';
294       for (j = 0; j < digits; j++)
295         buffer[i++] = '0';
296       if (GTK_RANGE (scale)->digits)
297         buffer[i++] = '.';
298       for (j = 0; j < GTK_RANGE (scale)->digits; j++)
299         buffer[i++] = '0';
300       buffer[i] = '\0';
301
302       pango_layout_set_text (layout, buffer, i);
303       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
304
305       if (width)
306         *width = logical_rect.width;
307       if (height)
308         *height = logical_rect.width;
309       
310       value = ABS (range->adjustment->upper);
311       if (value == 0) value = 1;
312       digits = log10 (value) + 1;
313       if (digits > 13)
314         digits = 13;
315
316       i = 0;
317       if (range->adjustment->upper < 0)
318         buffer[i++] = '-';
319       for (j = 0; j < digits; j++)
320         buffer[i++] = '0';
321       if (GTK_RANGE (scale)->digits)
322         buffer[i++] = '.';
323       for (j = 0; j < GTK_RANGE (scale)->digits; j++)
324         buffer[i++] = '0';
325       buffer[i] = '\0';
326
327       pango_layout_set_text (layout, buffer, i);
328       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
329
330       if (width)
331         *width = MAX (*width, logical_rect.width);
332       if (height)
333         *height = MAX (*height, logical_rect.height);
334
335       g_object_unref (G_OBJECT (layout));
336     }
337   else
338     {
339       if (width)
340         *width = 0;
341       if (height)
342         *height = 0;
343     }
344
345 }
346
347 gint
348 gtk_scale_get_value_width (GtkScale *scale)
349 {
350   gint width;
351
352   g_return_val_if_fail (scale != NULL, 0);
353   g_return_val_if_fail (GTK_IS_SCALE (scale), 0);
354   
355   gtk_scale_get_value_size (scale, &width, NULL);
356
357   return width;
358 }
359
360 void
361 gtk_scale_draw_value (GtkScale *scale)
362 {
363   g_return_if_fail (scale != NULL);
364   g_return_if_fail (GTK_IS_SCALE (scale));
365
366   if (GTK_SCALE_GET_CLASS (scale)->draw_value)
367     GTK_SCALE_GET_CLASS (scale)->draw_value (scale);
368 }
369
370
371 static void
372 gtk_scale_draw_background (GtkRange *range)
373 {
374   g_return_if_fail (range != NULL);
375   g_return_if_fail (GTK_IS_SCALE (range));
376
377   gtk_scale_draw_value (GTK_SCALE (range));
378 }