]> Pileus Git - ~andy/gtk/blob - gtk/gtkrange.c
Initial revision
[~andy/gtk] / gtk / gtkrange.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 "gtkmain.h"
20 #include "gtkrange.h"
21 #include "gtksignal.h"
22
23
24 #define SCROLL_TIMER_LENGTH  20
25 #define SCROLL_INITIAL_DELAY 100
26 #define SCROLL_DELAY_LENGTH  300
27
28 #define RANGE_CLASS(w)  GTK_RANGE_CLASS (GTK_OBJECT (w)->klass)
29
30
31 static void gtk_range_class_init               (GtkRangeClass    *klass);
32 static void gtk_range_init                     (GtkRange         *range);
33 static void gtk_range_destroy                  (GtkObject        *object);
34 static void gtk_range_draw                     (GtkWidget        *widget,
35                                                 GdkRectangle     *area);
36 static void gtk_range_draw_focus               (GtkWidget        *widget);
37 static void gtk_range_unrealize                (GtkWidget        *widget);
38 static gint gtk_range_expose                   (GtkWidget        *widget,
39                                                 GdkEventExpose   *event);
40 static gint gtk_range_button_press             (GtkWidget        *widget,
41                                                 GdkEventButton   *event);
42 static gint gtk_range_button_release           (GtkWidget        *widget,
43                                                 GdkEventButton   *event);
44 static gint gtk_range_motion_notify            (GtkWidget        *widget,
45                                                 GdkEventMotion   *event);
46 static gint gtk_range_key_press                (GtkWidget         *widget,
47                                                 GdkEventKey       *event);
48 static gint gtk_range_enter_notify             (GtkWidget        *widget,
49                                                 GdkEventCrossing *event);
50 static gint gtk_range_leave_notify             (GtkWidget        *widget,
51                                                 GdkEventCrossing *event);
52 static gint gtk_range_focus_in                 (GtkWidget        *widget,
53                                                 GdkEventFocus    *event);
54 static gint gtk_range_focus_out                (GtkWidget        *widget,
55                                                 GdkEventFocus    *event);
56 static void gtk_real_range_draw_trough         (GtkRange         *range);
57 static void gtk_real_range_draw_slider         (GtkRange         *range);
58 static gint gtk_real_range_timer               (GtkRange         *range);
59 static gint gtk_range_scroll                   (GtkRange         *range);
60
61 static void gtk_range_add_timer                (GtkRange         *range);
62 static void gtk_range_remove_timer             (GtkRange         *range);
63
64 static void gtk_range_adjustment_changed       (GtkAdjustment    *adjustment,
65                                                 gpointer          data);
66 static void gtk_range_adjustment_value_changed (GtkAdjustment    *adjustment,
67                                                 gpointer          data);
68
69 static void gtk_range_trough_hdims             (GtkRange         *range,
70                                                 gint             *left,
71                                                 gint             *right);
72 static void gtk_range_trough_vdims             (GtkRange         *range,
73                                                 gint             *top,
74                                                 gint             *bottom);
75
76 static GtkWidgetClass *parent_class = NULL;
77
78
79 guint
80 gtk_range_get_type ()
81 {
82   static guint range_type = 0;
83
84   if (!range_type)
85     {
86       GtkTypeInfo range_info =
87       {
88         "GtkRange",
89         sizeof (GtkRange),
90         sizeof (GtkRangeClass),
91         (GtkClassInitFunc) gtk_range_class_init,
92         (GtkObjectInitFunc) gtk_range_init,
93         (GtkArgFunc) NULL,
94       };
95
96       range_type = gtk_type_unique (gtk_widget_get_type (), &range_info);
97     }
98
99   return range_type;
100 }
101
102 static void
103 gtk_range_class_init (GtkRangeClass *class)
104 {
105   GtkObjectClass *object_class;
106   GtkWidgetClass *widget_class;
107
108   object_class = (GtkObjectClass*) class;
109   widget_class = (GtkWidgetClass*) class;
110
111   parent_class = gtk_type_class (gtk_widget_get_type ());
112
113   object_class->destroy = gtk_range_destroy;
114
115   widget_class->draw = gtk_range_draw;
116   widget_class->draw_focus = gtk_range_draw_focus;
117   widget_class->unrealize = gtk_range_unrealize;
118   widget_class->expose_event = gtk_range_expose;
119   widget_class->button_press_event = gtk_range_button_press;
120   widget_class->button_release_event = gtk_range_button_release;
121   widget_class->motion_notify_event = gtk_range_motion_notify;
122   widget_class->key_press_event = gtk_range_key_press;
123   widget_class->enter_notify_event = gtk_range_enter_notify;
124   widget_class->leave_notify_event = gtk_range_leave_notify;
125   widget_class->focus_in_event = gtk_range_focus_in;
126   widget_class->focus_out_event = gtk_range_focus_out;
127
128   class->slider_width = 11;
129   class->stepper_size = 11;
130   class->stepper_slider_spacing = 1;
131   class->min_slider_size = 7;
132   class->trough = 1;
133   class->slider = 2;
134   class->step_forw = 3;
135   class->step_back = 4;
136   class->draw_background = NULL;
137   class->draw_trough = gtk_real_range_draw_trough;
138   class->draw_slider = gtk_real_range_draw_slider;
139   class->draw_step_forw = NULL;
140   class->draw_step_back = NULL;
141   class->trough_click = NULL;
142   class->trough_keys = NULL;
143   class->motion = NULL;
144   class->timer = gtk_real_range_timer;
145 }
146
147 static void
148 gtk_range_init (GtkRange *range)
149 {
150   range->trough = NULL;
151   range->slider = NULL;
152   range->step_forw = NULL;
153   range->step_back = NULL;
154
155   range->x_click_point = 0;
156   range->y_click_point = 0;
157   range->button = 0;
158   range->digits = -1;
159   range->policy = GTK_UPDATE_CONTINUOUS;
160   range->scroll_type = GTK_SCROLL_NONE;
161   range->in_child = 0;
162   range->click_child = 0;
163   range->need_timer = FALSE;
164   range->timer = 0;
165   range->old_value = 0.0;
166   range->old_lower = 0.0;
167   range->old_upper = 0.0;
168   range->old_page_size = 0.0;
169   range->adjustment = NULL;
170 }
171
172 GtkAdjustment*
173 gtk_range_get_adjustment (GtkRange *range)
174 {
175   g_return_val_if_fail (range != NULL, NULL);
176   g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
177
178   return range->adjustment;
179 }
180
181 void
182 gtk_range_set_update_policy (GtkRange      *range,
183                              GtkUpdateType  policy)
184 {
185   g_return_if_fail (range != NULL);
186   g_return_if_fail (GTK_IS_RANGE (range));
187
188   range->policy = policy;
189 }
190
191 void
192 gtk_range_set_adjustment (GtkRange      *range,
193                           GtkAdjustment *adjustment)
194 {
195   g_return_if_fail (range != NULL);
196   g_return_if_fail (GTK_IS_RANGE (range));
197
198   if (range->adjustment)
199     {
200       gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), (gpointer) range);
201       gtk_object_unref (GTK_OBJECT (range->adjustment));
202     }
203
204   range->adjustment = adjustment;
205   gtk_object_ref (GTK_OBJECT (range->adjustment));
206
207   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
208                       (GtkSignalFunc) gtk_range_adjustment_changed,
209                       (gpointer) range);
210   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
211                       (GtkSignalFunc) gtk_range_adjustment_value_changed,
212                       (gpointer) range);
213
214   range->old_value = adjustment->value;
215   range->old_lower = adjustment->lower;
216   range->old_upper = adjustment->upper;
217   range->old_page_size = adjustment->page_size;
218
219   gtk_range_adjustment_changed (range->adjustment, (gpointer) range);
220 }
221
222 void
223 gtk_range_draw_background (GtkRange *range)
224 {
225   g_return_if_fail (range != NULL);
226   g_return_if_fail (GTK_IS_RANGE (range));
227
228   if (range->trough && RANGE_CLASS (range)->draw_background)
229     (* RANGE_CLASS (range)->draw_background) (range);
230 }
231
232 void
233 gtk_range_draw_trough (GtkRange *range)
234 {
235   g_return_if_fail (range != NULL);
236   g_return_if_fail (GTK_IS_RANGE (range));
237
238   if (range->trough && RANGE_CLASS (range)->draw_trough)
239     (* RANGE_CLASS (range)->draw_trough) (range);
240 }
241
242 void
243 gtk_range_draw_slider (GtkRange *range)
244 {
245   g_return_if_fail (range != NULL);
246   g_return_if_fail (GTK_IS_RANGE (range));
247
248   if (range->slider && RANGE_CLASS (range)->draw_slider)
249     (* RANGE_CLASS (range)->draw_slider) (range);
250 }
251
252 void
253 gtk_range_draw_step_forw (GtkRange *range)
254 {
255   g_return_if_fail (range != NULL);
256   g_return_if_fail (GTK_IS_RANGE (range));
257
258   if (range->step_forw && RANGE_CLASS (range)->draw_step_forw)
259     (* RANGE_CLASS (range)->draw_step_forw) (range);
260 }
261
262 void
263 gtk_range_draw_step_back (GtkRange *range)
264 {
265   g_return_if_fail (range != NULL);
266   g_return_if_fail (GTK_IS_RANGE (range));
267
268   if (range->step_back && RANGE_CLASS (range)->draw_step_back)
269     (* RANGE_CLASS (range)->draw_step_back) (range);
270 }
271
272 void
273 gtk_range_slider_update (GtkRange *range)
274 {
275   g_return_if_fail (range != NULL);
276   g_return_if_fail (GTK_IS_RANGE (range));
277
278   if (RANGE_CLASS (range)->slider_update)
279     (* RANGE_CLASS (range)->slider_update) (range);
280 }
281
282 gint
283 gtk_range_trough_click (GtkRange *range,
284                         gint      x,
285                         gint      y)
286 {
287   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
288   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
289
290   if (RANGE_CLASS (range)->trough_click)
291     return (* RANGE_CLASS (range)->trough_click) (range, x, y);
292
293   return GTK_TROUGH_NONE;
294 }
295
296 void
297 gtk_range_default_hslider_update (GtkRange *range)
298 {
299   gint left;
300   gint right;
301   gint x;
302
303   g_return_if_fail (range != NULL);
304   g_return_if_fail (GTK_IS_RANGE (range));
305
306   if (GTK_WIDGET_REALIZED (range))
307     {
308       gtk_range_trough_hdims (range, &left, &right);
309       x = left;
310
311       if (range->adjustment->value < range->adjustment->lower)
312         {
313           range->adjustment->value = range->adjustment->lower;
314           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
315         }
316       else if (range->adjustment->value > range->adjustment->upper)
317         {
318           range->adjustment->value = range->adjustment->upper;
319           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
320         }
321
322       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
323         x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
324               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
325
326       if (x < left)
327         x = left;
328       else if (x > right)
329         x = right;
330
331       gdk_window_move (range->slider, x, GTK_WIDGET (range)->style->klass->ythickness);
332     }
333 }
334
335 void
336 gtk_range_default_vslider_update (GtkRange *range)
337 {
338   gint top;
339   gint bottom;
340   gint y;
341
342   g_return_if_fail (range != NULL);
343   g_return_if_fail (GTK_IS_RANGE (range));
344
345   if (GTK_WIDGET_REALIZED (range))
346     {
347       gtk_range_trough_vdims (range, &top, &bottom);
348       y = top;
349
350       if (range->adjustment->value < range->adjustment->lower)
351         {
352           range->adjustment->value = range->adjustment->lower;
353           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
354         }
355       else if (range->adjustment->value > range->adjustment->upper)
356         {
357           range->adjustment->value = range->adjustment->upper;
358           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
359         }
360
361       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
362         y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
363               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
364
365       if (y < top)
366         y = top;
367       else if (y > bottom)
368         y = bottom;
369
370       gdk_window_move (range->slider, GTK_WIDGET (range)->style->klass->ythickness, y);
371     }
372 }
373
374 gint
375 gtk_range_default_htrough_click (GtkRange *range,
376                                  gint      x,
377                                  gint      y)
378 {
379   gint xthickness;
380   gint ythickness;
381   gint trough_width;
382   gint trough_height;
383   gint slider_x;
384
385   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
386   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
387
388   xthickness = GTK_WIDGET (range)->style->klass->xthickness;
389   ythickness = GTK_WIDGET (range)->style->klass->ythickness;
390
391   if ((x > xthickness) && (y > ythickness))
392     {
393       gdk_window_get_size (range->trough, &trough_width, &trough_height);
394
395       if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness))))
396         {
397           gdk_window_get_position (range->slider, &slider_x, NULL);
398
399           if (x < slider_x)
400             return GTK_TROUGH_START;
401           else
402             return GTK_TROUGH_END;
403         }
404     }
405
406   return GTK_TROUGH_NONE;
407 }
408
409 gint
410 gtk_range_default_vtrough_click (GtkRange *range,
411                                  gint      x,
412                                  gint      y)
413 {
414   gint xthickness;
415   gint ythickness;
416   gint trough_width;
417   gint trough_height;
418   gint slider_y;
419
420   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
421   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
422
423   xthickness = GTK_WIDGET (range)->style->klass->xthickness;
424   ythickness = GTK_WIDGET (range)->style->klass->ythickness;
425
426   if ((x > xthickness) && (y > ythickness))
427     {
428       gdk_window_get_size (range->trough, &trough_width, &trough_height);
429
430       if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness))))
431         {
432           gdk_window_get_position (range->slider, NULL, &slider_y);
433
434           if (y < slider_y)
435             return GTK_TROUGH_START;
436           else
437             return GTK_TROUGH_END;
438         }
439     }
440
441   return GTK_TROUGH_NONE;
442 }
443
444 void
445 gtk_range_default_hmotion (GtkRange *range,
446                            gint      xdelta,
447                            gint      ydelta)
448 {
449   gdouble old_value;
450   gint left, right;
451   gint slider_x, slider_y;
452   gint new_pos;
453
454   g_return_if_fail (range != NULL);
455   g_return_if_fail (GTK_IS_RANGE (range));
456
457   range = GTK_RANGE (range);
458
459   gdk_window_get_position (range->slider, &slider_x, &slider_y);
460   gtk_range_trough_hdims (range, &left, &right);
461
462   if (left == right)
463     return;
464
465   new_pos = slider_x + xdelta;
466
467   if (new_pos < left)
468     new_pos = left;
469   else if (new_pos > right)
470     new_pos = right;
471
472   old_value = range->adjustment->value;
473   range->adjustment->value = ((range->adjustment->upper -
474                                range->adjustment->lower -
475                                range->adjustment->page_size) *
476                               (new_pos - left) / (right - left) +
477                               range->adjustment->lower);
478
479   if (range->digits >= 0)
480     {
481       char buffer[64];
482
483       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
484       sscanf (buffer, "%f", &range->adjustment->value);
485     }
486
487   if (old_value != range->adjustment->value)
488     {
489       if (range->policy == GTK_UPDATE_CONTINUOUS)
490         {
491           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
492         }
493       else
494         {
495           gtk_range_slider_update (range);
496           gtk_range_draw_background (range);
497
498           if (range->policy == GTK_UPDATE_DELAYED)
499             {
500               gtk_range_remove_timer (range);
501               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
502                                               (GtkFunction) RANGE_CLASS (range)->timer,
503                                               (gpointer) range);
504             }
505         }
506     }
507 }
508
509 void
510 gtk_range_default_vmotion (GtkRange *range,
511                            gint      xdelta,
512                            gint      ydelta)
513 {
514   gdouble old_value;
515   gint top, bottom;
516   gint slider_x, slider_y;
517   gint new_pos;
518
519   g_return_if_fail (range != NULL);
520   g_return_if_fail (GTK_IS_RANGE (range));
521
522   range = GTK_RANGE (range);
523
524   gdk_window_get_position (range->slider, &slider_x, &slider_y);
525   gtk_range_trough_vdims (range, &top, &bottom);
526
527   if (bottom == top)
528     return;
529
530   new_pos = slider_y + ydelta;
531
532   if (new_pos < top)
533     new_pos = top;
534   else if (new_pos > bottom)
535     new_pos = bottom;
536
537   old_value = range->adjustment->value;
538   range->adjustment->value = ((range->adjustment->upper -
539                                range->adjustment->lower -
540                                range->adjustment->page_size) *
541                               (new_pos - top) / (bottom - top) +
542                               range->adjustment->lower);
543
544   if (range->digits >= 0)
545     {
546       char buffer[64];
547
548       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
549       sscanf (buffer, "%f", &range->adjustment->value);
550     }
551
552   if (old_value != range->adjustment->value)
553     {
554       if (range->policy == GTK_UPDATE_CONTINUOUS)
555         {
556           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
557         }
558       else
559         {
560           gtk_range_slider_update (range);
561           gtk_range_draw_background (range);
562
563           if (range->policy == GTK_UPDATE_DELAYED)
564             {
565               gtk_range_remove_timer (range);
566               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
567                                               (GtkFunction) RANGE_CLASS (range)->timer,
568                                               (gpointer) range);
569             }
570         }
571     }
572 }
573
574 gfloat
575 gtk_range_calc_value (GtkRange *range,
576                       gint      position)
577 {
578   return 0.0;
579 }
580
581
582 static void
583 gtk_range_destroy (GtkObject *object)
584 {
585   GtkRange *range;
586
587   g_return_if_fail (object != NULL);
588   g_return_if_fail (GTK_IS_RANGE (object));
589
590   range = GTK_RANGE (object);
591
592   if (range->adjustment)
593     gtk_object_unref (GTK_OBJECT (range->adjustment));
594
595   if (GTK_OBJECT_CLASS (parent_class)->destroy)
596     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
597 }
598
599 static void
600 gtk_range_draw (GtkWidget    *widget,
601                 GdkRectangle *area)
602 {
603   GtkRange *range;
604
605   g_return_if_fail (widget != NULL);
606   g_return_if_fail (GTK_IS_RANGE (widget));
607   g_return_if_fail (area != NULL);
608
609   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
610     {
611       range = GTK_RANGE (widget);
612
613       gtk_range_draw_background (range);
614       gtk_range_draw_trough (range);
615       gtk_range_draw_slider (range);
616       gtk_range_draw_step_forw (range);
617       gtk_range_draw_step_back (range);
618     }
619 }
620
621 static void
622 gtk_range_draw_focus (GtkWidget *widget)
623 {
624   g_return_if_fail (widget != NULL);
625   g_return_if_fail (GTK_IS_RANGE (widget));
626
627   if (GTK_WIDGET_DRAWABLE (widget))
628     gtk_range_draw_trough (GTK_RANGE (widget));
629 }
630
631 static void
632 gtk_range_unrealize (GtkWidget *widget)
633 {
634   GtkRange *range;
635
636   g_return_if_fail (widget != NULL);
637   g_return_if_fail (GTK_IS_RANGE (widget));
638
639   GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
640   range = GTK_RANGE (widget);
641
642   gtk_style_detach (widget->style);
643
644   if (range->slider)
645     gdk_window_destroy (range->slider);
646   if (range->trough)
647     gdk_window_destroy (range->trough);
648   if (range->step_forw)
649     gdk_window_destroy (range->step_forw);
650   if (range->step_back)
651     gdk_window_destroy (range->step_back);
652   if (widget->window)
653     gdk_window_destroy (widget->window);
654
655   range->slider = NULL;
656   range->trough = NULL;
657   range->step_forw = NULL;
658   range->step_back = NULL;
659   widget->window = NULL;
660 }
661
662 static gint
663 gtk_range_expose (GtkWidget      *widget,
664                   GdkEventExpose *event)
665 {
666   GtkRange *range;
667
668   g_return_val_if_fail (widget != NULL, FALSE);
669   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
670   g_return_val_if_fail (event != NULL, FALSE);
671
672   range = GTK_RANGE (widget);
673
674   if (event->window == range->trough)
675     {
676       gtk_range_draw_trough (range);
677     }
678   else if (event->window == widget->window)
679     {
680       gtk_range_draw_background (range);
681     }
682   else if (event->window == range->slider)
683     {
684       gtk_range_draw_slider (range);
685     }
686   else if (event->window == range->step_forw)
687     {
688       gtk_range_draw_step_forw (range);
689     }
690   else if (event->window == range->step_back)
691     {
692       gtk_range_draw_step_back (range);
693     }
694   return FALSE;
695 }
696
697 static gint
698 gtk_range_button_press (GtkWidget      *widget,
699                         GdkEventButton *event)
700 {
701   GtkRange *range;
702   gint trough_part;
703
704   g_return_val_if_fail (widget != NULL, FALSE);
705   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
706   g_return_val_if_fail (event != NULL, FALSE);
707
708   if (!GTK_WIDGET_HAS_FOCUS (widget))
709     gtk_widget_grab_focus (widget);
710
711   range = GTK_RANGE (widget);
712   if (!range->button)
713     {
714       gtk_grab_add (widget);
715
716       range->button = event->button;
717       range->x_click_point = event->x;
718       range->y_click_point = event->y;
719
720       if (event->window == range->trough)
721         {
722           range->click_child = RANGE_CLASS (range)->trough;
723
724           trough_part = gtk_range_trough_click (range, event->x, event->y);
725
726           range->scroll_type = GTK_SCROLL_NONE;
727           if (trough_part == GTK_TROUGH_START)
728             range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
729           else if (trough_part == GTK_TROUGH_END)
730             range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
731
732           if (range->scroll_type != GTK_SCROLL_NONE)
733             {
734               gtk_range_scroll (range);
735               gtk_range_add_timer (range);
736             }
737         }
738       else if (event->window == range->slider)
739         {
740           range->click_child = RANGE_CLASS (range)->slider;
741           range->scroll_type = GTK_SCROLL_NONE;
742         }
743       else if (event->window == range->step_forw)
744         {
745           range->click_child = RANGE_CLASS (range)->step_forw;
746           range->scroll_type = GTK_SCROLL_STEP_FORWARD;
747
748           gtk_range_scroll (range);
749           gtk_range_add_timer (range);
750           gtk_range_draw_step_forw (range);
751         }
752       else if (event->window == range->step_back)
753         {
754           range->click_child = RANGE_CLASS (range)->step_back;
755           range->scroll_type = GTK_SCROLL_STEP_BACKWARD;
756
757           gtk_range_scroll (range);
758           gtk_range_add_timer (range);
759           gtk_range_draw_step_back (range);
760         }
761     }
762
763   return FALSE;
764 }
765
766 static gint
767 gtk_range_button_release (GtkWidget      *widget,
768                           GdkEventButton *event)
769 {
770   GtkRange *range;
771
772   g_return_val_if_fail (widget != NULL, FALSE);
773   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
774   g_return_val_if_fail (event != NULL, FALSE);
775
776   range = GTK_RANGE (widget);
777
778   if (range->button == event->button)
779     {
780       gtk_grab_remove (widget);
781
782       range->button = 0;
783       range->x_click_point = -1;
784       range->y_click_point = -1;
785
786       if (range->click_child == RANGE_CLASS (range)->slider)
787         {
788           if (range->policy == GTK_UPDATE_DELAYED)
789             gtk_range_remove_timer (range);
790
791           if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
792               (range->old_value != range->adjustment->value))
793             gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
794         }
795       else if ((range->click_child == RANGE_CLASS (range)->trough) ||
796                (range->click_child == RANGE_CLASS (range)->step_forw) ||
797                (range->click_child == RANGE_CLASS (range)->step_back))
798         {
799           gtk_range_remove_timer (range);
800
801           if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
802               (range->old_value != range->adjustment->value))
803             gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
804
805           if (range->click_child == RANGE_CLASS (range)->step_forw)
806             {
807               range->click_child = 0;
808               gtk_range_draw_step_forw (range);
809             }
810           else if (range->click_child == RANGE_CLASS (range)->step_back)
811             {
812               range->click_child = 0;
813               gtk_range_draw_step_back (range);
814             }
815         }
816
817       range->click_child = 0;
818     }
819
820   return FALSE;
821 }
822
823 static gint
824 gtk_range_motion_notify (GtkWidget      *widget,
825                          GdkEventMotion *event)
826 {
827   GtkRange *range;
828   GdkModifierType mods;
829   gint x, y, mask;
830
831   g_return_val_if_fail (widget != NULL, FALSE);
832   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
833   g_return_val_if_fail (event != NULL, FALSE);
834
835   range = GTK_RANGE (widget);
836
837   if (range->click_child == RANGE_CLASS (range)->slider)
838     {
839       x = event->x;
840       y = event->y;
841
842       if (event->is_hint || (event->window != range->slider))
843         gdk_window_get_pointer (range->slider, &x, &y, &mods);
844
845       switch (range->button)
846         {
847         case 1:
848           mask = GDK_BUTTON1_MASK;
849           break;
850         case 2:
851           mask = GDK_BUTTON2_MASK;
852           break;
853         case 3:
854           mask = GDK_BUTTON3_MASK;
855           break;
856         default:
857           mask = 0;
858           break;
859         }
860
861       if (mods & mask)
862         {
863           if (RANGE_CLASS (range)->motion)
864             (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
865         }
866     }
867
868   return FALSE;
869 }
870
871 static gint
872 gtk_range_key_press (GtkWidget   *widget,
873                      GdkEventKey *event)
874 {
875   GtkRange *range;
876   gint return_val;
877   GtkScrollType scroll = GTK_SCROLL_NONE;
878   GtkTroughType pos = GTK_TROUGH_NONE;
879
880   g_return_val_if_fail (widget != NULL, FALSE);
881   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
882   g_return_val_if_fail (event != NULL, FALSE);
883
884   range = GTK_RANGE (widget);
885   return_val = FALSE;
886
887   if (RANGE_CLASS (range)->trough_keys)
888     return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos);
889
890   if (return_val)
891     {
892       if (scroll != GTK_SCROLL_NONE)
893         {
894           range->scroll_type = scroll;
895           gtk_range_scroll (range);
896           if (range->old_value != range->adjustment->value)
897             {
898               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
899               switch (range->scroll_type)
900                 {
901                 case GTK_SCROLL_STEP_BACKWARD:
902                   gtk_range_draw_step_back (range);
903                   break;
904                 case GTK_SCROLL_STEP_FORWARD:
905                   gtk_range_draw_step_forw (range);
906                   break;
907                 }
908             }
909         }
910       if (pos != GTK_TROUGH_NONE)
911         {
912           if (pos == GTK_TROUGH_START)
913             range->adjustment->value = range->adjustment->lower;
914           else
915             range->adjustment->value =
916               range->adjustment->upper - range->adjustment->page_size;
917
918           if (range->old_value != range->adjustment->value)
919             {
920               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
921                                        "value_changed");
922
923               gtk_range_slider_update (range);
924               gtk_range_draw_background (range);
925             }
926         }
927     }
928   return return_val;
929 }
930
931 static gint
932 gtk_range_enter_notify (GtkWidget        *widget,
933                         GdkEventCrossing *event)
934 {
935   GtkRange *range;
936
937   g_return_val_if_fail (widget != NULL, FALSE);
938   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
939   g_return_val_if_fail (event != NULL, FALSE);
940
941   range = GTK_RANGE (widget);
942
943   if (event->window == range->trough)
944     {
945       range->in_child = RANGE_CLASS (range)->trough;
946     }
947   else if (event->window == range->slider)
948     {
949       range->in_child = RANGE_CLASS (range)->slider;
950
951       if ((range->click_child == 0) ||
952           (range->click_child == RANGE_CLASS (range)->trough))
953         gtk_range_draw_slider (range);
954     }
955   else if (event->window == range->step_forw)
956     {
957       range->in_child = RANGE_CLASS (range)->step_forw;
958
959       if ((range->click_child == 0) ||
960           (range->click_child == RANGE_CLASS (range)->trough))
961         gtk_range_draw_step_forw (range);
962     }
963   else if (event->window == range->step_back)
964     {
965       range->in_child = RANGE_CLASS (range)->step_back;
966
967       if ((range->click_child == 0) ||
968           (range->click_child == RANGE_CLASS (range)->trough))
969         gtk_range_draw_step_back (range);
970     }
971
972   return FALSE;
973 }
974
975 static gint
976 gtk_range_leave_notify (GtkWidget        *widget,
977                         GdkEventCrossing *event)
978 {
979   GtkRange *range;
980
981   g_return_val_if_fail (widget != NULL, FALSE);
982   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
983   g_return_val_if_fail (event != NULL, FALSE);
984
985   range = GTK_RANGE (widget);
986
987   range->in_child = 0;
988
989   if (event->window == range->trough)
990     {
991     }
992   else if (event->window == range->slider)
993     {
994       if ((range->click_child == 0) ||
995           (range->click_child == RANGE_CLASS (range)->trough))
996         gtk_range_draw_slider (range);
997     }
998   else if (event->window == range->step_forw)
999     {
1000       if ((range->click_child == 0) ||
1001           (range->click_child == RANGE_CLASS (range)->trough))
1002         gtk_range_draw_step_forw (range);
1003     }
1004   else if (event->window == range->step_back)
1005     {
1006       if ((range->click_child == 0) ||
1007           (range->click_child == RANGE_CLASS (range)->trough))
1008         gtk_range_draw_step_back (range);
1009     }
1010
1011   return FALSE;
1012 }
1013
1014 static gint
1015 gtk_range_focus_in (GtkWidget     *widget,
1016                     GdkEventFocus *event)
1017 {
1018   g_return_val_if_fail (widget != NULL, FALSE);
1019   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1020   g_return_val_if_fail (event != NULL, FALSE);
1021
1022   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1023   gtk_widget_draw_focus (widget);
1024
1025   return FALSE;
1026 }
1027
1028 static gint
1029 gtk_range_focus_out (GtkWidget     *widget,
1030                      GdkEventFocus *event)
1031 {
1032   g_return_val_if_fail (widget != NULL, FALSE);
1033   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1034   g_return_val_if_fail (event != NULL, FALSE);
1035
1036   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1037   gtk_widget_draw_focus (widget);
1038
1039   return FALSE;
1040 }
1041
1042 static void
1043 gtk_real_range_draw_trough (GtkRange *range)
1044 {
1045   g_return_if_fail (range != NULL);
1046   g_return_if_fail (GTK_IS_RANGE (range));
1047
1048   if (range->trough)
1049     {
1050       gtk_draw_shadow (GTK_WIDGET (range)->style, range->trough,
1051                        GTK_STATE_NORMAL, GTK_SHADOW_IN,
1052                        0, 0, -1, -1);
1053
1054       if (GTK_WIDGET_HAS_FOCUS (range))
1055         gdk_draw_rectangle (GTK_WIDGET (range)->window,
1056                             GTK_WIDGET (range)->style->black_gc,
1057                             FALSE, 0, 0,
1058                             GTK_WIDGET (range)->allocation.width - 1,
1059                             GTK_WIDGET (range)->allocation.height - 1);
1060       else if (range->trough != GTK_WIDGET (range)->window)
1061         gdk_draw_rectangle (GTK_WIDGET (range)->window,
1062                             GTK_WIDGET (range)->style->bg_gc[GTK_STATE_NORMAL],
1063                             FALSE, 0, 0,
1064                             GTK_WIDGET (range)->allocation.width - 1,
1065                             GTK_WIDGET (range)->allocation.height - 1);
1066     }
1067 }
1068
1069 static void
1070 gtk_real_range_draw_slider (GtkRange *range)
1071 {
1072   GtkStateType state_type;
1073
1074   g_return_if_fail (range != NULL);
1075   g_return_if_fail (GTK_IS_RANGE (range));
1076
1077   if (range->slider)
1078     {
1079       if ((range->in_child == RANGE_CLASS (range)->slider) ||
1080           (range->click_child == RANGE_CLASS (range)->slider))
1081         state_type = GTK_STATE_PRELIGHT;
1082       else
1083         state_type = GTK_STATE_NORMAL;
1084
1085       gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type);
1086       gdk_window_clear (range->slider);
1087
1088       gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider,
1089                        state_type, GTK_SHADOW_OUT,
1090                        0, 0, -1, -1);
1091     }
1092 }
1093
1094 static gint
1095 gtk_real_range_timer (GtkRange *range)
1096 {
1097   gint return_val;
1098
1099   g_return_val_if_fail (range != NULL, FALSE);
1100   g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1101
1102   return_val = TRUE;
1103   if (range->click_child == RANGE_CLASS (range)->slider)
1104     {
1105       if (range->policy == GTK_UPDATE_DELAYED)
1106         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1107       return_val = FALSE;
1108     }
1109   else
1110     {
1111       if (!range->timer)
1112         {
1113           return_val = FALSE;
1114           if (range->need_timer)
1115             range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
1116                                             (GtkFunction) RANGE_CLASS (range)->timer,
1117                                             (gpointer) range);
1118           else
1119             return FALSE;
1120           range->need_timer = FALSE;
1121         }
1122
1123       if (gtk_range_scroll (range))
1124         return return_val;
1125     }
1126
1127   return return_val;
1128 }
1129
1130 static gint
1131 gtk_range_scroll (GtkRange *range)
1132 {
1133   gfloat new_value;
1134   gint return_val;
1135
1136   g_return_val_if_fail (range != NULL, FALSE);
1137   g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1138
1139   new_value = range->adjustment->value;
1140   return_val = TRUE;
1141
1142   switch (range->scroll_type)
1143     {
1144     case GTK_SCROLL_NONE:
1145       break;
1146
1147     case GTK_SCROLL_STEP_BACKWARD:
1148       new_value -= range->adjustment->step_increment;
1149       if (new_value <= range->adjustment->lower)
1150         {
1151           new_value = range->adjustment->lower;
1152           return_val = FALSE;
1153           range->timer = 0;
1154         }
1155       break;
1156
1157     case GTK_SCROLL_STEP_FORWARD:
1158       new_value += range->adjustment->step_increment;
1159       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1160         {
1161           new_value = range->adjustment->upper - range->adjustment->page_size;
1162           return_val = FALSE;
1163           range->timer = 0;
1164         }
1165       break;
1166
1167     case GTK_SCROLL_PAGE_BACKWARD:
1168       new_value -= range->adjustment->page_increment;
1169       if (new_value <= range->adjustment->lower)
1170         {
1171           new_value = range->adjustment->lower;
1172           return_val = FALSE;
1173           range->timer = 0;
1174         }
1175       break;
1176
1177     case GTK_SCROLL_PAGE_FORWARD:
1178       new_value += range->adjustment->page_increment;
1179       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1180         {
1181           new_value = range->adjustment->upper - range->adjustment->page_size;
1182           return_val = FALSE;
1183           range->timer = 0;
1184         }
1185       break;
1186     }
1187
1188   if (new_value != range->adjustment->value)
1189     {
1190       range->adjustment->value = new_value;
1191
1192       if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
1193           (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
1194         {
1195           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1196         }
1197       else
1198         {
1199           gtk_range_slider_update (range);
1200           gtk_range_draw_background (range);
1201         }
1202     }
1203
1204   return return_val;
1205 }
1206
1207
1208 static void
1209 gtk_range_add_timer (GtkRange *range)
1210 {
1211   g_return_if_fail (range != NULL);
1212   g_return_if_fail (GTK_IS_RANGE (range));
1213
1214   if (!range->timer)
1215     {
1216       range->need_timer = TRUE;
1217       range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
1218                                       (GtkFunction) RANGE_CLASS (range)->timer,
1219                                       (gpointer) range);
1220     }
1221 }
1222
1223 static void
1224 gtk_range_remove_timer (GtkRange *range)
1225 {
1226   g_return_if_fail (range != NULL);
1227   g_return_if_fail (GTK_IS_RANGE (range));
1228
1229   if (range->timer)
1230     {
1231       gtk_timeout_remove (range->timer);
1232       range->timer = 0;
1233     }
1234   range->need_timer = FALSE;
1235 }
1236
1237 static void
1238 gtk_range_adjustment_changed (GtkAdjustment *adjustment,
1239                               gpointer       data)
1240 {
1241   GtkRange *range;
1242
1243   g_return_if_fail (adjustment != NULL);
1244   g_return_if_fail (data != NULL);
1245
1246   range = GTK_RANGE (data);
1247
1248   if (((range->old_lower != adjustment->lower) ||
1249        (range->old_upper != adjustment->upper) ||
1250        (range->old_page_size != adjustment->page_size)) &&
1251       (range->old_value == adjustment->value))
1252     {
1253       if ((adjustment->lower == adjustment->upper) ||
1254           (range->old_lower == (range->old_upper - range->old_page_size)))
1255         {
1256           adjustment->value = adjustment->lower;
1257           gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
1258         }
1259     }
1260
1261   if ((range->old_value != adjustment->value) ||
1262       (range->old_lower != adjustment->lower) ||
1263       (range->old_upper != adjustment->upper) ||
1264       (range->old_page_size != adjustment->page_size))
1265     {
1266       gtk_range_slider_update (range);
1267       gtk_range_draw_background (range);
1268
1269       range->old_value = adjustment->value;
1270       range->old_lower = adjustment->lower;
1271       range->old_upper = adjustment->upper;
1272       range->old_page_size = adjustment->page_size;
1273     }
1274 }
1275
1276 static void
1277 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
1278                                     gpointer       data)
1279 {
1280   GtkRange *range;
1281
1282   g_return_if_fail (adjustment != NULL);
1283   g_return_if_fail (data != NULL);
1284
1285   range = GTK_RANGE (data);
1286
1287   if (range->old_value != adjustment->value)
1288     {
1289       gtk_range_slider_update (range);
1290       gtk_range_draw_background (range);
1291
1292       range->old_value = adjustment->value;
1293     }
1294 }
1295
1296
1297 static void
1298 gtk_range_trough_hdims (GtkRange *range,
1299                         gint     *left,
1300                         gint     *right)
1301 {
1302   gint trough_width;
1303   gint slider_length;
1304   gint tmp_width;
1305   gint tleft;
1306   gint tright;
1307
1308   g_return_if_fail (range != NULL);
1309
1310   gdk_window_get_size (range->trough, &trough_width, NULL);
1311   gdk_window_get_size (range->slider, &slider_length, NULL);
1312
1313   tleft = GTK_WIDGET (range)->style->klass->xthickness;
1314   tright = trough_width - slider_length - GTK_WIDGET (range)->style->klass->xthickness;
1315
1316   if (range->step_back)
1317     {
1318       gdk_window_get_size (range->step_back, &tmp_width, NULL);
1319       tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1320     }
1321
1322   if (range->step_forw)
1323     {
1324       gdk_window_get_size (range->step_forw, &tmp_width, NULL);
1325       tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1326     }
1327
1328   if (left)
1329     *left = tleft;
1330   if (right)
1331     *right = tright;
1332 }
1333
1334 static void
1335 gtk_range_trough_vdims (GtkRange *range,
1336                         gint     *top,
1337                         gint     *bottom)
1338 {
1339   gint trough_height;
1340   gint slider_length;
1341   gint tmp_height;
1342   gint ttop;
1343   gint tbottom;
1344
1345   g_return_if_fail (range != NULL);
1346
1347   gdk_window_get_size (range->trough, NULL, &trough_height);
1348   gdk_window_get_size (range->slider, NULL, &slider_length);
1349
1350   ttop = GTK_WIDGET (range)->style->klass->xthickness;
1351   tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->klass->ythickness;
1352
1353   if (range->step_back)
1354     {
1355       gdk_window_get_size (range->step_back, NULL, &tmp_height);
1356       ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1357     }
1358
1359   if (range->step_forw)
1360     {
1361       gdk_window_get_size (range->step_forw, NULL, &tmp_height);
1362       tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1363     }
1364
1365   if (top)
1366     *top = ttop;
1367   if (bottom)
1368     *bottom = tbottom;
1369 }