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 250 /* must hold button this long before ... */
34 #define SCROLL_LATER_DELAY 100 /* ... it starts repeating at this rate */
35 #define SCROLL_DELAY_LENGTH 300
37 #define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w)
44 static void gtk_range_class_init (GtkRangeClass *klass);
45 static void gtk_range_init (GtkRange *range);
46 static void gtk_range_set_arg (GtkObject *object,
49 static void gtk_range_get_arg (GtkObject *object,
52 static void gtk_range_destroy (GtkObject *object);
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_scroll_event (GtkWidget *widget,
69 GdkEventScroll *event);
70 static void gtk_range_style_set (GtkWidget *widget,
71 GtkStyle *previous_style);
73 static void gtk_real_range_draw_trough (GtkRange *range);
74 static void gtk_real_range_draw_slider (GtkRange *range);
75 static gint gtk_real_range_timer (GtkRange *range);
76 static gint gtk_range_scroll (GtkRange *range,
79 static void gtk_range_add_timer (GtkRange *range);
80 static void gtk_range_remove_timer (GtkRange *range);
82 static void gtk_range_adjustment_changed (GtkAdjustment *adjustment,
84 static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
87 static void gtk_range_trough_hdims (GtkRange *range,
90 static void gtk_range_trough_vdims (GtkRange *range,
94 static GtkWidgetClass *parent_class = NULL;
98 gtk_range_get_type (void)
100 static GtkType range_type = 0;
104 static const GtkTypeInfo range_info =
108 sizeof (GtkRangeClass),
109 (GtkClassInitFunc) gtk_range_class_init,
110 (GtkObjectInitFunc) gtk_range_init,
111 /* reserved_1 */ NULL,
112 /* reserved_2 */ NULL,
113 (GtkClassInitFunc) NULL,
116 range_type = gtk_type_unique (GTK_TYPE_WIDGET, &range_info);
123 gtk_range_class_init (GtkRangeClass *class)
125 GtkObjectClass *object_class;
126 GtkWidgetClass *widget_class;
128 object_class = (GtkObjectClass*) class;
129 widget_class = (GtkWidgetClass*) class;
131 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
133 object_class->set_arg = gtk_range_set_arg;
134 object_class->get_arg = gtk_range_get_arg;
135 object_class->destroy = gtk_range_destroy;
137 widget_class->unrealize = gtk_range_unrealize;
138 widget_class->expose_event = gtk_range_expose;
139 widget_class->button_press_event = gtk_range_button_press;
140 widget_class->button_release_event = gtk_range_button_release;
141 widget_class->motion_notify_event = gtk_range_motion_notify;
142 widget_class->scroll_event = gtk_range_scroll_event;
143 widget_class->key_press_event = gtk_range_key_press;
144 widget_class->enter_notify_event = gtk_range_enter_notify;
145 widget_class->leave_notify_event = gtk_range_leave_notify;
146 widget_class->style_set = gtk_range_style_set;
148 class->slider_width = 11;
149 class->stepper_size = 11;
150 class->stepper_slider_spacing = 1;
151 class->min_slider_size = 7;
154 class->step_forw = 3;
155 class->step_back = 4;
156 class->draw_background = NULL;
157 class->clear_background = NULL;
158 class->draw_trough = gtk_real_range_draw_trough;
159 class->draw_slider = gtk_real_range_draw_slider;
160 class->draw_step_forw = NULL;
161 class->draw_step_back = NULL;
162 class->trough_click = NULL;
163 class->trough_keys = NULL;
164 class->motion = NULL;
165 class->timer = gtk_real_range_timer;
167 gtk_object_add_arg_type ("GtkRange::update_policy",
168 GTK_TYPE_UPDATE_TYPE,
174 gtk_range_set_arg (GtkObject *object,
180 range = GTK_RANGE (object);
184 case ARG_UPDATE_POLICY:
185 gtk_range_set_update_policy (range, GTK_VALUE_ENUM (*arg));
193 gtk_range_get_arg (GtkObject *object,
199 range = GTK_RANGE (object);
203 case ARG_UPDATE_POLICY:
204 GTK_VALUE_ENUM (*arg) = range->policy;
207 arg->type = GTK_TYPE_INVALID;
213 gtk_range_init (GtkRange *range)
215 range->trough = NULL;
216 range->slider = NULL;
217 range->step_forw = NULL;
218 range->step_back = NULL;
220 range->x_click_point = 0;
221 range->y_click_point = 0;
224 range->policy = GTK_UPDATE_CONTINUOUS;
225 range->scroll_type = GTK_SCROLL_NONE;
227 range->click_child = 0;
228 range->need_timer = FALSE;
230 range->flippable = 0;
231 range->old_value = 0.0;
232 range->old_lower = 0.0;
233 range->old_upper = 0.0;
234 range->old_page_size = 0.0;
235 range->adjustment = NULL;
239 gtk_range_get_adjustment (GtkRange *range)
241 g_return_val_if_fail (range != NULL, NULL);
242 g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
244 if (!range->adjustment)
245 gtk_range_set_adjustment (range, NULL);
247 return range->adjustment;
251 gtk_range_set_update_policy (GtkRange *range,
252 GtkUpdateType policy)
254 g_return_if_fail (range != NULL);
255 g_return_if_fail (GTK_IS_RANGE (range));
257 range->policy = policy;
261 gtk_range_set_adjustment (GtkRange *range,
262 GtkAdjustment *adjustment)
264 g_return_if_fail (range != NULL);
265 g_return_if_fail (GTK_IS_RANGE (range));
268 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
270 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
272 if (range->adjustment != adjustment)
274 if (range->adjustment)
276 gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
278 gtk_object_unref (GTK_OBJECT (range->adjustment));
281 range->adjustment = adjustment;
282 gtk_object_ref (GTK_OBJECT (adjustment));
283 gtk_object_sink (GTK_OBJECT (adjustment));
285 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
286 (GtkSignalFunc) gtk_range_adjustment_changed,
288 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
289 (GtkSignalFunc) gtk_range_adjustment_value_changed,
292 range->old_value = adjustment->value;
293 range->old_lower = adjustment->lower;
294 range->old_upper = adjustment->upper;
295 range->old_page_size = adjustment->page_size;
297 gtk_range_adjustment_changed (adjustment, (gpointer) range);
302 gtk_range_set_inverted (GtkRange *range,
305 g_return_if_fail (GTK_IS_RANGE (range));
307 setting = setting != FALSE;
309 if (setting != range->inverted)
311 range->inverted = setting;
312 gtk_widget_queue_resize (GTK_WIDGET (range));
317 gtk_range_get_inverted (GtkRange *range)
319 g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
321 return range->inverted;
325 _gtk_range_draw_background (GtkRange *range)
327 g_return_if_fail (range != NULL);
328 g_return_if_fail (GTK_IS_RANGE (range));
330 if (range->trough && RANGE_CLASS (range)->draw_background)
331 (* RANGE_CLASS (range)->draw_background) (range);
335 _gtk_range_clear_background (GtkRange *range)
337 g_return_if_fail (range != NULL);
338 g_return_if_fail (GTK_IS_RANGE (range));
340 if (range->trough && RANGE_CLASS (range)->clear_background)
341 (* RANGE_CLASS (range)->clear_background) (range);
345 _gtk_range_draw_trough (GtkRange *range)
347 g_return_if_fail (range != NULL);
348 g_return_if_fail (GTK_IS_RANGE (range));
350 if (range->trough && RANGE_CLASS (range)->draw_trough)
351 (* RANGE_CLASS (range)->draw_trough) (range);
355 _gtk_range_draw_slider (GtkRange *range)
357 g_return_if_fail (range != NULL);
358 g_return_if_fail (GTK_IS_RANGE (range));
360 if (range->slider && RANGE_CLASS (range)->draw_slider)
361 (* RANGE_CLASS (range)->draw_slider) (range);
365 _gtk_range_draw_step_forw (GtkRange *range)
367 g_return_if_fail (range != NULL);
368 g_return_if_fail (GTK_IS_RANGE (range));
370 if (range->step_forw && RANGE_CLASS (range)->draw_step_forw)
371 (* RANGE_CLASS (range)->draw_step_forw) (range);
375 _gtk_range_draw_step_back (GtkRange *range)
377 g_return_if_fail (range != NULL);
378 g_return_if_fail (GTK_IS_RANGE (range));
380 if (range->step_back && RANGE_CLASS (range)->draw_step_back)
381 (* RANGE_CLASS (range)->draw_step_back) (range);
385 _gtk_range_slider_update (GtkRange *range)
387 g_return_if_fail (range != NULL);
388 g_return_if_fail (GTK_IS_RANGE (range));
390 if (RANGE_CLASS (range)->slider_update)
391 (* RANGE_CLASS (range)->slider_update) (range);
395 _gtk_range_trough_click (GtkRange *range,
400 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
401 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
403 if (RANGE_CLASS (range)->trough_click)
404 return (* RANGE_CLASS (range)->trough_click) (range, x, y, jump_perc);
406 return GTK_TROUGH_NONE;
410 get_window_region (GdkWindow *window)
414 gdk_window_get_position (window, &rect.x, &rect.y);
415 gdk_window_get_size (window, &rect.width, &rect.height);
417 return gdk_region_rectangle (&rect);
421 move_and_update_window (GdkWindow *window, gint x, gint y)
423 GdkRegion *old_region;
424 GdkRegion *new_region;
425 GdkWindow *parent = gdk_window_get_parent (window);
427 old_region = get_window_region (window);
428 gdk_window_move (window, x, y);
429 new_region = get_window_region (window);
431 gdk_region_subtract (old_region, new_region);
432 gdk_window_invalidate_region (parent, old_region, TRUE);
433 gdk_region_destroy (old_region);
434 gdk_region_destroy (new_region);
436 gdk_window_process_updates (parent, TRUE);
440 should_invert (GtkRange *range,
445 (range->inverted && !range->flippable) ||
446 (range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
447 (!range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
449 return range->inverted;
453 _gtk_range_default_hslider_update (GtkRange *range)
459 g_return_if_fail (range != NULL);
460 g_return_if_fail (GTK_IS_RANGE (range));
462 if (GTK_WIDGET_REALIZED (range))
464 gtk_range_trough_hdims (range, &left, &right);
467 if (range->adjustment->value < range->adjustment->lower)
469 range->adjustment->value = range->adjustment->lower;
470 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
472 else if (range->adjustment->value > range->adjustment->upper)
474 range->adjustment->value = range->adjustment->upper;
475 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
478 if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
479 x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
480 (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
487 if (should_invert (range, TRUE))
488 x = right - (x - left);
490 move_and_update_window (range->slider, x, GTK_WIDGET (range)->style->ythickness);
495 _gtk_range_default_vslider_update (GtkRange *range)
501 g_return_if_fail (range != NULL);
502 g_return_if_fail (GTK_IS_RANGE (range));
504 if (GTK_WIDGET_REALIZED (range))
506 gtk_range_trough_vdims (range, &top, &bottom);
509 if (range->adjustment->value < range->adjustment->lower)
511 range->adjustment->value = range->adjustment->lower;
512 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
514 else if (range->adjustment->value > range->adjustment->upper)
516 range->adjustment->value = range->adjustment->upper;
517 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
520 if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
521 y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
522 (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
529 if (should_invert (range, FALSE))
530 y = bottom - (y - top);
532 move_and_update_window (range->slider, GTK_WIDGET (range)->style->xthickness, y);
537 _gtk_range_default_htrough_click (GtkRange *range,
549 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
550 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
552 ythickness = GTK_WIDGET (range)->style->ythickness;
554 gtk_range_trough_hdims (range, &left, &right);
555 gdk_window_get_size (range->slider, &slider_length, NULL);
556 right += slider_length;
558 if (should_invert (range, TRUE))
559 x = (right - x) + left;
561 if ((x > left) && (y > ythickness))
563 gdk_window_get_size (range->trough, &trough_width, &trough_height);
565 if ((x < right) && (y < (trough_height - ythickness)))
569 *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left));
570 return GTK_TROUGH_JUMP;
573 gdk_window_get_position (range->slider, &slider_x, NULL);
576 return GTK_TROUGH_START;
578 return GTK_TROUGH_END;
582 return GTK_TROUGH_NONE;
586 _gtk_range_default_vtrough_click (GtkRange *range,
598 g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
599 g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
601 xthickness = GTK_WIDGET (range)->style->xthickness;
603 gtk_range_trough_vdims (range, &top, &bottom);
604 gdk_window_get_size (range->slider, NULL, &slider_length);
605 bottom += slider_length;
607 if (should_invert (range, FALSE))
608 y = (bottom - y) + top;
610 if ((x > xthickness) && (y > top))
612 gdk_window_get_size (range->trough, &trough_width, &trough_height);
614 if ((x < (trough_width - xthickness) && (y < bottom)))
618 *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top));
620 return GTK_TROUGH_JUMP;
623 gdk_window_get_position (range->slider, NULL, &slider_y);
626 return GTK_TROUGH_START;
628 return GTK_TROUGH_END;
632 return GTK_TROUGH_NONE;
636 _gtk_range_default_hmotion (GtkRange *range,
642 gint slider_x, slider_y;
645 g_return_if_fail (GTK_IS_RANGE (range));
646 g_return_if_fail (GTK_WIDGET_REALIZED (range));
648 gdk_window_get_position (range->slider, &slider_x, &slider_y);
649 gtk_range_trough_hdims (range, &left, &right);
654 new_pos = slider_x + xdelta;
656 if (should_invert (range, TRUE))
657 new_pos = (right - new_pos) + left;
661 else if (new_pos > right)
664 old_value = range->adjustment->value;
665 range->adjustment->value = ((range->adjustment->upper -
666 range->adjustment->lower -
667 range->adjustment->page_size) *
668 (new_pos - left) / (right - left) +
669 range->adjustment->lower);
671 if (range->digits >= 0)
675 sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
676 sscanf (buffer, "%f", &range->adjustment->value);
679 if (old_value != range->adjustment->value)
681 if (range->policy == GTK_UPDATE_CONTINUOUS)
683 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
687 _gtk_range_slider_update (range);
688 _gtk_range_clear_background (range);
690 if (range->policy == GTK_UPDATE_DELAYED)
692 gtk_range_remove_timer (range);
693 range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
694 (GtkFunction) RANGE_CLASS (range)->timer,
702 _gtk_range_default_vmotion (GtkRange *range,
708 gint slider_x, slider_y;
711 g_return_if_fail (GTK_IS_RANGE (range));
712 g_return_if_fail (GTK_WIDGET_REALIZED (range));
714 range = GTK_RANGE (range);
716 gdk_window_get_position (range->slider, &slider_x, &slider_y);
717 gtk_range_trough_vdims (range, &top, &bottom);
722 new_pos = slider_y + ydelta;
724 if (should_invert (range, FALSE))
725 new_pos = (bottom - new_pos) + top;
729 else if (new_pos > bottom)
732 old_value = range->adjustment->value;
733 range->adjustment->value = ((range->adjustment->upper -
734 range->adjustment->lower -
735 range->adjustment->page_size) *
736 (new_pos - top) / (bottom - top) +
737 range->adjustment->lower);
739 if (range->digits >= 0)
743 sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
744 sscanf (buffer, "%f", &range->adjustment->value);
747 if (old_value != range->adjustment->value)
749 if (range->policy == GTK_UPDATE_CONTINUOUS)
751 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
755 _gtk_range_slider_update (range);
756 _gtk_range_clear_background (range);
758 if (range->policy == GTK_UPDATE_DELAYED)
760 gtk_range_remove_timer (range);
761 range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
762 (GtkFunction) RANGE_CLASS (range)->timer,
771 gtk_range_destroy (GtkObject *object)
775 g_return_if_fail (object != NULL);
776 g_return_if_fail (GTK_IS_RANGE (object));
778 range = GTK_RANGE (object);
780 gtk_range_remove_timer (range);
781 if (range->adjustment)
783 if (range->adjustment)
784 gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
786 gtk_object_unref (GTK_OBJECT (range->adjustment));
787 range->adjustment = NULL;
790 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
794 gtk_range_unrealize (GtkWidget *widget)
798 g_return_if_fail (widget != NULL);
799 g_return_if_fail (GTK_IS_RANGE (widget));
801 range = GTK_RANGE (widget);
805 gdk_window_set_user_data (range->slider, NULL);
806 gdk_window_destroy (range->slider);
807 range->slider = NULL;
811 gdk_window_set_user_data (range->trough, NULL);
812 gdk_window_destroy (range->trough);
813 range->trough = NULL;
815 if (range->step_forw)
817 gdk_window_set_user_data (range->step_forw, NULL);
818 gdk_window_destroy (range->step_forw);
819 range->step_forw = NULL;
821 if (range->step_back)
823 gdk_window_set_user_data (range->step_back, NULL);
824 gdk_window_destroy (range->step_back);
825 range->step_back = NULL;
828 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
829 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
833 gtk_range_expose (GtkWidget *widget,
834 GdkEventExpose *event)
838 g_return_val_if_fail (widget != NULL, FALSE);
839 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
840 g_return_val_if_fail (event != NULL, FALSE);
842 range = GTK_RANGE (widget);
844 /* We should really pass another argument -
845 *the redrawn area - to all the drawing functions)
847 if (event->window == range->trough)
849 _gtk_range_draw_trough (range);
851 else if (event->window == widget->window)
853 _gtk_range_draw_background (range);
855 else if (event->window == range->slider)
857 _gtk_range_draw_slider (range);
859 else if (event->window == range->step_forw)
861 _gtk_range_draw_step_forw (range);
863 else if (event->window == range->step_back)
865 _gtk_range_draw_step_back (range);
871 gtk_range_button_press (GtkWidget *widget,
872 GdkEventButton *event)
878 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
879 g_return_val_if_fail (event != NULL, FALSE);
881 if (!GTK_WIDGET_HAS_FOCUS (widget))
882 gtk_widget_grab_focus (widget);
885 range = GTK_RANGE (widget);
886 if (range->button == 0)
888 gtk_grab_add (widget);
890 range->button = event->button;
891 range->x_click_point = event->x;
892 range->y_click_point = event->y;
894 if (event->window == range->trough)
896 range->click_child = RANGE_CLASS (range)->trough;
898 if (range->button == 2)
899 trough_part = _gtk_range_trough_click (range, event->x, event->y, &jump_perc);
901 trough_part = _gtk_range_trough_click (range, event->x, event->y, NULL);
903 range->scroll_type = GTK_SCROLL_NONE;
904 if (trough_part == GTK_TROUGH_START)
905 range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
906 else if (trough_part == GTK_TROUGH_END)
907 range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
908 else if (trough_part == GTK_TROUGH_JUMP &&
909 jump_perc >= 0 && jump_perc <= 1)
910 range->scroll_type = GTK_SCROLL_JUMP;
912 if (range->scroll_type != GTK_SCROLL_NONE)
914 gtk_range_scroll (range, jump_perc);
915 gtk_range_add_timer (range);
918 else if (event->window == range->slider)
920 range->click_child = RANGE_CLASS (range)->slider;
921 range->scroll_type = GTK_SCROLL_NONE;
923 else if (event->window == range->step_forw ||
924 event->window == range->step_back)
926 gboolean back = (event->window == range->step_back);
928 if (range->button == 3)
930 range->scroll_type = GTK_SCROLL_JUMP;
931 gtk_range_scroll (range, back ? 0.0 : 1.0);
936 back ? RANGE_CLASS (range)->step_back
937 : RANGE_CLASS (range)->step_forw;
939 if (range->button == 2)
941 back ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD;
944 back ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD;
946 gtk_range_scroll (range, -1);
947 gtk_range_add_timer (range);
950 _gtk_range_draw_step_back (range);
952 _gtk_range_draw_step_forw (range);
961 gtk_range_button_release (GtkWidget *widget,
962 GdkEventButton *event)
966 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
967 g_return_val_if_fail (event != NULL, FALSE);
969 range = GTK_RANGE (widget);
971 if (range->button == event->button)
973 gtk_grab_remove (widget);
976 range->x_click_point = -1;
977 range->y_click_point = -1;
979 if (range->click_child == RANGE_CLASS (range)->slider)
981 if (range->policy == GTK_UPDATE_DELAYED)
982 gtk_range_remove_timer (range);
984 if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
985 (range->old_value != range->adjustment->value))
986 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
988 else if ((range->click_child == RANGE_CLASS (range)->trough) ||
989 (range->click_child == RANGE_CLASS (range)->step_forw) ||
990 (range->click_child == RANGE_CLASS (range)->step_back))
992 gtk_range_remove_timer (range);
994 if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
995 (range->old_value != range->adjustment->value))
996 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
998 if (range->click_child == RANGE_CLASS (range)->step_forw)
1000 range->click_child = 0;
1001 _gtk_range_draw_step_forw (range);
1003 else if (range->click_child == RANGE_CLASS (range)->step_back)
1005 range->click_child = 0;
1006 _gtk_range_draw_step_back (range);
1010 range->click_child = 0;
1017 gtk_range_scroll_event (GtkWidget *widget,
1018 GdkEventScroll *event)
1022 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1023 g_return_val_if_fail (event != NULL, FALSE);
1025 range = GTK_RANGE (widget);
1027 if (GTK_WIDGET_REALIZED (range))
1029 GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1030 gfloat new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ?
1031 -adj->page_increment / 2:
1032 adj->page_increment / 2);
1033 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
1034 gtk_adjustment_set_value (adj, new_value);
1041 gtk_range_motion_notify (GtkWidget *widget,
1042 GdkEventMotion *event)
1046 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1047 g_return_val_if_fail (event != NULL, FALSE);
1049 range = GTK_RANGE (widget);
1051 if (range->click_child == RANGE_CLASS (range)->slider)
1053 GdkModifierType mods;
1054 gint x, y, mask, x2, y2;
1056 gdk_window_get_pointer (range->trough, &x, &y, &mods);
1057 gdk_window_get_position (range->slider, &x2, &y2);
1062 switch (range->button)
1065 mask = GDK_BUTTON1_MASK;
1068 mask = GDK_BUTTON2_MASK;
1071 mask = GDK_BUTTON3_MASK;
1080 if (RANGE_CLASS (range)->motion)
1081 (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
1089 gtk_range_key_press (GtkWidget *widget,
1094 GtkScrollType scroll = GTK_SCROLL_NONE;
1095 GtkTroughType pos = GTK_TROUGH_NONE;
1097 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1098 g_return_val_if_fail (event != NULL, FALSE);
1100 range = GTK_RANGE (widget);
1103 if (RANGE_CLASS (range)->trough_keys)
1104 return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos);
1108 if (scroll != GTK_SCROLL_NONE)
1110 range->scroll_type = scroll;
1112 gtk_range_scroll (range, -1);
1113 if (range->old_value != range->adjustment->value)
1115 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1116 switch (range->scroll_type)
1118 case GTK_SCROLL_STEP_LEFT:
1119 if (should_invert (range, TRUE))
1120 _gtk_range_draw_step_forw (range);
1122 _gtk_range_draw_step_back (range);
1125 case GTK_SCROLL_STEP_UP:
1126 if (should_invert (range, FALSE))
1127 _gtk_range_draw_step_forw (range);
1129 _gtk_range_draw_step_back (range);
1132 case GTK_SCROLL_STEP_RIGHT:
1133 if (should_invert (range, TRUE))
1134 _gtk_range_draw_step_back (range);
1136 _gtk_range_draw_step_forw (range);
1139 case GTK_SCROLL_STEP_DOWN:
1140 if (should_invert (range, FALSE))
1141 _gtk_range_draw_step_back (range);
1143 _gtk_range_draw_step_forw (range);
1146 case GTK_SCROLL_STEP_BACKWARD:
1147 _gtk_range_draw_step_back (range);
1150 case GTK_SCROLL_STEP_FORWARD:
1151 _gtk_range_draw_step_forw (range);
1156 if (pos != GTK_TROUGH_NONE)
1158 if (pos == GTK_TROUGH_START)
1159 range->adjustment->value = range->adjustment->lower;
1160 else if (pos == GTK_TROUGH_END)
1161 range->adjustment->value =
1162 range->adjustment->upper - range->adjustment->page_size;
1164 if (range->old_value != range->adjustment->value)
1166 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
1169 _gtk_range_slider_update (range);
1170 _gtk_range_clear_background (range);
1178 gtk_range_enter_notify (GtkWidget *widget,
1179 GdkEventCrossing *event)
1183 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1184 g_return_val_if_fail (event != NULL, FALSE);
1186 range = GTK_RANGE (widget);
1188 if (event->window == range->trough)
1190 range->in_child = RANGE_CLASS (range)->trough;
1192 else if (event->window == range->slider)
1194 range->in_child = RANGE_CLASS (range)->slider;
1196 if ((range->click_child == 0) ||
1197 (range->click_child == RANGE_CLASS (range)->trough))
1198 _gtk_range_draw_slider (range);
1200 else if (event->window == range->step_forw)
1202 range->in_child = RANGE_CLASS (range)->step_forw;
1204 if ((range->click_child == 0) ||
1205 (range->click_child == RANGE_CLASS (range)->trough))
1206 _gtk_range_draw_step_forw (range);
1208 else if (event->window == range->step_back)
1210 range->in_child = RANGE_CLASS (range)->step_back;
1212 if ((range->click_child == 0) ||
1213 (range->click_child == RANGE_CLASS (range)->trough))
1214 _gtk_range_draw_step_back (range);
1221 gtk_range_leave_notify (GtkWidget *widget,
1222 GdkEventCrossing *event)
1226 g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1227 g_return_val_if_fail (event != NULL, FALSE);
1229 range = GTK_RANGE (widget);
1231 range->in_child = 0;
1233 if (event->window == range->trough)
1236 else if (event->window == range->slider)
1238 if ((range->click_child == 0) ||
1239 (range->click_child == RANGE_CLASS (range)->trough))
1240 _gtk_range_draw_slider (range);
1242 else if (event->window == range->step_forw)
1244 if ((range->click_child == 0) ||
1245 (range->click_child == RANGE_CLASS (range)->trough))
1246 _gtk_range_draw_step_forw (range);
1248 else if (event->window == range->step_back)
1250 if ((range->click_child == 0) ||
1251 (range->click_child == RANGE_CLASS (range)->trough))
1252 _gtk_range_draw_step_back (range);
1259 gtk_real_range_draw_trough (GtkRange *range)
1261 g_return_if_fail (GTK_IS_RANGE (range));
1265 gtk_paint_box (GTK_WIDGET (range)->style, range->trough,
1266 GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1267 NULL, GTK_WIDGET(range), "trough",
1269 if (GTK_WIDGET_HAS_FOCUS (range))
1270 gtk_paint_focus (GTK_WIDGET (range)->style,
1272 NULL, GTK_WIDGET(range), "trough",
1278 gtk_real_range_draw_slider (GtkRange *range)
1280 GtkStateType state_type;
1282 g_return_if_fail (GTK_IS_RANGE (range));
1286 if ((range->in_child == RANGE_CLASS (range)->slider) ||
1287 (range->click_child == RANGE_CLASS (range)->slider))
1288 state_type = GTK_STATE_PRELIGHT;
1290 state_type = GTK_STATE_NORMAL;
1291 gtk_paint_box (GTK_WIDGET (range)->style, range->slider,
1292 state_type, GTK_SHADOW_OUT,
1293 NULL, GTK_WIDGET (range), "slider",
1299 gtk_real_range_timer (GtkRange *range)
1303 GDK_THREADS_ENTER ();
1306 if (range->click_child == RANGE_CLASS (range)->slider)
1308 if (range->policy == GTK_UPDATE_DELAYED)
1309 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1314 GdkModifierType mods, mask;
1319 if (range->need_timer)
1320 range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
1321 (GtkFunction) RANGE_CLASS (range)->timer,
1325 GDK_THREADS_LEAVE ();
1328 range->need_timer = FALSE;
1331 switch (range->button)
1334 mask = GDK_BUTTON1_MASK;
1337 mask = GDK_BUTTON2_MASK;
1340 mask = GDK_BUTTON3_MASK;
1347 gdk_window_get_pointer (range->slider, NULL, NULL, &mods);
1350 return_val = gtk_range_scroll (range, -1);
1353 GDK_THREADS_LEAVE ();
1359 gtk_range_scroll (GtkRange *range,
1364 GtkScrollType scroll_type;
1366 g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1368 new_value = range->adjustment->value;
1371 /* Translate visual to logical */
1373 scroll_type = range->scroll_type;
1374 switch (scroll_type)
1376 case GTK_SCROLL_STEP_UP:
1377 if (should_invert (range, FALSE))
1378 scroll_type = GTK_SCROLL_STEP_FORWARD;
1380 scroll_type = GTK_SCROLL_STEP_BACKWARD;
1383 case GTK_SCROLL_STEP_DOWN:
1384 if (should_invert (range, FALSE))
1385 scroll_type = GTK_SCROLL_STEP_BACKWARD;
1387 scroll_type = GTK_SCROLL_STEP_FORWARD;
1390 case GTK_SCROLL_PAGE_UP:
1391 if (should_invert (range, FALSE))
1392 scroll_type = GTK_SCROLL_PAGE_FORWARD;
1394 scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1397 case GTK_SCROLL_PAGE_DOWN:
1398 if (should_invert (range, FALSE))
1399 scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1401 scroll_type = GTK_SCROLL_PAGE_FORWARD;
1404 case GTK_SCROLL_STEP_LEFT:
1405 if (should_invert (range, TRUE))
1406 scroll_type = GTK_SCROLL_STEP_FORWARD;
1408 scroll_type = GTK_SCROLL_STEP_BACKWARD;
1411 case GTK_SCROLL_STEP_RIGHT:
1412 if (should_invert (range, TRUE))
1413 scroll_type = GTK_SCROLL_STEP_BACKWARD;
1415 scroll_type = GTK_SCROLL_STEP_FORWARD;
1418 case GTK_SCROLL_PAGE_LEFT:
1419 if (should_invert (range, TRUE))
1420 scroll_type = GTK_SCROLL_PAGE_FORWARD;
1422 scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1425 case GTK_SCROLL_PAGE_RIGHT:
1426 if (should_invert (range, TRUE))
1427 scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1429 scroll_type = GTK_SCROLL_PAGE_FORWARD;
1436 switch (scroll_type)
1438 case GTK_SCROLL_NONE:
1441 case GTK_SCROLL_JUMP:
1442 if (jump_perc >= 0 && jump_perc <= 1)
1444 new_value = (range->adjustment->lower +
1445 (range->adjustment->upper - range->adjustment->page_size -
1446 range->adjustment->lower) * jump_perc);
1450 case GTK_SCROLL_STEP_BACKWARD:
1451 new_value -= range->adjustment->step_increment;
1452 if (new_value <= range->adjustment->lower)
1454 new_value = range->adjustment->lower;
1460 case GTK_SCROLL_STEP_FORWARD:
1461 new_value += range->adjustment->step_increment;
1462 if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1464 new_value = range->adjustment->upper - range->adjustment->page_size;
1470 case GTK_SCROLL_PAGE_BACKWARD:
1471 new_value -= range->adjustment->page_increment;
1472 if (new_value <= range->adjustment->lower)
1474 new_value = range->adjustment->lower;
1480 case GTK_SCROLL_PAGE_FORWARD:
1481 new_value += range->adjustment->page_increment;
1482 if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1484 new_value = range->adjustment->upper - range->adjustment->page_size;
1490 case GTK_SCROLL_STEP_UP:
1491 case GTK_SCROLL_STEP_DOWN:
1492 case GTK_SCROLL_PAGE_UP:
1493 case GTK_SCROLL_PAGE_DOWN:
1494 case GTK_SCROLL_STEP_LEFT:
1495 case GTK_SCROLL_STEP_RIGHT:
1496 case GTK_SCROLL_PAGE_LEFT:
1497 case GTK_SCROLL_PAGE_RIGHT:
1498 g_assert_not_reached ();
1503 if (new_value != range->adjustment->value)
1505 range->adjustment->value = new_value;
1507 if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
1508 (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
1510 gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1514 _gtk_range_slider_update (range);
1515 _gtk_range_clear_background (range);
1524 gtk_range_timer_1st_time (GtkRange *range)
1527 * If the real timeout function succeeds and the timeout is still set,
1528 * replace it with a quicker one so successive scrolling goes faster.
1530 gtk_object_ref (GTK_OBJECT (range));
1532 if (RANGE_CLASS (range)->timer (range))
1536 /* We explicitely remove ourselves here in the paranoia
1537 * that due to things happening above in the callback
1538 * above, we might have been removed, and another added.
1540 g_source_remove (range->timer);
1541 range->timer = gtk_timeout_add (SCROLL_LATER_DELAY,
1542 (GtkFunction) RANGE_CLASS (range)->timer,
1547 gtk_object_unref (GTK_OBJECT (range));
1549 return FALSE; /* don't keep calling this function */
1553 gtk_range_add_timer (GtkRange *range)
1555 g_return_if_fail (GTK_IS_RANGE (range));
1559 range->need_timer = TRUE;
1560 range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
1561 (GtkFunction) gtk_range_timer_1st_time,
1567 gtk_range_remove_timer (GtkRange *range)
1569 g_return_if_fail (GTK_IS_RANGE (range));
1573 gtk_timeout_remove (range->timer);
1576 range->need_timer = FALSE;
1580 gtk_range_adjustment_changed (GtkAdjustment *adjustment,
1585 g_return_if_fail (adjustment != NULL);
1586 g_return_if_fail (data != NULL);
1588 range = GTK_RANGE (data);
1590 if (((range->old_lower != adjustment->lower) ||
1591 (range->old_upper != adjustment->upper) ||
1592 (range->old_page_size != adjustment->page_size)) &&
1593 (range->old_value == adjustment->value))
1595 if ((adjustment->lower == adjustment->upper) ||
1596 (range->old_lower == (range->old_upper - range->old_page_size)))
1598 adjustment->value = adjustment->lower;
1599 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
1603 if ((range->old_value != adjustment->value) ||
1604 (range->old_lower != adjustment->lower) ||
1605 (range->old_upper != adjustment->upper) ||
1606 (range->old_page_size != adjustment->page_size))
1608 _gtk_range_slider_update (range);
1609 _gtk_range_clear_background (range);
1611 range->old_value = adjustment->value;
1612 range->old_lower = adjustment->lower;
1613 range->old_upper = adjustment->upper;
1614 range->old_page_size = adjustment->page_size;
1619 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
1624 g_return_if_fail (adjustment != NULL);
1625 g_return_if_fail (data != NULL);
1627 range = GTK_RANGE (data);
1629 if (range->old_value != adjustment->value)
1631 _gtk_range_slider_update (range);
1632 _gtk_range_clear_background (range);
1634 range->old_value = adjustment->value;
1640 gtk_range_trough_hdims (GtkRange *range,
1650 g_return_if_fail (range != NULL);
1652 gdk_window_get_size (range->trough, &trough_width, NULL);
1653 gdk_window_get_size (range->slider, &slider_length, NULL);
1655 tleft = GTK_WIDGET (range)->style->xthickness;
1656 tright = trough_width - slider_length - GTK_WIDGET (range)->style->xthickness;
1658 if (range->step_back)
1660 gdk_window_get_size (range->step_back, &tmp_width, NULL);
1661 tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1664 if (range->step_forw)
1666 gdk_window_get_size (range->step_forw, &tmp_width, NULL);
1667 tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1677 gtk_range_trough_vdims (GtkRange *range,
1687 g_return_if_fail (range != NULL);
1689 gdk_window_get_size (range->trough, NULL, &trough_height);
1690 gdk_window_get_size (range->slider, NULL, &slider_length);
1692 ttop = GTK_WIDGET (range)->style->ythickness;
1693 tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->ythickness;
1695 if (range->step_back)
1697 gdk_window_get_size (range->step_back, NULL, &tmp_height);
1698 ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1701 if (range->step_forw)
1703 gdk_window_get_size (range->step_forw, NULL, &tmp_height);
1704 tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1714 gtk_range_style_set (GtkWidget *widget,
1715 GtkStyle *previous_style)
1719 g_return_if_fail (widget != NULL);
1720 g_return_if_fail (GTK_IS_RANGE (widget));
1722 range = GTK_RANGE (widget);
1724 if (GTK_WIDGET_REALIZED (widget))
1727 gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
1730 gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
1732 /* The backgrounds of the step_forw and step_back never actually
1733 * get drawn in draw calls, so we call gdk_window_clear() here
1734 * so they get the correct colors. This is a hack. OWT.
1737 if (range->step_forw)
1739 gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
1740 gdk_window_clear (range->step_forw);
1743 if (range->step_back)
1745 gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
1746 gdk_window_clear (range->step_back);