]> Pileus Git - ~andy/gtk/blob - gtk/gtkvscale.c
ri Jun 14 10:00:29 2002 Owen Taylor <otaylor@redhat.com>
[~andy/gtk] / gtk / gtkvscale.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2001 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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-2000.  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 <stdio.h>
29 #include <stdlib.h>
30 #include "gtkvscale.h"
31 #include "gtksignal.h"
32 #include "gtkintl.h"
33
34 #define VALUE_SPACING 2
35
36 static gpointer parent_class;
37
38 static void     gtk_vscale_class_init       (GtkVScaleClass *klass);
39 static void     gtk_vscale_init             (GtkVScale      *vscale);
40 static gboolean gtk_vscale_expose           (GtkWidget      *widget,
41                                              GdkEventExpose *event);
42
43 GtkType
44 gtk_vscale_get_type (void)
45 {
46   static GtkType vscale_type = 0;
47   
48   if (!vscale_type)
49     {
50       static const GtkTypeInfo vscale_info =
51       {
52         "GtkVScale",
53         sizeof (GtkVScale),
54         sizeof (GtkVScaleClass),
55         (GtkClassInitFunc) gtk_vscale_class_init,
56         (GtkObjectInitFunc) gtk_vscale_init,
57         /* reserved_1 */ NULL,
58         /* reserved_2 */ NULL,
59         (GtkClassInitFunc) NULL,
60       };
61       
62       vscale_type = gtk_type_unique (GTK_TYPE_SCALE, &vscale_info);
63     }
64   
65   return vscale_type;
66 }
67
68 static void
69 gtk_vscale_class_init (GtkVScaleClass *class)
70 {
71   GObjectClass   *gobject_class;
72   GtkWidgetClass *widget_class;
73   GtkRangeClass *range_class;
74   
75   gobject_class = G_OBJECT_CLASS (class);
76   widget_class = GTK_WIDGET_CLASS (class);
77   range_class = GTK_RANGE_CLASS (class); 
78
79   parent_class = g_type_class_peek_parent (class);
80
81   range_class->slider_detail = "vscale";
82   
83   widget_class->expose_event = gtk_vscale_expose;
84 }
85
86 static void
87 gtk_vscale_init (GtkVScale *vscale)
88 {
89   GtkRange *range;
90
91   range = GTK_RANGE (vscale);
92   
93   range->orientation = GTK_ORIENTATION_VERTICAL;
94 }
95
96 GtkWidget*
97 gtk_vscale_new (GtkAdjustment *adjustment)
98 {
99   GtkWidget *vscale;
100   
101   vscale = gtk_widget_new (GTK_TYPE_VSCALE,
102                            "adjustment", adjustment,
103                            NULL);
104   
105   return vscale;
106 }
107
108
109 /**
110  * gtk_vscale_new_with_range:
111  * @min: minimum value
112  * @max: maximum value
113  * @step: step increment (tick size) used with keyboard shortcuts
114  * 
115  * Creates a new vertical scale widget that lets the user input a
116  * number between @min and @max (including @min and @max) with the
117  * increment @step.  @step must be nonzero; it's the distance the
118  * slider moves when using the arrow keys to adjust the scale value.
119  * 
120  * Return value: a new #GtkVScale
121  **/
122 GtkWidget*
123 gtk_vscale_new_with_range (gdouble min,
124                            gdouble max,
125                            gdouble step)
126 {
127   GtkObject *adj;
128   GtkScale *scale;
129   gint digits;
130
131   g_return_val_if_fail (min < max, NULL);
132   g_return_val_if_fail (step != 0.0, NULL);
133
134   adj = gtk_adjustment_new (min, min, max, step, 10 * step, 0);
135   
136   scale = g_object_new (GTK_TYPE_VSCALE,
137                         "adjustment", adj,
138                         NULL);
139
140   if (fabs (step) >= 1.0 || step == 0.0)
141     digits = 0;
142   else {
143     digits = abs ((gint) floor (log10 (fabs (step))));
144     if (digits > 5)
145       digits = 5;
146   }
147
148   gtk_scale_set_digits (scale, digits);
149   
150   return GTK_WIDGET (scale);
151 }
152
153 static gboolean
154 gtk_vscale_expose (GtkWidget      *widget,
155                    GdkEventExpose *event)
156 {
157   GtkRange *range;
158   GtkVScale *vscale;
159   GtkScale *scale;
160   
161   range = GTK_RANGE (widget);
162   scale = GTK_SCALE (widget);
163   vscale = GTK_VSCALE (widget);
164   
165   /* We need to chain up _first_ so the various geometry members of
166    * GtkRange struct are updated.
167    */
168   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
169     GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
170
171   if (scale->draw_value)
172     {
173       PangoLayout *layout;
174       PangoRectangle logical_rect;
175       gchar *txt;
176       gint x, y;
177       GtkStateType state_type;
178       gint value_spacing;
179
180       gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
181       
182       txt = _gtk_scale_format_value (scale,
183                                      GTK_RANGE (scale)->adjustment->value);
184       
185       layout = gtk_widget_create_pango_layout (widget, txt);
186       g_free (txt);
187       
188       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
189       
190       switch (scale->value_pos)
191         {
192         case GTK_POS_LEFT:
193           x = range->range_rect.x - logical_rect.width - value_spacing;
194           y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
195           y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
196           break;
197           
198         case GTK_POS_RIGHT:
199           x = range->range_rect.x + range->range_rect.width + value_spacing;
200           y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
201           y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
202           break;
203           
204         case GTK_POS_TOP:
205           x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
206           y = range->range_rect.y - logical_rect.height - value_spacing;
207           break;
208           
209         case GTK_POS_BOTTOM:
210           x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
211           y = range->range_rect.y + range->range_rect.height + value_spacing;
212           break;
213
214         default:
215           g_return_val_if_reached (FALSE);
216           x = 0;
217           y = 0;
218           break;
219         }
220       
221       x += widget->allocation.x;
222       y += widget->allocation.y;
223       
224       state_type = GTK_STATE_NORMAL;
225       if (!GTK_WIDGET_IS_SENSITIVE (scale))
226         state_type = GTK_STATE_INSENSITIVE;
227
228       gtk_paint_layout (widget->style,
229                         widget->window,
230                         state_type,
231                         FALSE,
232                         NULL,
233                         widget,
234                         "vscale",
235                         x, y,
236                         layout);
237
238       g_object_unref (G_OBJECT (layout));
239     }
240   
241   return FALSE;
242 }