]> Pileus Git - ~andy/gtk/blob - gtk/gtkvscale.c
Added notice to look in AUTHORS and ChangeLog files for a list of changes.
[~andy/gtk] / gtk / gtkvscale.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 <stdio.h>
28 #include "gtkvscale.h"
29 #include "gtksignal.h"
30 #include "gdk/gdkkeysyms.h"
31
32
33 #define SCALE_CLASS(w)  GTK_SCALE_CLASS (GTK_OBJECT (w)->klass)
34 #define RANGE_CLASS(w)  GTK_RANGE_CLASS (GTK_OBJECT (w)->klass)
35
36 enum {
37   ARG_0,
38   ARG_ADJUSTMENT
39 };
40
41 static void gtk_vscale_class_init    (GtkVScaleClass *klass);
42 static void gtk_vscale_init          (GtkVScale      *vscale);
43 static void gtk_vscale_set_arg       (GtkObject      *object,
44                                       GtkArg         *arg,
45                                       guint           arg_id);
46 static void gtk_vscale_get_arg       (GtkObject      *object,
47                                       GtkArg         *arg,
48                                       guint           arg_id);
49 static void gtk_vscale_realize       (GtkWidget      *widget);
50 static void gtk_vscale_size_request  (GtkWidget      *widget,
51                                       GtkRequisition *requisition);
52 static void gtk_vscale_size_allocate (GtkWidget      *widget,
53                                       GtkAllocation  *allocation);
54 static void gtk_vscale_pos_trough    (GtkVScale      *vscale,
55                                       gint           *x,
56                                       gint           *y,
57                                       gint           *w,
58                                       gint           *h);
59 static void gtk_vscale_pos_background (GtkVScale     *vscale,
60                                        gint          *x,
61                                        gint          *y,
62                                        gint          *w,
63                                        gint          *h);
64 static void gtk_vscale_draw_slider   (GtkRange       *range);
65 static void gtk_vscale_draw_value    (GtkScale       *scale);
66 static void gtk_vscale_draw          (GtkWidget      *widget,
67                                       GdkRectangle   *area);
68 static gint gtk_vscale_trough_keys   (GtkRange *range,
69                                       GdkEventKey *key,
70                                       GtkScrollType *scroll,
71                                       GtkTroughType *pos);
72 static void gtk_vscale_clear_background (GtkRange    *range);
73
74 GtkType
75 gtk_vscale_get_type (void)
76 {
77   static GtkType vscale_type = 0;
78   
79   if (!vscale_type)
80     {
81       static const GtkTypeInfo vscale_info =
82       {
83         "GtkVScale",
84         sizeof (GtkVScale),
85         sizeof (GtkVScaleClass),
86         (GtkClassInitFunc) gtk_vscale_class_init,
87         (GtkObjectInitFunc) gtk_vscale_init,
88         /* reserved_1 */ NULL,
89         /* reserved_2 */ NULL,
90         (GtkClassInitFunc) NULL,
91       };
92       
93       vscale_type = gtk_type_unique (GTK_TYPE_SCALE, &vscale_info);
94     }
95   
96   return vscale_type;
97 }
98
99 static void
100 gtk_vscale_class_init (GtkVScaleClass *class)
101 {
102   GtkObjectClass *object_class;
103   GtkWidgetClass *widget_class;
104   GtkRangeClass *range_class;
105   GtkScaleClass *scale_class;
106   
107   object_class = (GtkObjectClass*) class;
108   widget_class = (GtkWidgetClass*) class;
109   range_class = (GtkRangeClass*) class;
110   scale_class = (GtkScaleClass*) class;
111   
112   gtk_object_add_arg_type ("GtkVScale::adjustment",
113                            GTK_TYPE_ADJUSTMENT,
114                            GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
115                            ARG_ADJUSTMENT);
116   
117   object_class->set_arg = gtk_vscale_set_arg;
118   object_class->get_arg = gtk_vscale_get_arg;
119   
120   widget_class->realize = gtk_vscale_realize;
121   widget_class->size_request = gtk_vscale_size_request;
122   widget_class->size_allocate = gtk_vscale_size_allocate;
123   widget_class->draw = gtk_vscale_draw;
124   
125   range_class->slider_update = gtk_range_default_vslider_update;
126   range_class->trough_click = gtk_range_default_vtrough_click;
127   range_class->motion = gtk_range_default_vmotion;
128   range_class->draw_slider = gtk_vscale_draw_slider;
129   range_class->trough_keys = gtk_vscale_trough_keys;
130   range_class->clear_background = gtk_vscale_clear_background;
131   
132   scale_class->draw_value = gtk_vscale_draw_value;
133 }
134
135 static void
136 gtk_vscale_set_arg (GtkObject          *object,
137                     GtkArg             *arg,
138                     guint               arg_id)
139 {
140   GtkVScale *vscale;
141   
142   vscale = GTK_VSCALE (object);
143   
144   switch (arg_id)
145     {
146     case ARG_ADJUSTMENT:
147       gtk_range_set_adjustment (GTK_RANGE (vscale), GTK_VALUE_POINTER (*arg));
148       break;
149     default:
150       break;
151     }
152 }
153
154 static void
155 gtk_vscale_get_arg (GtkObject          *object,
156                     GtkArg             *arg,
157                     guint               arg_id)
158 {
159   GtkVScale *vscale;
160   
161   vscale = GTK_VSCALE (object);
162   
163   switch (arg_id)
164     {
165     case ARG_ADJUSTMENT:
166       GTK_VALUE_POINTER (*arg) = GTK_RANGE (vscale);
167       break;
168     default:
169       arg->type = GTK_TYPE_INVALID;
170       break;
171     }
172 }
173
174 static void
175 gtk_vscale_init (GtkVScale *vscale)
176 {
177   GTK_WIDGET_SET_FLAGS (vscale, GTK_NO_WINDOW);
178 }
179
180 GtkWidget*
181 gtk_vscale_new (GtkAdjustment *adjustment)
182 {
183   GtkWidget *vscale;
184   
185   vscale = gtk_widget_new (GTK_TYPE_VSCALE,
186                            "adjustment", adjustment,
187                            NULL);
188   
189   return vscale;
190 }
191
192
193 static void
194 gtk_vscale_realize (GtkWidget *widget)
195 {
196   GtkRange *range;
197   GdkWindowAttr attributes;
198   gint attributes_mask;
199   gint x, y, w, h;
200   
201   g_return_if_fail (widget != NULL);
202   g_return_if_fail (GTK_IS_VSCALE (widget));
203   
204   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
205   range = GTK_RANGE (widget);
206   
207   widget->window = gtk_widget_get_parent_window (widget);
208   gdk_window_ref (widget->window);
209   
210   gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h);
211   
212   attributes.x = x;
213   attributes.y = y;
214   attributes.width = w;
215   attributes.height = h;
216   attributes.wclass = GDK_INPUT_OUTPUT;
217   attributes.window_type = GDK_WINDOW_CHILD;
218          
219   attributes.event_mask = gtk_widget_get_events (widget) | 
220     (GDK_EXPOSURE_MASK |
221      GDK_BUTTON_PRESS_MASK |
222      GDK_BUTTON_RELEASE_MASK |
223      GDK_ENTER_NOTIFY_MASK |
224      GDK_LEAVE_NOTIFY_MASK);
225   attributes.visual = gtk_widget_get_visual (widget);
226   attributes.colormap = gtk_widget_get_colormap (widget);
227   
228   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
229   
230   range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
231   
232   attributes.width = RANGE_CLASS (range)->slider_width;
233   attributes.height = SCALE_CLASS (range)->slider_length;
234   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
235                             GDK_POINTER_MOTION_HINT_MASK);
236   
237   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
238   
239   widget->style = gtk_style_attach (widget->style, widget->window);
240   
241   gdk_window_set_user_data (range->trough, widget);
242   gdk_window_set_user_data (range->slider, widget);
243   
244   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
245   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
246   
247   gtk_range_slider_update (GTK_RANGE (widget));
248   
249   gdk_window_show (range->slider);
250 }
251
252 static void
253 gtk_vscale_draw (GtkWidget    *widget,
254                  GdkRectangle *area)
255 {
256   GtkRange *range;
257   GdkRectangle tmp_area;
258   GdkRectangle child_area;
259   gint x, y, width, height;
260   
261   g_return_if_fail (widget != NULL);
262   g_return_if_fail (GTK_IS_RANGE (widget));
263   g_return_if_fail (area != NULL);
264   
265   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
266     {
267       range = GTK_RANGE (widget);
268       
269       gtk_vscale_pos_background (GTK_VSCALE (widget), &x, &y, &width, &height);
270       
271       tmp_area.x = x;
272       tmp_area.y = y;
273       tmp_area.width = width;
274       tmp_area.height = height;
275       
276       if (gdk_rectangle_intersect (area, &tmp_area, &child_area))
277         gtk_range_draw_background (range);
278       
279       gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height);
280       
281       tmp_area.x = x;
282       tmp_area.y = y;
283       tmp_area.width = width;
284       tmp_area.height = height;
285       
286       if (gdk_rectangle_intersect (area, &tmp_area, &child_area))
287         {
288           gtk_range_draw_trough (range);
289           gtk_range_draw_slider (range);
290           gtk_range_draw_step_forw (range);
291           gtk_range_draw_step_back (range);
292         }
293     }
294 }
295
296 static void
297 gtk_vscale_clear_background (GtkRange    *range)
298 {
299   GtkWidget *widget;
300   GtkScale *scale;
301   gint x, y, width, height;
302   
303   g_return_if_fail (range != NULL);
304   g_return_if_fail (GTK_IS_SCALE (range));
305   
306   widget = GTK_WIDGET (range);
307   scale = GTK_SCALE (range);
308   
309   gtk_vscale_pos_background (GTK_VSCALE (widget), &x, &y, &width, &height);
310   
311   gtk_widget_queue_clear_area (GTK_WIDGET (range),
312                                x, y, width, height);
313 }
314
315 static void
316 gtk_vscale_size_request (GtkWidget      *widget,
317                          GtkRequisition *requisition)
318 {
319   GtkScale *scale;
320   gint value_width;
321   
322   g_return_if_fail (widget != NULL);
323   g_return_if_fail (GTK_IS_VSCALE (widget));
324   g_return_if_fail (requisition != NULL);
325   
326   scale = GTK_SCALE (widget);
327   
328   requisition->width = (RANGE_CLASS (scale)->slider_width +
329                         widget->style->klass->ythickness * 2);
330   requisition->height = (SCALE_CLASS (scale)->slider_length +
331                          widget->style->klass->xthickness) * 2;
332   
333   if (scale->draw_value)
334     {
335       value_width = gtk_scale_get_value_width (scale);
336       
337       if ((scale->value_pos == GTK_POS_LEFT) ||
338           (scale->value_pos == GTK_POS_RIGHT))
339         {
340           requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
341           if (requisition->height < (widget->style->font->ascent + widget->style->font->descent))
342             requisition->height = widget->style->font->ascent + widget->style->font->descent;
343         }
344       else if ((scale->value_pos == GTK_POS_TOP) ||
345                (scale->value_pos == GTK_POS_BOTTOM))
346         {
347           if (requisition->width < value_width)
348             requisition->width = value_width;
349           requisition->height += widget->style->font->ascent + widget->style->font->descent;
350         }
351     }
352 }
353
354 static void
355 gtk_vscale_size_allocate (GtkWidget     *widget,
356                           GtkAllocation *allocation)
357 {
358   GtkRange *range;
359   GtkScale *scale;
360   gint width, height;
361   gint x, y;
362   
363   g_return_if_fail (widget != NULL);
364   g_return_if_fail (GTK_IS_VSCALE (widget));
365   g_return_if_fail (allocation != NULL);
366   
367   widget->allocation = *allocation;
368   if (GTK_WIDGET_REALIZED (widget))
369     {
370       range = GTK_RANGE (widget);
371       scale = GTK_SCALE (widget);
372       
373       gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height);
374       
375       gdk_window_move_resize (range->trough, x, y, width, height);
376       gtk_range_slider_update (GTK_RANGE (widget));
377     }
378 }
379
380 static void
381 gtk_vscale_pos_trough (GtkVScale *vscale,
382                        gint      *x,
383                        gint      *y,
384                        gint      *w,
385                        gint      *h)
386 {
387   GtkWidget *widget;
388   GtkScale *scale;
389   
390   g_return_if_fail (vscale != NULL);
391   g_return_if_fail (GTK_IS_VSCALE (vscale));
392   g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
393   
394   widget = GTK_WIDGET (vscale);
395   scale = GTK_SCALE (vscale);
396   
397   *w = (RANGE_CLASS (scale)->slider_width +
398         widget->style->klass->xthickness * 2);
399   *h = widget->allocation.height;
400   
401   if (scale->draw_value)
402     {
403       *x = 0;
404       *y = 0;
405       
406       switch (scale->value_pos)
407         {
408         case GTK_POS_LEFT:
409           *x = (gtk_scale_get_value_width (scale) + SCALE_CLASS (scale)->value_spacing +
410                 (widget->allocation.width - widget->requisition.width) / 2);
411           break;
412         case GTK_POS_RIGHT:
413           *x = (widget->allocation.width - widget->requisition.width) / 2;
414           break;
415         case GTK_POS_TOP:
416           *x = (widget->allocation.width - *w) / 2;
417           *y = widget->style->font->ascent + widget->style->font->descent;
418           *h -= *y;
419           break;
420         case GTK_POS_BOTTOM:
421           *x = (widget->allocation.width - *w) / 2;
422           *h -= widget->style->font->ascent + widget->style->font->descent;
423           break;
424         }
425     }
426   else
427     {
428       *x = (widget->allocation.width - *w) / 2;
429       *y = 0;
430     }
431   *y += 1;
432   *h -= 2;
433   
434   *x += widget->allocation.x;
435   *y += widget->allocation.y;
436 }
437
438 static void
439 gtk_vscale_pos_background (GtkVScale *vscale,
440                            gint      *x,
441                            gint      *y,
442                            gint      *w,
443                            gint      *h)
444 {
445   GtkWidget *widget;
446   GtkScale *scale;
447   
448   gint tx, ty, twidth, theight;
449   
450   g_return_if_fail (vscale != NULL);
451   g_return_if_fail (GTK_IS_VSCALE (vscale));
452   g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
453   
454   gtk_vscale_pos_trough (vscale, &tx, &ty, &twidth, &theight);
455   
456   widget = GTK_WIDGET (vscale);
457   scale = GTK_SCALE (vscale);
458   
459   *x = widget->allocation.x;
460   *y = widget->allocation.y;
461   *w = widget->allocation.width;
462   *h = widget->allocation.height;
463   
464   switch (scale->value_pos)
465     {
466     case GTK_POS_LEFT:
467       *w -= twidth;
468       break;
469     case GTK_POS_RIGHT:
470       *x += twidth;
471       *w -= twidth;
472       break;
473     case GTK_POS_TOP:
474       *h -= theight;
475       break;
476     case GTK_POS_BOTTOM:
477       *y += theight;
478       *h -= theight;
479       break;
480     }
481 }
482
483 static void
484 gtk_vscale_draw_slider (GtkRange *range)
485 {
486   GtkStateType state_type;
487   
488   g_return_if_fail (range != NULL);
489   g_return_if_fail (GTK_IS_VSCALE (range));
490   
491   if (range->slider)
492     {
493       if ((range->in_child == RANGE_CLASS (range)->slider) ||
494           (range->click_child == RANGE_CLASS (range)->slider))
495         state_type = GTK_STATE_PRELIGHT;
496       else
497         state_type = GTK_STATE_NORMAL;
498       
499       gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, 
500                         GTK_SHADOW_OUT, 
501                         NULL, GTK_WIDGET (range), "vscale",
502                         0, 0, -1, -1, 
503                         GTK_ORIENTATION_VERTICAL); 
504     }
505 }
506
507 static void
508 gtk_vscale_draw_value (GtkScale *scale)
509 {
510   GtkStateType state_type;
511   GtkWidget *widget;
512   gchar buffer[32];
513   gint text_width;
514   gint width, height;
515   gint x, y;
516   
517   g_return_if_fail (scale != NULL);
518   g_return_if_fail (GTK_IS_VSCALE (scale));
519   
520   widget = GTK_WIDGET (scale);
521   
522   if (scale->draw_value)
523     {
524       sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
525       text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer);
526       
527       switch (scale->value_pos)
528         {
529         case GTK_POS_LEFT:
530           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
531           gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
532           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
533           gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
534           
535           x -= SCALE_CLASS (scale)->value_spacing + text_width;
536           y += widget->allocation.y + ((height -
537                                         (GTK_WIDGET (scale)->style->font->ascent +
538                                          GTK_WIDGET (scale)->style->font->descent)) / 2 +
539                                        GTK_WIDGET (scale)->style->font->ascent);
540           break;
541         case GTK_POS_RIGHT:
542           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
543           gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
544           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
545           gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
546           
547           x += width + SCALE_CLASS (scale)->value_spacing;
548           y += widget->allocation.y + ((height -
549                                         (GTK_WIDGET (scale)->style->font->ascent +
550                                          GTK_WIDGET (scale)->style->font->descent)) / 2 +
551                                        GTK_WIDGET (scale)->style->font->ascent);
552           break;
553         case GTK_POS_TOP:
554           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
555           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
556           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
557           
558           x += (width - text_width) / 2;
559           y -= GTK_WIDGET (scale)->style->font->descent;
560           break;
561         case GTK_POS_BOTTOM:
562           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
563           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
564           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
565           
566           x += (width - text_width) / 2;
567           y += height + GTK_WIDGET (scale)->style->font->ascent;
568           break;
569         }
570       
571       state_type = GTK_STATE_NORMAL;
572       if (!GTK_WIDGET_IS_SENSITIVE (scale))
573         state_type = GTK_STATE_INSENSITIVE;
574       
575       gtk_paint_string (GTK_WIDGET (scale)->style,
576                         GTK_WIDGET (scale)->window,
577                         state_type, 
578                         NULL, GTK_WIDGET (scale), "vscale",
579                         x, y, buffer);
580     }
581 }
582
583 static gint
584 gtk_vscale_trough_keys (GtkRange *range,
585                         GdkEventKey *key,
586                         GtkScrollType *scroll,
587                         GtkTroughType *pos)
588 {
589   gint return_val = FALSE;
590   switch (key->keyval)
591     {
592     case GDK_Up:
593       return_val = TRUE;
594       *scroll = GTK_SCROLL_STEP_BACKWARD;
595       break;
596     case GDK_Down:
597       return_val = TRUE;
598       *scroll = GTK_SCROLL_STEP_FORWARD;
599       break;
600     case GDK_Page_Up:
601       return_val = TRUE;
602       *scroll = GTK_SCROLL_PAGE_BACKWARD;
603       break;
604     case GDK_Page_Down:
605       return_val = TRUE;
606       *scroll = GTK_SCROLL_PAGE_FORWARD;
607       break;
608     case GDK_Home:
609       return_val = TRUE;
610       *pos = GTK_TROUGH_START;
611       break;
612     case GDK_End:
613       return_val = TRUE;
614       *pos = GTK_TROUGH_END;
615       break;
616     }
617   return return_val;
618 }