]> Pileus Git - ~andy/gtk/blob - gtk/gtkvscale.c
main part for GtkArgSetFunc/GtkArgGetFunc implementation.
[~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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <stdio.h>
19 #include "gtkvscale.h"
20 #include "gtksignal.h"
21 #include "gdk/gdkkeysyms.h"
22
23
24 #define SCALE_CLASS(w)  GTK_SCALE_CLASS (GTK_OBJECT (w)->klass)
25 #define RANGE_CLASS(w)  GTK_RANGE_CLASS (GTK_OBJECT (w)->klass)
26
27
28 static void gtk_vscale_class_init    (GtkVScaleClass *klass);
29 static void gtk_vscale_init          (GtkVScale      *vscale);
30 static void gtk_vscale_realize       (GtkWidget      *widget);
31 static void gtk_vscale_size_request  (GtkWidget      *widget,
32                                       GtkRequisition *requisition);
33 static void gtk_vscale_size_allocate (GtkWidget      *widget,
34                                       GtkAllocation  *allocation);
35 static void gtk_vscale_pos_trough    (GtkVScale      *vscale,
36                                       gint           *x,
37                                       gint           *y,
38                                       gint           *w,
39                                       gint           *h);
40 static void gtk_vscale_draw_slider   (GtkRange       *range);
41 static void gtk_vscale_draw_value    (GtkScale       *scale);
42 static gint gtk_vscale_trough_keys   (GtkRange *range,
43                                       GdkEventKey *key,
44                                       GtkScrollType *scroll,
45                                       GtkTroughType *pos);
46
47
48 guint
49 gtk_vscale_get_type ()
50 {
51   static guint vscale_type = 0;
52
53   if (!vscale_type)
54     {
55       GtkTypeInfo vscale_info =
56       {
57         "GtkVScale",
58         sizeof (GtkVScale),
59         sizeof (GtkVScaleClass),
60         (GtkClassInitFunc) gtk_vscale_class_init,
61         (GtkObjectInitFunc) gtk_vscale_init,
62         (GtkArgSetFunc) NULL,
63         (GtkArgGetFunc) NULL,
64       };
65
66       vscale_type = gtk_type_unique (gtk_scale_get_type (), &vscale_info);
67     }
68
69   return vscale_type;
70 }
71
72 static void
73 gtk_vscale_class_init (GtkVScaleClass *class)
74 {
75   GtkWidgetClass *widget_class;
76   GtkRangeClass *range_class;
77   GtkScaleClass *scale_class;
78
79   widget_class = (GtkWidgetClass*) class;
80   range_class = (GtkRangeClass*) class;
81   scale_class = (GtkScaleClass*) class;
82
83   widget_class->realize = gtk_vscale_realize;
84   widget_class->size_request = gtk_vscale_size_request;
85   widget_class->size_allocate = gtk_vscale_size_allocate;
86
87   range_class->slider_update = gtk_range_default_vslider_update;
88   range_class->trough_click = gtk_range_default_vtrough_click;
89   range_class->motion = gtk_range_default_vmotion;
90   range_class->draw_slider = gtk_vscale_draw_slider;
91   range_class->trough_keys = gtk_vscale_trough_keys;
92
93   scale_class->draw_value = gtk_vscale_draw_value;
94 }
95
96 static void
97 gtk_vscale_init (GtkVScale *vscale)
98 {
99 }
100
101 GtkWidget*
102 gtk_vscale_new (GtkAdjustment *adjustment)
103 {
104   GtkVScale *vscale;
105
106   vscale = gtk_type_new (gtk_vscale_get_type ());
107
108   if (!adjustment)
109     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
110
111   gtk_range_set_adjustment (GTK_RANGE (vscale), adjustment);
112
113   return GTK_WIDGET (vscale);
114 }
115
116
117 static void
118 gtk_vscale_realize (GtkWidget *widget)
119 {
120   GtkRange *range;
121   GdkWindowAttr attributes;
122   gint attributes_mask;
123   gint x, y, w, h;
124
125   g_return_if_fail (widget != NULL);
126   g_return_if_fail (GTK_IS_VSCALE (widget));
127
128   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
129   range = GTK_RANGE (widget);
130
131   attributes.x = widget->allocation.x;
132   attributes.y = widget->allocation.y;
133   attributes.width = widget->allocation.width;
134   attributes.height = widget->allocation.height;
135   attributes.wclass = GDK_INPUT_OUTPUT;
136   attributes.window_type = GDK_WINDOW_CHILD;
137   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
138   attributes.visual = gtk_widget_get_visual (widget);
139   attributes.colormap = gtk_widget_get_colormap (widget);
140
141   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
142   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
143
144   gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h);
145   attributes.x = x;
146   attributes.y = y;
147   attributes.width = w;
148   attributes.height = h;
149   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
150                             GDK_BUTTON_RELEASE_MASK |
151                             GDK_ENTER_NOTIFY_MASK |
152                             GDK_LEAVE_NOTIFY_MASK);
153
154   range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
155
156   attributes.width = RANGE_CLASS (range)->slider_width;
157   attributes.height = SCALE_CLASS (range)->slider_length;
158   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
159                             GDK_POINTER_MOTION_HINT_MASK);
160
161   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
162
163   widget->style = gtk_style_attach (widget->style, widget->window);
164
165   gdk_window_set_user_data (widget->window, widget);
166   gdk_window_set_user_data (range->trough, widget);
167   gdk_window_set_user_data (range->slider, widget);
168
169   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
170   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
171   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
172
173   gtk_range_slider_update (GTK_RANGE (widget));
174
175   gdk_window_show (range->slider);
176   gdk_window_show (range->trough);
177 }
178
179 static void
180 gtk_vscale_size_request (GtkWidget      *widget,
181                          GtkRequisition *requisition)
182 {
183   GtkScale *scale;
184   gint value_width;
185
186   g_return_if_fail (widget != NULL);
187   g_return_if_fail (GTK_IS_VSCALE (widget));
188   g_return_if_fail (requisition != NULL);
189
190   scale = GTK_SCALE (widget);
191
192   requisition->width = (RANGE_CLASS (scale)->slider_width +
193                         widget->style->klass->ythickness * 2);
194   requisition->height = (SCALE_CLASS (scale)->slider_length +
195                          widget->style->klass->xthickness) * 2;
196
197   if (scale->draw_value)
198     {
199       value_width = gtk_scale_value_width (scale);
200
201       if ((scale->value_pos == GTK_POS_LEFT) ||
202           (scale->value_pos == GTK_POS_RIGHT))
203         {
204           requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
205           if (requisition->height < (widget->style->font->ascent + widget->style->font->descent))
206             requisition->height = widget->style->font->ascent + widget->style->font->descent;
207         }
208       else if ((scale->value_pos == GTK_POS_TOP) ||
209                (scale->value_pos == GTK_POS_BOTTOM))
210         {
211           if (requisition->width < value_width)
212             requisition->width = value_width;
213           requisition->height += widget->style->font->ascent + widget->style->font->descent;
214         }
215     }
216 }
217
218 static void
219 gtk_vscale_size_allocate (GtkWidget     *widget,
220                           GtkAllocation *allocation)
221 {
222   GtkRange *range;
223   GtkScale *scale;
224   gint width, height;
225   gint x, y;
226
227   g_return_if_fail (widget != NULL);
228   g_return_if_fail (GTK_IS_VSCALE (widget));
229   g_return_if_fail (allocation != NULL);
230
231   widget->allocation = *allocation;
232   if (GTK_WIDGET_REALIZED (widget))
233     {
234       range = GTK_RANGE (widget);
235       scale = GTK_SCALE (widget);
236
237       gdk_window_move_resize (widget->window,
238                               allocation->x, allocation->y,
239                               allocation->width, allocation->height);
240
241       gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height);
242
243       gdk_window_move_resize (range->trough, x, y, width, height);
244       gtk_range_slider_update (GTK_RANGE (widget));
245     }
246 }
247
248 static void
249 gtk_vscale_pos_trough (GtkVScale *vscale,
250                        gint      *x,
251                        gint      *y,
252                        gint      *w,
253                        gint      *h)
254 {
255   GtkWidget *widget;
256   GtkScale *scale;
257
258   g_return_if_fail (vscale != NULL);
259   g_return_if_fail (GTK_IS_VSCALE (vscale));
260   g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
261
262   widget = GTK_WIDGET (vscale);
263   scale = GTK_SCALE (vscale);
264
265   *w = (RANGE_CLASS (scale)->slider_width +
266         widget->style->klass->xthickness * 2);
267   *h = widget->allocation.height;
268
269   if (scale->draw_value)
270     {
271       *x = 0;
272       *y = 0;
273
274       switch (scale->value_pos)
275         {
276         case GTK_POS_LEFT:
277           *x = (gtk_scale_value_width (scale) +
278                 (widget->allocation.width - widget->requisition.width) / 2);
279           break;
280         case GTK_POS_RIGHT:
281           *x = (widget->allocation.width - widget->requisition.width) / 2;
282           break;
283         case GTK_POS_TOP:
284           *x = (widget->allocation.width - *w) / 2;
285           *y = widget->style->font->ascent + widget->style->font->descent;
286           *h -= *y;
287           break;
288         case GTK_POS_BOTTOM:
289           *x = (widget->allocation.width - *w) / 2;
290           *h -= widget->style->font->ascent + widget->style->font->descent;
291           break;
292         }
293     }
294   else
295     {
296       *x = (widget->allocation.width - *w) / 2;
297       *y = 0;
298     }
299   *y += 1;
300   *h -= 2;
301 }
302
303 static void
304 gtk_vscale_draw_slider (GtkRange *range)
305 {
306   GtkStateType state_type;
307   gint width, height;
308
309   g_return_if_fail (range != NULL);
310   g_return_if_fail (GTK_IS_VSCALE (range));
311
312   if (range->slider)
313     {
314       if ((range->in_child == RANGE_CLASS (range)->slider) ||
315           (range->click_child == RANGE_CLASS (range)->slider))
316         state_type = GTK_STATE_PRELIGHT;
317       else
318         state_type = GTK_STATE_NORMAL;
319
320       gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type);
321       gdk_window_clear (range->slider);
322
323       gdk_window_get_size (range->slider, &width, &height);
324       gtk_draw_hline (GTK_WIDGET (range)->style, range->slider,
325                       state_type, 1, width - 2, height / 2);
326
327       gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider,
328                        state_type, GTK_SHADOW_OUT,
329                        0, 0, -1, -1);
330     }
331 }
332
333 static void
334 gtk_vscale_draw_value (GtkScale *scale)
335 {
336   GtkStateType state_type;
337   gchar buffer[16];
338   gint text_width;
339   gint width, height;
340   gint x, y;
341
342   g_return_if_fail (scale != NULL);
343   g_return_if_fail (GTK_IS_VSCALE (scale));
344
345   if (scale->draw_value)
346     {
347       gdk_window_get_size (GTK_WIDGET (scale)->window, &width, &height);
348       gdk_window_clear_area (GTK_WIDGET (scale)->window, 1, 1, width - 3, height - 3);
349
350       sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
351       text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer);
352
353       switch (scale->value_pos)
354         {
355         case GTK_POS_LEFT:
356           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
357           gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
358           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
359           gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
360
361           x -= SCALE_CLASS (scale)->value_spacing + text_width;
362           y += ((height -
363                  (GTK_WIDGET (scale)->style->font->ascent +
364                   GTK_WIDGET (scale)->style->font->descent)) / 2 +
365                 GTK_WIDGET (scale)->style->font->ascent);
366           break;
367         case GTK_POS_RIGHT:
368           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
369           gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
370           gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
371           gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
372
373           x += width + SCALE_CLASS (scale)->value_spacing;
374           y += ((height -
375                  (GTK_WIDGET (scale)->style->font->ascent +
376                   GTK_WIDGET (scale)->style->font->descent)) / 2 +
377                 GTK_WIDGET (scale)->style->font->ascent);
378           break;
379         case GTK_POS_TOP:
380           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
381           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
382           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
383
384           x += (width - text_width) / 2;
385           y -= GTK_WIDGET (scale)->style->font->descent;
386           break;
387         case GTK_POS_BOTTOM:
388           gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
389           gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
390           gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
391
392           x += (width - text_width) / 2;
393           y += height + GTK_WIDGET (scale)->style->font->ascent;
394           break;
395         }
396
397       state_type = GTK_STATE_NORMAL;
398       if (!GTK_WIDGET_IS_SENSITIVE (scale))
399         state_type = GTK_STATE_INSENSITIVE;
400
401       gtk_draw_string (GTK_WIDGET (scale)->style,
402                        GTK_WIDGET (scale)->window,
403                        state_type, x, y, buffer);
404     }
405 }
406
407 static gint
408 gtk_vscale_trough_keys(GtkRange *range,
409                        GdkEventKey *key,
410                        GtkScrollType *scroll,
411                        GtkTroughType *pos)
412 {
413   gint return_val = FALSE;
414   switch (key->keyval)
415     {
416     case GDK_Up:
417       return_val = TRUE;
418       *scroll = GTK_SCROLL_STEP_BACKWARD;
419       break;
420     case GDK_Down:
421       return_val = TRUE;
422       *scroll = GTK_SCROLL_STEP_FORWARD;
423       break;
424     case GDK_Page_Up:
425       return_val = TRUE;
426       *scroll = GTK_SCROLL_PAGE_BACKWARD;
427       break;
428     case GDK_Page_Down:
429       return_val = TRUE;
430       *scroll = GTK_SCROLL_PAGE_FORWARD;
431       break;
432     case GDK_Home:
433       return_val = TRUE;
434       *pos = GTK_TROUGH_START;
435       break;
436     case GDK_End:
437       return_val = TRUE;
438       *pos = GTK_TROUGH_END;
439       break;
440     }
441   return return_val;
442 }