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