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