]> Pileus Git - ~andy/gtk/blob - gtk/gtkhscale.c
Remove explicit pointer grabs, since they are no longer necessary.
[~andy/gtk] / gtk / gtkhscale.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 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 <stdio.h>
28 #include "gtkhscale.h"
29 #include "gtksignal.h"
30 #include "gdk/gdkkeysyms.h"
31 #include "gtkintl.h"
32
33 #define SCALE_CLASS(w)  GTK_SCALE_GET_CLASS (w)
34 #define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
35
36 enum {
37   PROP_0,
38   PROP_ADJUSTMENT
39 };
40
41 static void     gtk_hscale_class_init       (GtkHScaleClass *klass);
42 static void     gtk_hscale_init             (GtkHScale      *hscale);
43 static void     gtk_hscale_get_property     (GObject        *object,
44                                              guint           prop_id,
45                                              GValue          *value,
46                                              GParamSpec      *pspec);
47 static void     gtk_hscale_set_property     (GObject         *object,
48                                              guint            prop_id,
49                                              const GValue    *value,
50                                              GParamSpec      *pspec);
51 static void     gtk_hscale_realize          (GtkWidget      *widget);
52 static void     gtk_hscale_size_request     (GtkWidget      *widget,
53                                              GtkRequisition *requisition);
54 static void     gtk_hscale_size_allocate    (GtkWidget      *widget,
55                                              GtkAllocation  *allocation);
56 static void     gtk_hscale_pos_trough       (GtkHScale      *hscale,
57                                              gint           *x,
58                                              gint           *y,
59                                              gint           *w,
60                                              gint           *h);
61 static void     gtk_hscale_pos_background   (GtkHScale      *hscale,
62                                              gint           *x,
63                                              gint           *y,
64                                              gint           *w,
65                                              gint           *h);
66 static void     gtk_hscale_draw_slider      (GtkRange       *range);
67 static void     gtk_hscale_draw_value       (GtkScale       *scale);
68 static gboolean gtk_hscale_trough_keys      (GtkRange       *range,
69                                              GdkEventKey    *key,
70                                              GtkScrollType  *scroll,
71                                              GtkTroughType  *pos);
72 static void     gtk_hscale_clear_background (GtkRange       *range);
73
74
75 GtkType
76 gtk_hscale_get_type (void)
77 {
78   static GtkType hscale_type = 0;
79   
80   if (!hscale_type)
81     {
82       static const GtkTypeInfo hscale_info =
83       {
84         "GtkHScale",
85         sizeof (GtkHScale),
86         sizeof (GtkHScaleClass),
87         (GtkClassInitFunc) gtk_hscale_class_init,
88         (GtkObjectInitFunc) gtk_hscale_init,
89         /* reserved_1 */ NULL,
90         /* reserved_2 */ NULL,
91         (GtkClassInitFunc) NULL,
92       };
93       
94       hscale_type = gtk_type_unique (GTK_TYPE_SCALE, &hscale_info);
95     }
96   
97   return hscale_type;
98 }
99
100 static void
101 gtk_hscale_class_init (GtkHScaleClass *class)
102 {
103   GObjectClass *gobject_class;
104   GtkObjectClass *object_class;
105   GtkWidgetClass *widget_class;
106   GtkRangeClass *range_class;
107   GtkScaleClass *scale_class;
108
109   gobject_class = (GObjectClass*) class;
110   object_class = (GtkObjectClass*) class;
111   widget_class = (GtkWidgetClass*) class;
112   range_class = (GtkRangeClass*) class;
113   scale_class = (GtkScaleClass*) class;
114
115   gobject_class->set_property = gtk_hscale_set_property;
116   gobject_class->get_property = gtk_hscale_get_property;   
117  
118   widget_class->realize = gtk_hscale_realize;
119   widget_class->size_request = gtk_hscale_size_request;
120   widget_class->size_allocate = gtk_hscale_size_allocate;
121   
122   range_class->slider_update = _gtk_range_default_hslider_update;
123   range_class->trough_click = _gtk_range_default_htrough_click;
124   range_class->motion = _gtk_range_default_hmotion;
125   range_class->draw_slider = gtk_hscale_draw_slider;
126   range_class->trough_keys = gtk_hscale_trough_keys;
127   range_class->clear_background = gtk_hscale_clear_background;
128   
129   scale_class->draw_value = gtk_hscale_draw_value;
130
131   g_object_class_install_property (gobject_class,
132                                    PROP_ADJUSTMENT,
133                                    g_param_spec_object ("adjustment",
134                                                         _("Adjustment"),
135                                                         _("The GtkAdjustment that determines the values to use for this HScale."),
136                                                         GTK_TYPE_ADJUSTMENT,
137                                                         G_PARAM_READWRITE));
138
139 }
140
141 static void 
142 gtk_hscale_set_property (GObject        *object,
143                          guint           prop_id,
144                          const GValue   *value,
145                          GParamSpec     *pspec)
146 {
147   GtkHScale *hscale;
148   
149   hscale = GTK_HSCALE (object);
150   
151   switch (prop_id)
152     {
153     case PROP_ADJUSTMENT:
154       gtk_range_set_adjustment (GTK_RANGE (hscale), g_value_get_object (value));
155       break;
156     default:
157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158       break;
159     }
160 }
161
162 static void 
163 gtk_hscale_get_property (GObject                    *object,
164                          guint                       prop_id,
165                          GValue                     *value,
166                          GParamSpec                 *pspec)
167 {
168   GtkHScale *hscale;
169   
170   hscale = GTK_HSCALE (object);
171   
172   switch (prop_id)
173     {
174     case PROP_ADJUSTMENT:
175       g_value_set_object (value,
176                           G_OBJECT (gtk_range_get_adjustment (GTK_RANGE (hscale))));
177       break;
178     default:
179       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180       break;
181     }
182 }
183
184 static void
185 gtk_hscale_init (GtkHScale *hscale)
186 {
187   GTK_WIDGET_SET_FLAGS (hscale, GTK_NO_WINDOW);
188 }
189
190 GtkWidget*
191 gtk_hscale_new (GtkAdjustment *adjustment)
192 {
193   GtkWidget *hscale;
194   
195   hscale = gtk_widget_new (GTK_TYPE_HSCALE,
196                            "adjustment", adjustment,
197                            NULL);
198
199   GTK_RANGE (hscale) -> flippable = 1;
200
201   return hscale;
202 }
203
204
205 static void
206 gtk_hscale_realize (GtkWidget *widget)
207 {
208   GtkRange *range;
209   GdkWindowAttr attributes;
210   gint attributes_mask;
211   gint x, y, w, h;
212   gint slider_width, slider_length;
213   
214   g_return_if_fail (widget != NULL);
215   g_return_if_fail (GTK_IS_HSCALE (widget));
216   
217   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
218   range = GTK_RANGE (widget);
219
220   _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL);
221   gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
222   
223   widget->window = gtk_widget_get_parent_window (widget);
224   gdk_window_ref (widget->window);
225   
226   gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h);
227
228   attributes.x = x;
229   attributes.y = y;
230   attributes.width = w;
231   attributes.height = h;
232   attributes.wclass = GDK_INPUT_OUTPUT;
233   attributes.window_type = GDK_WINDOW_CHILD;
234   
235   attributes.event_mask = gtk_widget_get_events (widget) | 
236     (GDK_EXPOSURE_MASK |
237      GDK_BUTTON_PRESS_MASK |
238      GDK_BUTTON_RELEASE_MASK |
239      GDK_ENTER_NOTIFY_MASK |
240      GDK_LEAVE_NOTIFY_MASK);
241   attributes.visual = gtk_widget_get_visual (widget);
242   attributes.colormap = gtk_widget_get_colormap (widget);
243   
244   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
245   
246   range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
247   
248   attributes.width = slider_length;
249   attributes.height = slider_width;
250   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
251                             GDK_POINTER_MOTION_HINT_MASK);
252   
253   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
254   
255   widget->style = gtk_style_attach (widget->style, widget->window);
256   
257   gdk_window_set_user_data (range->trough, widget);
258   gdk_window_set_user_data (range->slider, widget);
259   
260   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
261   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
262   
263   _gtk_range_slider_update (GTK_RANGE (widget));
264   
265   gdk_window_show (range->slider);
266 }
267
268 static void 
269 gtk_hscale_clear_background (GtkRange    *range)
270 {
271   GtkWidget *widget;
272   gint x, y, width, height;
273   
274   g_return_if_fail (range != NULL);
275   
276   widget = GTK_WIDGET (range);
277   
278   gtk_hscale_pos_background (GTK_HSCALE (range), &x, &y, &width, &height);
279   
280   gtk_widget_queue_clear_area (GTK_WIDGET (range),
281                                x, y, width, height);
282 }
283
284 static void
285 gtk_hscale_size_request (GtkWidget      *widget,
286                          GtkRequisition *requisition)
287 {
288   GtkScale *scale = GTK_SCALE (widget);
289   gint slider_width, slider_length, trough_border;
290   
291   g_return_if_fail (widget != NULL);
292   g_return_if_fail (GTK_IS_HSCALE (widget));
293   g_return_if_fail (requisition != NULL);
294   
295   _gtk_range_get_props (GTK_RANGE (scale),
296                         &slider_width, &trough_border, NULL, NULL);
297   gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
298
299   requisition->width = (slider_length + trough_border) * 2;
300   requisition->height = (slider_width + trough_border * 2);
301   
302   if (scale->draw_value)
303     {
304       gint value_width, value_height;
305       gtk_scale_get_value_size (scale, &value_width, &value_height);
306       
307       if ((scale->value_pos == GTK_POS_LEFT) ||
308           (scale->value_pos == GTK_POS_RIGHT))
309         {
310           requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
311           if (requisition->height < value_height)
312             requisition->height = value_height;
313         }
314       else if ((scale->value_pos == GTK_POS_TOP) ||
315                (scale->value_pos == GTK_POS_BOTTOM))
316         {
317           if (requisition->width < value_width)
318             requisition->width = value_width;
319           requisition->height += value_height;
320         }
321     }
322 }
323
324 static void
325 gtk_hscale_size_allocate (GtkWidget     *widget,
326                           GtkAllocation *allocation)
327 {
328   GtkRange *range;
329   GtkScale *scale;
330   gint width, height;
331   gint x, y;
332   
333   g_return_if_fail (widget != NULL);
334   g_return_if_fail (GTK_IS_HSCALE (widget));
335   g_return_if_fail (allocation != NULL);
336   
337   widget->allocation = *allocation;
338   if (GTK_WIDGET_REALIZED (widget))
339     {
340       range = GTK_RANGE (widget);
341       scale = GTK_SCALE (widget);
342       
343       gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height);
344       
345       gdk_window_move_resize (range->trough, 
346                               x, y, width, height);
347       _gtk_range_slider_update (GTK_RANGE (widget));
348     }
349 }
350
351 static void
352 gtk_hscale_pos_trough (GtkHScale *hscale,
353                        gint      *x,
354                        gint      *y,
355                        gint      *w,
356                        gint      *h)
357 {
358   GtkWidget *widget = GTK_WIDGET (hscale);
359   GtkScale *scale = GTK_SCALE (hscale);
360   gint slider_width;
361   gint trough_border;
362   
363   _gtk_range_get_props (GTK_RANGE (scale),
364                         &slider_width, &trough_border, NULL, NULL);
365   
366   *w = widget->allocation.width;
367   *h = (slider_width + trough_border * 2);
368   
369   if (scale->draw_value)
370     {
371       gint value_width, value_height;
372       gtk_scale_get_value_size (scale, &value_width, &value_height);
373       
374       *x = 0;
375       *y = 0;
376       
377       switch (scale->value_pos)
378         {
379         case GTK_POS_LEFT:
380           *x += value_width + SCALE_CLASS (scale)->value_spacing;
381           *y = (widget->allocation.height - *h) / 2;
382           *w -= *x;
383           break;
384         case GTK_POS_RIGHT:
385           *w -= value_width + SCALE_CLASS (scale)->value_spacing;
386           *y = (widget->allocation.height - *h) / 2;
387           break;
388         case GTK_POS_TOP:
389           *y = (value_height + (widget->allocation.height - widget->requisition.height) / 2);
390           break;
391         case GTK_POS_BOTTOM:
392           *y = (widget->allocation.height - widget->requisition.height) / 2;
393           break;
394         }
395     }
396   else
397     {
398       *x = 0;
399       *y = (widget->allocation.height - *h) / 2;
400     }
401   *x += 1;
402   *w -= 2;
403   
404   *x += widget->allocation.x;
405   *y += widget->allocation.y;
406 }
407
408 static void
409 gtk_hscale_pos_background (GtkHScale *hscale,
410                            gint      *x,
411                            gint      *y,
412                            gint      *w,
413                            gint      *h)
414 {
415   GtkWidget *widget;
416   GtkScale *scale;
417   
418   gint tx, ty, twidth, theight;
419   
420   g_return_if_fail (hscale != NULL);
421   g_return_if_fail (GTK_IS_HSCALE (hscale));
422   g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
423   
424   gtk_hscale_pos_trough (hscale, &tx, &ty, &twidth, &theight);
425   
426   widget = GTK_WIDGET (hscale);
427   scale = GTK_SCALE (hscale);
428   
429   *x = widget->allocation.x;
430   *y = widget->allocation.y;
431   *w = widget->allocation.width;
432   *h = widget->allocation.height;
433   
434   switch (scale->value_pos)
435     {
436     case GTK_POS_LEFT:
437       *w -= twidth;
438       break;
439     case GTK_POS_RIGHT:
440       *x += twidth;
441       *w -= twidth;
442       break;
443     case GTK_POS_TOP:
444       *h -= theight;
445       break;
446     case GTK_POS_BOTTOM:
447       *y += theight;
448       *h -= theight;
449       break;
450     }
451   *w = MAX (*w, 0);
452   *h = MAX (*h, 0);
453 }
454
455 static void
456 gtk_hscale_draw_slider (GtkRange *range)
457 {
458   GtkStateType state_type;
459   
460   g_return_if_fail (range != NULL);
461   g_return_if_fail (GTK_IS_HSCALE (range));
462   
463   if (range->slider)
464     {
465       if ((range->in_child == RANGE_CLASS (range)->slider) ||
466           (range->click_child == RANGE_CLASS (range)->slider))
467         state_type = GTK_STATE_PRELIGHT;
468       else
469         state_type = GTK_STATE_NORMAL;
470       
471       gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, 
472                         GTK_SHADOW_OUT,
473                         NULL, GTK_WIDGET (range), "hscale",
474                         0, 0, -1, -1, 
475                         GTK_ORIENTATION_HORIZONTAL); 
476     }
477 }
478
479 static void
480 gtk_hscale_draw_value (GtkScale *scale)
481 {
482   GtkStateType state_type;
483   GtkWidget *widget;
484   gchar buffer[32];
485   gint width, height;
486   gint x, y;
487   
488   g_return_if_fail (scale != NULL);
489   g_return_if_fail (GTK_IS_HSCALE (scale));
490   
491   widget = GTK_WIDGET (scale);
492   
493   if (scale->draw_value)
494     {
495       PangoLayout *layout;
496       PangoRectangle logical_rect;
497       
498       sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
499       layout = gtk_widget_create_pango_layout (widget, buffer);
500       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
501
502       switch (scale->value_pos)
503         {
504         case GTK_POS_LEFT:
505           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
506           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
507           
508           x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width;
509           y += (height - logical_rect.height) / 2;
510           break;
511         case GTK_POS_RIGHT:
512           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
513           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
514           
515           x += width + SCALE_CLASS (scale)->value_spacing;
516           y += (height - logical_rect.height) / 2;
517           break;
518         case GTK_POS_TOP:
519           gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
520           gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
521           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
522           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
523           
524           x += widget->allocation.x + (width - logical_rect.width) / 2;
525           x = CLAMP (x, widget->allocation.x,
526                      widget->allocation.x + widget->allocation.width - logical_rect.width);
527           y -= logical_rect.height;
528           break;
529         case GTK_POS_BOTTOM:
530           gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
531           gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
532           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
533           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
534           
535           x += widget->allocation.x + (width - logical_rect.width) / 2;
536           x = CLAMP (x, widget->allocation.x,
537                      widget->allocation.x + widget->allocation.width - logical_rect.width);
538           y += height;
539           break;
540         }
541       
542       state_type = GTK_STATE_NORMAL;
543       if (!GTK_WIDGET_IS_SENSITIVE (scale))
544         state_type = GTK_STATE_INSENSITIVE;
545
546       gtk_paint_layout (widget->style,
547                         widget->window,
548                         state_type,
549                         NULL,
550                         widget,
551                         "hscale",
552                         x, y,
553                         layout);
554
555       g_object_unref (G_OBJECT (layout));
556     }
557 }
558
559 static gboolean
560 gtk_hscale_trough_keys (GtkRange *range,
561                         GdkEventKey *key,
562                         GtkScrollType *scroll,
563                         GtkTroughType *pos)
564 {
565   gint return_val = FALSE;
566   switch (key->keyval)
567     {
568     case GDK_Left:
569       return_val = TRUE;
570       if (key->state & GDK_CONTROL_MASK)
571         *scroll = GTK_SCROLL_PAGE_LEFT;
572       else
573         *scroll = GTK_SCROLL_STEP_LEFT;
574       break;
575     case GDK_Right:
576       return_val = TRUE;
577       if (key->state & GDK_CONTROL_MASK)
578         *scroll = GTK_SCROLL_PAGE_RIGHT;
579       else
580         *scroll = GTK_SCROLL_STEP_RIGHT;
581       break;
582     case GDK_Home:
583       return_val = TRUE;
584       *pos = GTK_TROUGH_START;
585       break;
586     case GDK_End:
587       return_val = TRUE;
588       *pos = GTK_TROUGH_END;
589       break;
590     }
591   return return_val;
592 }