1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
30 #include "gtksignal.h"
32 #define SCROLL_TIMER_LENGTH 20
33 #define SCROLL_INITIAL_DELAY 100
34 #define SCROLL_DELAY_LENGTH 300
36 #define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w)
43 static void gtk_range_class_init (GtkRangeClass *klass);
44 static void gtk_range_init (GtkRange *range);
45 static void gtk_range_set_arg (GtkObject *object,
48 static void gtk_range_get_arg (GtkObject *object,
51 static void gtk_range_destroy (GtkObject *object);
52 static void gtk_range_draw_focus (GtkWidget *widget);
53 static void gtk_range_unrealize (GtkWidget *widget);
54 static gint gtk_range_expose (GtkWidget *widget,
55 GdkEventExpose *event);
56 static gint gtk_range_button_press (GtkWidget *widget,
57 GdkEventButton *event);
58 static gint gtk_range_button_release (GtkWidget *widget,
59 GdkEventButton *event);
60 static gint gtk_range_motion_notify (GtkWidget *widget,
61 GdkEventMotion *event);
62 static gint gtk_range_key_press (GtkWidget *widget,
64 static gint gtk_range_enter_notify (GtkWidget *widget,
65 GdkEventCrossing *event);
66 static gint gtk_range_leave_notify (GtkWidget *widget,
67 GdkEventCrossing *event);
68 static gint gtk_range_focus_in (GtkWidget *widget,
69 GdkEventFocus *event);
70 static gint gtk_range_focus_out (GtkWidget *widget,
71 GdkEventFocus *event);
72 static gint gtk_range_scroll_event (GtkWidget *widget,
73 GdkEventScroll *event);
74 static void gtk_range_style_set (GtkWidget *widget,
75 GtkStyle *previous_style);
77 static void gtk_real_range_draw_trough (GtkRange *range);
78 static void gtk_real_range_draw_slider (GtkRange *range);
79 static gint gtk_real_range_timer (GtkRange *range);
80 static gint gtk_range_scroll (GtkRange *range,
83 static void gtk_range_add_timer (GtkRange *range);
84 static void gtk_range_remove_timer (GtkRange *range);
86 static void gtk_range_adjustment_changed (GtkAdjustment *adjustment,
88 static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
91 static void gtk_range_trough_hdims (GtkRange *range,
94 static void gtk_range_trough_vdims (GtkRange *range,
98 static GtkWidgetClass *parent_class = NULL;
102 gtk_range_get_type (void)
104 static GtkType range_type = 0;
108 static const GtkTypeInfo range_info =
112 sizeof (GtkRangeClass),
113 (GtkClassInitFunc) gtk_range_class_init,
114 (GtkObjectInitFunc) gtk_range_init,
115 /* reserved_1 */ NULL,
116 /* reserved_2 */ NULL,
117 (GtkClassInitFunc) NULL,
120 range_type = gtk_type_unique (GTK_TYPE_WIDGET, &range_info);
127 gtk_range_class_init (GtkRangeClass *class)
129 GtkObjectClass *object_class;
130 GtkWidgetClass *widget_class;
132 object_class = (GtkObjectClass*) class;
133 widget_class = (GtkWidgetClass*) class;
135 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
137 object_class->set_arg = gtk_range_set_arg;
138 object_class->get_arg = gtk_range_get_arg;
139 object_class->destroy = gtk_range_destroy;
141 widget_class->draw_focus = gtk_range_draw_focus;
142 widget_class->unrealize = gtk_range_unrealize;
143 widget_class->expose_event = gtk_range_expose;
144 widget_class->button_press_event = gtk_range_button_press;
145 widget_class->button_release_event = gtk_range_button_release;
146 widget_class->motion_notify_event = gtk_range_motion_notify;
147 widget_class->scroll_event = gtk_range_scroll_event;
148 widget_class->key_press_event = gtk_range_key_press;
149 widget_class->enter_notify_event = gtk_range_enter_notify;
150 widget_class->leave_notify_event = gtk_range_leave_notify;
151 widget_class->focus_in_event = gtk_range_focus_in;
152 widget_class->focus_out_event = gtk_range_focus_out;
153 widget_class->style_set = gtk_range_style_set;
155 class->slider_width = 11;
156 class->stepper_size = 11;
157 class->stepper_slider_spacing = 1;
158 class->min_slider_size = 7;
161 class->step_forw = 3;
162 class->step_back = 4;
163 class->draw_background = NULL;
164 class->clear_background = NULL;
165 class->draw_trough = gtk_real_range_draw_trough;
166 class->draw_slider = gtk_real_range_draw_slider;
167 class->draw_step_forw = NULL;
168 class->draw_step_back = NULL;
169 class->trough_click = NULL;
170 class->trough_keys = NULL;
171 class->motion = NULL;
172 class->timer = gtk_real_range_timer;
174 gtk_object_add_arg_type ("GtkRange::update_policy",
175 GTK_TYPE_UPDATE_TYPE,
181 gtk_range_set_arg (GtkObject *object,
187 range = GTK_RANGE (object);
191 case ARG_UPDATE_POLICY:
192 gtk_range_set_update_policy (range, GTK_VALUE_ENUM (*arg));
200 gtk_range_get_arg (GtkObject *object,
206 range = GTK_RANGE (object);
210 case ARG_UPDATE_POLICY:
211 GTK_VALUE_ENUM (*arg) = range->policy;
214 arg->type = GTK_TYPE_INVALID;
220 gtk_range_init (GtkRange *range)
222 range->trough = NULL;
223 range->slider = NULL;
224 range->step_forw = NULL;
225 range->step_back = NULL;
227 range->x_click_point = 0;
228 range->y_click_point = 0;
231 range->policy = GTK_UPDATE_CONTINUOUS;
232 range->scroll_type = GTK_SCROLL_NONE;
234 range->click_child = 0;
235 range->need_timer = FALSE;
237 range->flippable = 0;
238 range->old_value = 0.0;
239 range->old_lower = 0.0;
240 range->old_upper = 0.0;
241 range->old_page_size = 0.0;
242 range->adjustment = NULL;
246 gtk_range_get_adjustment (GtkRange *range)
248 g_return_val_if_fail (range != NULL, NULL);
249 g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
251 if (!range->adjustment)
252 gtk_range_set_adjustment (range, NULL);
254 return range->adjustment;
258 gtk_range_set_update_policy (GtkRange *range,
259 GtkUpdateType policy)
261 g_return_if_fail (range != NULL);
262 g_return_if_fail (GTK_IS_RANGE (range));
264 range->policy = policy;
268 gtk_range_set_adjustment (GtkRange *range,
269 GtkAdjustment *adjustment)
271 g_return_if_fail (range != NULL);
272 g_return_if_fail (GTK_IS_RANGE (range));
275 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
277 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
279 if (range->adjustment != adjustment)
281 if (range->adjustment)
283 gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
285 gtk_object_unref (GTK_OBJECT (range->adjustment));
288 range->adjustment = adjustment;
289 gtk_object_ref (GTK_OBJECT (adjustment));
290 gtk_object_sink (GTK_OBJECT (adjustment));
292 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
293 (GtkSignalFunc) gtk_range_adjustment_changed,
295 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
296 (GtkSignalFunc) gtk_range_adjustment_value_changed,
299 range->old_value = adjustment->value;
300 range->old_lower = adjustment->lower;
301 range->old_upper = adjustment->upper;
302 range->old_page_size = adjustment->page_size;
304 gtk_range_adjustment_changed (adjustment, (gpointer) range);
309 gtk_range_draw_background (GtkRange *range)
311 g_return_if_fail (range != NULL);
312 g_return_if_fail (GTK_IS_RANGE (range));
314 if (range->trough && RANGE_CLASS (range)->draw_background)
315 (* RANGE_CLASS (range)->draw_background) (range);
319 gtk_range_clear_background (GtkRange *range)
321 g_return_if_fail (range != NULL);
322 g_return_if_fail (GTK_IS_RANGE (range));
324 if (range->trough && RANGE_CLASS (range)->clear_background)
325 (* RANGE_CLASS (range)->clear_background) (range);
329 gtk_range_draw_trough (GtkRange *range)
331 g_return_if_fail (range != NULL);
332 g_return_if_fail (GTK_IS_RANGE (range));
334 if (range->trough && RANGE_CLASS (range)->draw_trough)
335 (* RANGE_CLASS (range)->draw_trough) (range);
339 gtk_range_draw_slider (GtkRange *range)
341 g_return_if_fail (range != NULL);
342 g_return_if_fail (GTK_IS_RANGE (range));
344 if (range->slider && RANGE_CLASS (range)->draw_slider)
345 (* RANGE_CLASS (range)->draw_slider) (range);
349 gtk_range_draw_step_forw (GtkRange *range)
351 g_return_if_fail (range != NULL);
352 g_return_if_fail (GTK_IS_RANGE (range));
354 if (range->step_forw && RANGE_CLASS (range)->draw_step_forw)
355 (* RANGE_CLASS (range)->draw_step_forw) (range);
359 gtk_range_draw_step_back (GtkRange *range)
361 g_return_if_fail (range != NULL);
362 g_return_if_fail (GTK_IS_RANGE (range));
364 if (range->step_back && RANGE_CLASS (range)->draw_step_back)
365 (* RANGE_CLASS (range)->draw_step_back) (range);
369 gtk_range_slider_update (GtkRange *range)
371 g_return_if_fail (range != NULL);
372 g_return_if_fail (GTK_IS_RANGE (range));
374 if (RANGE_CLASS (range)->slider_update)
375 (* RANGE_CLASS (range)->slider_update) (range);
379 gtk_range_trough_click (GtkRange *range,
384 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
385 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
387 if (RANGE_CLASS (range)->trough_click)
388 return (* RANGE_CLASS (range)->trough_click) (range, x, y, jump_perc);
390 return GTK_TROUGH_NONE;
394 get_window_region (GdkWindow *window)
398 gdk_window_get_position (window, &rect.x, &rect.y);
399 gdk_window_get_size (window, &rect.width, &rect.height);
401 return gdk_region_rectangle (&rect);
405 move_and_update_window (GdkWindow *window, gint x, gint y)
407 GdkRegion *old_region;
408 GdkRegion *new_region;
409 GdkWindow *parent = gdk_window_get_parent (window);
411 old_region = get_window_region (window);
412 gdk_window_move (window, x, y);
413 new_region = get_window_region (window);
415 gdk_region_subtract (old_region, new_region);
416 gdk_window_invalidate_region (parent, old_region, TRUE);
417 gdk_region_destroy (old_region);
418 gdk_region_destroy (new_region);
420 gdk_window_process_updates (parent, TRUE);
424 gtk_range_default_hslider_update (GtkRange *range)
430 g_return_if_fail (range != NULL);
431 g_return_if_fail (GTK_IS_RANGE (range));
433 if (GTK_WIDGET_REALIZED (range))
435 gtk_range_trough_hdims (range, &left, &right);
438 if (range->adjustment->value < range->adjustment->lower)
440 range->adjustment->value = range->adjustment->lower;
441 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
443 else if (range->adjustment->value > range->adjustment->upper)
445 range->adjustment->value = range->adjustment->upper;
446 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
449 if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
450 x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
451 (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
458 if (range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL)
459 x = right - (x - left);
461 move_and_update_window (range->slider, x, GTK_WIDGET (range)->style->ythickness);
466 gtk_range_default_vslider_update (GtkRange *range)
472 g_return_if_fail (range != NULL);
473 g_return_if_fail (GTK_IS_RANGE (range));
475 if (GTK_WIDGET_REALIZED (range))
477 gtk_range_trough_vdims (range, &top, &bottom);
480 if (range->adjustment->value < range->adjustment->lower)
482 range->adjustment->value = range->adjustment->lower;
483 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
485 else if (range->adjustment->value > range->adjustment->upper)
487 range->adjustment->value = range->adjustment->upper;
488 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
491 if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
492 y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
493 (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
500 move_and_update_window (range->slider, GTK_WIDGET (range)->style->xthickness, y);
505 gtk_range_default_htrough_click (GtkRange *range,
517 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
518 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
520 ythickness = GTK_WIDGET (range)->style->ythickness;
522 gtk_range_trough_hdims (range, &left, &right);
523 gdk_window_get_size (range->slider, &slider_length, NULL);
524 right += slider_length;
526 if (range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL)
527 x = (right - x) + left;
529 if ((x > left) && (y > ythickness))
531 gdk_window_get_size (range->trough, &trough_width, &trough_height);
533 if ((x < right) && (y < (trough_height - ythickness)))
537 *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left));
538 return GTK_TROUGH_JUMP;
541 gdk_window_get_position (range->slider, &slider_x, NULL);
544 return GTK_TROUGH_START;
546 return GTK_TROUGH_END;
550 return GTK_TROUGH_NONE;
554 gtk_range_default_vtrough_click (GtkRange *range,
566 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
567 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
569 xthickness = GTK_WIDGET (range)->style->xthickness;
571 gtk_range_trough_vdims (range, &top, &bottom);
572 gdk_window_get_size (range->slider, NULL, &slider_length);
573 bottom += slider_length;
575 if ((x > xthickness) && (y > top))
577 gdk_window_get_size (range->trough, &trough_width, &trough_height);
579 if ((x < (trough_width - xthickness) && (y < bottom)))
583 *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top));
585 return GTK_TROUGH_JUMP;
588 gdk_window_get_position (range->slider, NULL, &slider_y);
591 return GTK_TROUGH_START;
593 return GTK_TROUGH_END;
597 return GTK_TROUGH_NONE;
601 gtk_range_default_hmotion (GtkRange *range,
607 gint slider_x, slider_y;
610 g_return_if_fail (GTK_IS_RANGE (range));
611 g_return_if_fail (GTK_WIDGET_REALIZED (range));
613 gdk_window_get_position (range->slider, &slider_x, &slider_y);
614 gtk_range_trough_hdims (range, &left, &right);
619 new_pos = slider_x + xdelta;
621 if (range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL)
622 new_pos = (right - new_pos) + left;
626 else if (new_pos > right)
629 old_value = range->adjustment->value;
630 range->adjustment->value = ((range->adjustment->upper -
631 range->adjustment->lower -
632 range->adjustment->page_size) *
633 (new_pos - left) / (right - left) +
634 range->adjustment->lower);
636 if (range->digits >= 0)
640 sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
641 sscanf (buffer, "%f", &range->adjustment->value);
644 if (old_value != range->adjustment->value)
646 if (range->policy == GTK_UPDATE_CONTINUOUS)
648 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
652 gtk_range_slider_update (range);
653 gtk_range_clear_background (range);
655 if (range->policy == GTK_UPDATE_DELAYED)
657 gtk_range_remove_timer (range);
658 range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
659 (GtkFunction) RANGE_CLASS (range)->timer,
667 gtk_range_default_vmotion (GtkRange *range,
673 gint slider_x, slider_y;
676 g_return_if_fail (GTK_IS_RANGE (range));
677 g_return_if_fail (GTK_WIDGET_REALIZED (range));
679 range = GTK_RANGE (range);
681 gdk_window_get_position (range->slider, &slider_x, &slider_y);
682 gtk_range_trough_vdims (range, &top, &bottom);
687 new_pos = slider_y + ydelta;
691 else if (new_pos > bottom)
694 old_value = range->adjustment->value;
695 range->adjustment->value = ((range->adjustment->upper -
696 range->adjustment->lower -
697 range->adjustment->page_size) *
698 (new_pos - top) / (bottom - top) +
699 range->adjustment->lower);
701 if (range->digits >= 0)
705 sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
706 sscanf (buffer, "%f", &range->adjustment->value);
709 if (old_value != range->adjustment->value)
711 if (range->policy == GTK_UPDATE_CONTINUOUS)
713 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
717 gtk_range_slider_update (range);
718 gtk_range_clear_background (range);
720 if (range->policy == GTK_UPDATE_DELAYED)
722 gtk_range_remove_timer (range);
723 range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
724 (GtkFunction) RANGE_CLASS (range)->timer,
733 gtk_range_destroy (GtkObject *object)
737 g_return_if_fail (object != NULL);
738 g_return_if_fail (GTK_IS_RANGE (object));
740 range = GTK_RANGE (object);
742 gtk_range_remove_timer (range);
743 if (range->adjustment)
745 if (range->adjustment)
746 gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
748 gtk_object_unref (GTK_OBJECT (range->adjustment));
749 range->adjustment = NULL;
752 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
756 gtk_range_draw_focus (GtkWidget *widget)
758 g_return_if_fail (widget != NULL);
759 g_return_if_fail (GTK_IS_RANGE (widget));
761 if (GTK_WIDGET_DRAWABLE (widget))
762 gtk_range_draw_trough (GTK_RANGE (widget));
766 gtk_range_unrealize (GtkWidget *widget)
770 g_return_if_fail (widget != NULL);
771 g_return_if_fail (GTK_IS_RANGE (widget));
773 range = GTK_RANGE (widget);
777 gdk_window_set_user_data (range->slider, NULL);
778 gdk_window_destroy (range->slider);
779 range->slider = NULL;
783 gdk_window_set_user_data (range->trough, NULL);
784 gdk_window_destroy (range->trough);
785 range->trough = NULL;
787 if (range->step_forw)
789 gdk_window_set_user_data (range->step_forw, NULL);
790 gdk_window_destroy (range->step_forw);
791 range->step_forw = NULL;
793 if (range->step_back)
795 gdk_window_set_user_data (range->step_back, NULL);
796 gdk_window_destroy (range->step_back);
797 range->step_back = NULL;
800 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
801 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
805 gtk_range_expose (GtkWidget *widget,
806 GdkEventExpose *event)
810 g_return_val_if_fail (widget != NULL, FALSE);
811 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
812 g_return_val_if_fail (event != NULL, FALSE);
814 range = GTK_RANGE (widget);
816 /* We should really pass another argument -
817 *the redrawn area - to all the drawing functions)
819 if (event->window == range->trough)
821 gtk_range_draw_trough (range);
823 else if (event->window == widget->window)
825 gtk_range_draw_background (range);
827 else if (event->window == range->slider)
829 gtk_range_draw_slider (range);
831 else if (event->window == range->step_forw)
833 gtk_range_draw_step_forw (range);
835 else if (event->window == range->step_back)
837 gtk_range_draw_step_back (range);
843 gtk_range_button_press (GtkWidget *widget,
844 GdkEventButton *event)
850 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
851 g_return_val_if_fail (event != NULL, FALSE);
853 if (!GTK_WIDGET_HAS_FOCUS (widget))
854 gtk_widget_grab_focus (widget);
857 range = GTK_RANGE (widget);
858 if (range->button == 0)
860 gtk_grab_add (widget);
862 range->button = event->button;
863 range->x_click_point = event->x;
864 range->y_click_point = event->y;
866 if (event->window == range->trough)
868 range->click_child = RANGE_CLASS (range)->trough;
870 if (range->button == 2)
871 trough_part = gtk_range_trough_click (range, event->x, event->y, &jump_perc);
873 trough_part = gtk_range_trough_click (range, event->x, event->y, NULL);
875 range->scroll_type = GTK_SCROLL_NONE;
876 if (trough_part == GTK_TROUGH_START)
877 range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
878 else if (trough_part == GTK_TROUGH_END)
879 range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
880 else if (trough_part == GTK_TROUGH_JUMP &&
881 jump_perc >= 0 && jump_perc <= 1)
882 range->scroll_type = GTK_SCROLL_JUMP;
884 if (range->scroll_type != GTK_SCROLL_NONE)
886 gtk_range_scroll (range, jump_perc);
887 gtk_range_add_timer (range);
890 else if (event->window == range->slider)
892 range->click_child = RANGE_CLASS (range)->slider;
893 range->scroll_type = GTK_SCROLL_NONE;
895 else if (event->window == range->step_forw ||
896 event->window == range->step_back)
898 gboolean back = (event->window == range->step_back);
900 if (range->button == 3)
902 range->scroll_type = GTK_SCROLL_JUMP;
903 gtk_range_scroll (range, back ? 0.0 : 1.0);
908 back ? RANGE_CLASS (range)->step_back
909 : RANGE_CLASS (range)->step_forw;
911 if (range->button == 2)
913 back ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD;
916 back ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD;
918 gtk_range_scroll (range, -1);
919 gtk_range_add_timer (range);
922 gtk_range_draw_step_back (range);
924 gtk_range_draw_step_forw (range);
933 gtk_range_button_release (GtkWidget *widget,
934 GdkEventButton *event)
938 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
939 g_return_val_if_fail (event != NULL, FALSE);
941 range = GTK_RANGE (widget);
943 if (range->button == event->button)
945 gtk_grab_remove (widget);
948 range->x_click_point = -1;
949 range->y_click_point = -1;
951 if (range->click_child == RANGE_CLASS (range)->slider)
953 if (range->policy == GTK_UPDATE_DELAYED)
954 gtk_range_remove_timer (range);
956 if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
957 (range->old_value != range->adjustment->value))
958 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
960 else if ((range->click_child == RANGE_CLASS (range)->trough) ||
961 (range->click_child == RANGE_CLASS (range)->step_forw) ||
962 (range->click_child == RANGE_CLASS (range)->step_back))
964 gtk_range_remove_timer (range);
966 if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
967 (range->old_value != range->adjustment->value))
968 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
970 if (range->click_child == RANGE_CLASS (range)->step_forw)
972 range->click_child = 0;
973 gtk_range_draw_step_forw (range);
975 else if (range->click_child == RANGE_CLASS (range)->step_back)
977 range->click_child = 0;
978 gtk_range_draw_step_back (range);
982 range->click_child = 0;
989 gtk_range_scroll_event (GtkWidget *widget,
990 GdkEventScroll *event)
994 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
995 g_return_val_if_fail (event != NULL, FALSE);
997 range = GTK_RANGE (widget);
999 if (GTK_WIDGET_REALIZED (range))
1001 GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1002 gfloat new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ?
1003 -adj->page_increment / 2:
1004 adj->page_increment / 2);
1005 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
1006 gtk_adjustment_set_value (adj, new_value);
1013 gtk_range_motion_notify (GtkWidget *widget,
1014 GdkEventMotion *event)
1018 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1019 g_return_val_if_fail (event != NULL, FALSE);
1021 range = GTK_RANGE (widget);
1023 if (range->click_child == RANGE_CLASS (range)->slider)
1025 GdkModifierType mods;
1026 gint x, y, mask, x2, y2;
1028 gdk_window_get_pointer (range->trough, &x, &y, &mods);
1029 gdk_window_get_position (range->slider, &x2, &y2);
1034 switch (range->button)
1037 mask = GDK_BUTTON1_MASK;
1040 mask = GDK_BUTTON2_MASK;
1043 mask = GDK_BUTTON3_MASK;
1052 if (RANGE_CLASS (range)->motion)
1053 (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
1061 gtk_range_key_press (GtkWidget *widget,
1066 GtkScrollType scroll = GTK_SCROLL_NONE;
1067 GtkTroughType pos = GTK_TROUGH_NONE;
1069 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1070 g_return_val_if_fail (event != NULL, FALSE);
1072 range = GTK_RANGE (widget);
1075 if (RANGE_CLASS (range)->trough_keys)
1076 return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos);
1080 if (scroll != GTK_SCROLL_NONE)
1082 range->scroll_type = scroll;
1083 gtk_range_scroll (range, -1);
1084 if (range->old_value != range->adjustment->value)
1086 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1087 switch (range->scroll_type)
1089 case GTK_SCROLL_STEP_BACKWARD:
1090 gtk_range_draw_step_back (range);
1092 case GTK_SCROLL_STEP_FORWARD:
1093 gtk_range_draw_step_forw (range);
1098 if (pos != GTK_TROUGH_NONE)
1100 if (pos == GTK_TROUGH_START)
1101 range->adjustment->value = range->adjustment->lower;
1102 else if (pos == GTK_TROUGH_END)
1103 range->adjustment->value =
1104 range->adjustment->upper - range->adjustment->page_size;
1106 if (range->old_value != range->adjustment->value)
1108 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
1111 gtk_range_slider_update (range);
1112 gtk_range_clear_background (range);
1120 gtk_range_enter_notify (GtkWidget *widget,
1121 GdkEventCrossing *event)
1125 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1126 g_return_val_if_fail (event != NULL, FALSE);
1128 range = GTK_RANGE (widget);
1130 if (event->window == range->trough)
1132 range->in_child = RANGE_CLASS (range)->trough;
1134 else if (event->window == range->slider)
1136 range->in_child = RANGE_CLASS (range)->slider;
1138 if ((range->click_child == 0) ||
1139 (range->click_child == RANGE_CLASS (range)->trough))
1140 gtk_range_draw_slider (range);
1142 else if (event->window == range->step_forw)
1144 range->in_child = RANGE_CLASS (range)->step_forw;
1146 if ((range->click_child == 0) ||
1147 (range->click_child == RANGE_CLASS (range)->trough))
1148 gtk_range_draw_step_forw (range);
1150 else if (event->window == range->step_back)
1152 range->in_child = RANGE_CLASS (range)->step_back;
1154 if ((range->click_child == 0) ||
1155 (range->click_child == RANGE_CLASS (range)->trough))
1156 gtk_range_draw_step_back (range);
1163 gtk_range_leave_notify (GtkWidget *widget,
1164 GdkEventCrossing *event)
1168 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1169 g_return_val_if_fail (event != NULL, FALSE);
1171 range = GTK_RANGE (widget);
1173 range->in_child = 0;
1175 if (event->window == range->trough)
1178 else if (event->window == range->slider)
1180 if ((range->click_child == 0) ||
1181 (range->click_child == RANGE_CLASS (range)->trough))
1182 gtk_range_draw_slider (range);
1184 else if (event->window == range->step_forw)
1186 if ((range->click_child == 0) ||
1187 (range->click_child == RANGE_CLASS (range)->trough))
1188 gtk_range_draw_step_forw (range);
1190 else if (event->window == range->step_back)
1192 if ((range->click_child == 0) ||
1193 (range->click_child == RANGE_CLASS (range)->trough))
1194 gtk_range_draw_step_back (range);
1201 gtk_range_focus_in (GtkWidget *widget,
1202 GdkEventFocus *event)
1204 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1205 g_return_val_if_fail (event != NULL, FALSE);
1207 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1208 gtk_widget_draw_focus (widget);
1214 gtk_range_focus_out (GtkWidget *widget,
1215 GdkEventFocus *event)
1217 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1218 g_return_val_if_fail (event != NULL, FALSE);
1220 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1221 gtk_widget_draw_focus (widget);
1227 gtk_real_range_draw_trough (GtkRange *range)
1229 g_return_if_fail (GTK_IS_RANGE (range));
1233 gtk_paint_box (GTK_WIDGET (range)->style, range->trough,
1234 GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1235 NULL, GTK_WIDGET(range), "trough",
1237 if (GTK_WIDGET_HAS_FOCUS (range))
1238 gtk_paint_focus (GTK_WIDGET (range)->style,
1240 NULL, GTK_WIDGET(range), "trough",
1246 gtk_real_range_draw_slider (GtkRange *range)
1248 GtkStateType state_type;
1250 g_return_if_fail (GTK_IS_RANGE (range));
1254 if ((range->in_child == RANGE_CLASS (range)->slider) ||
1255 (range->click_child == RANGE_CLASS (range)->slider))
1256 state_type = GTK_STATE_PRELIGHT;
1258 state_type = GTK_STATE_NORMAL;
1259 gtk_paint_box (GTK_WIDGET (range)->style, range->slider,
1260 state_type, GTK_SHADOW_OUT,
1261 NULL, GTK_WIDGET (range), "slider",
1267 gtk_real_range_timer (GtkRange *range)
1271 GDK_THREADS_ENTER ();
1274 if (range->click_child == RANGE_CLASS (range)->slider)
1276 if (range->policy == GTK_UPDATE_DELAYED)
1277 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1282 GdkModifierType mods, mask;
1287 if (range->need_timer)
1288 range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
1289 (GtkFunction) RANGE_CLASS (range)->timer,
1293 GDK_THREADS_LEAVE ();
1296 range->need_timer = FALSE;
1299 switch (range->button)
1302 mask = GDK_BUTTON1_MASK;
1305 mask = GDK_BUTTON2_MASK;
1308 mask = GDK_BUTTON3_MASK;
1315 gdk_window_get_pointer (range->slider, NULL, NULL, &mods);
1318 return_val = gtk_range_scroll (range, -1);
1321 GDK_THREADS_LEAVE ();
1327 gtk_range_scroll (GtkRange *range,
1333 g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1335 new_value = range->adjustment->value;
1338 switch (range->scroll_type)
1340 case GTK_SCROLL_NONE:
1343 case GTK_SCROLL_JUMP:
1344 if (jump_perc >= 0 && jump_perc <= 1)
1346 new_value = (range->adjustment->lower +
1347 (range->adjustment->upper - range->adjustment->page_size -
1348 range->adjustment->lower) * jump_perc);
1352 case GTK_SCROLL_STEP_BACKWARD:
1353 new_value -= range->adjustment->step_increment;
1354 if (new_value <= range->adjustment->lower)
1356 new_value = range->adjustment->lower;
1362 case GTK_SCROLL_STEP_FORWARD:
1363 new_value += range->adjustment->step_increment;
1364 if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1366 new_value = range->adjustment->upper - range->adjustment->page_size;
1372 case GTK_SCROLL_PAGE_BACKWARD:
1373 new_value -= range->adjustment->page_increment;
1374 if (new_value <= range->adjustment->lower)
1376 new_value = range->adjustment->lower;
1382 case GTK_SCROLL_PAGE_FORWARD:
1383 new_value += range->adjustment->page_increment;
1384 if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1386 new_value = range->adjustment->upper - range->adjustment->page_size;
1393 if (new_value != range->adjustment->value)
1395 range->adjustment->value = new_value;
1397 if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
1398 (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
1400 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1404 gtk_range_slider_update (range);
1405 gtk_range_clear_background (range);
1414 gtk_range_add_timer (GtkRange *range)
1416 g_return_if_fail (GTK_IS_RANGE (range));
1420 range->need_timer = TRUE;
1421 range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
1422 (GtkFunction) RANGE_CLASS (range)->timer,
1428 gtk_range_remove_timer (GtkRange *range)
1430 g_return_if_fail (GTK_IS_RANGE (range));
1434 gtk_timeout_remove (range->timer);
1437 range->need_timer = FALSE;
1441 gtk_range_adjustment_changed (GtkAdjustment *adjustment,
1446 g_return_if_fail (adjustment != NULL);
1447 g_return_if_fail (data != NULL);
1449 range = GTK_RANGE (data);
1451 if (((range->old_lower != adjustment->lower) ||
1452 (range->old_upper != adjustment->upper) ||
1453 (range->old_page_size != adjustment->page_size)) &&
1454 (range->old_value == adjustment->value))
1456 if ((adjustment->lower == adjustment->upper) ||
1457 (range->old_lower == (range->old_upper - range->old_page_size)))
1459 adjustment->value = adjustment->lower;
1460 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
1464 if ((range->old_value != adjustment->value) ||
1465 (range->old_lower != adjustment->lower) ||
1466 (range->old_upper != adjustment->upper) ||
1467 (range->old_page_size != adjustment->page_size))
1469 gtk_range_slider_update (range);
1470 gtk_range_clear_background (range);
1472 range->old_value = adjustment->value;
1473 range->old_lower = adjustment->lower;
1474 range->old_upper = adjustment->upper;
1475 range->old_page_size = adjustment->page_size;
1480 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
1485 g_return_if_fail (adjustment != NULL);
1486 g_return_if_fail (data != NULL);
1488 range = GTK_RANGE (data);
1490 if (range->old_value != adjustment->value)
1492 gtk_range_slider_update (range);
1493 gtk_range_clear_background (range);
1495 range->old_value = adjustment->value;
1501 gtk_range_trough_hdims (GtkRange *range,
1511 g_return_if_fail (range != NULL);
1513 gdk_window_get_size (range->trough, &trough_width, NULL);
1514 gdk_window_get_size (range->slider, &slider_length, NULL);
1516 tleft = GTK_WIDGET (range)->style->xthickness;
1517 tright = trough_width - slider_length - GTK_WIDGET (range)->style->xthickness;
1519 if (range->step_back)
1521 gdk_window_get_size (range->step_back, &tmp_width, NULL);
1522 tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1525 if (range->step_forw)
1527 gdk_window_get_size (range->step_forw, &tmp_width, NULL);
1528 tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1538 gtk_range_trough_vdims (GtkRange *range,
1548 g_return_if_fail (range != NULL);
1550 gdk_window_get_size (range->trough, NULL, &trough_height);
1551 gdk_window_get_size (range->slider, NULL, &slider_length);
1553 ttop = GTK_WIDGET (range)->style->ythickness;
1554 tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->ythickness;
1556 if (range->step_back)
1558 gdk_window_get_size (range->step_back, NULL, &tmp_height);
1559 ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1562 if (range->step_forw)
1564 gdk_window_get_size (range->step_forw, NULL, &tmp_height);
1565 tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1575 gtk_range_style_set (GtkWidget *widget,
1576 GtkStyle *previous_style)
1580 g_return_if_fail (widget != NULL);
1581 g_return_if_fail (GTK_IS_RANGE (widget));
1583 range = GTK_RANGE (widget);
1585 if (GTK_WIDGET_REALIZED (widget))
1588 gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
1591 gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
1593 /* The backgrounds of the step_forw and step_back never actually
1594 * get drawn in draw calls, so we call gdk_window_clear() here
1595 * so they get the correct colors. This is a hack. OWT.
1598 if (range->step_forw)
1600 gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
1601 gdk_window_clear (range->step_forw);
1604 if (range->step_back)
1606 gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
1607 gdk_window_clear (range->step_back);