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