/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "gtkmain.h" #include "gtkrange.h" #include "gtksignal.h" #define SCROLL_TIMER_LENGTH 20 #define SCROLL_INITIAL_DELAY 100 #define SCROLL_DELAY_LENGTH 300 #define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) static void gtk_range_class_init (GtkRangeClass *klass); static void gtk_range_init (GtkRange *range); static void gtk_range_destroy (GtkObject *object); static void gtk_range_draw (GtkWidget *widget, GdkRectangle *area); static void gtk_range_draw_focus (GtkWidget *widget); static void gtk_range_unrealize (GtkWidget *widget); static gint gtk_range_expose (GtkWidget *widget, GdkEventExpose *event); static gint gtk_range_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_range_button_release (GtkWidget *widget, GdkEventButton *event); static gint gtk_range_motion_notify (GtkWidget *widget, GdkEventMotion *event); static gint gtk_range_key_press (GtkWidget *widget, GdkEventKey *event); static gint gtk_range_enter_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_range_leave_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_range_focus_in (GtkWidget *widget, GdkEventFocus *event); static gint gtk_range_focus_out (GtkWidget *widget, GdkEventFocus *event); static void gtk_real_range_draw_trough (GtkRange *range); static void gtk_real_range_draw_slider (GtkRange *range); static gint gtk_real_range_timer (GtkRange *range); static gint gtk_range_scroll (GtkRange *range); static void gtk_range_add_timer (GtkRange *range); static void gtk_range_remove_timer (GtkRange *range); static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, gpointer data); static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data); static void gtk_range_trough_hdims (GtkRange *range, gint *left, gint *right); static void gtk_range_trough_vdims (GtkRange *range, gint *top, gint *bottom); static GtkWidgetClass *parent_class = NULL; guint gtk_range_get_type () { static guint range_type = 0; if (!range_type) { GtkTypeInfo range_info = { "GtkRange", sizeof (GtkRange), sizeof (GtkRangeClass), (GtkClassInitFunc) gtk_range_class_init, (GtkObjectInitFunc) gtk_range_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; range_type = gtk_type_unique (gtk_widget_get_type (), &range_info); } return range_type; } static void gtk_range_class_init (GtkRangeClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; parent_class = gtk_type_class (gtk_widget_get_type ()); object_class->destroy = gtk_range_destroy; widget_class->draw = gtk_range_draw; widget_class->draw_focus = gtk_range_draw_focus; widget_class->unrealize = gtk_range_unrealize; widget_class->expose_event = gtk_range_expose; widget_class->button_press_event = gtk_range_button_press; widget_class->button_release_event = gtk_range_button_release; widget_class->motion_notify_event = gtk_range_motion_notify; widget_class->key_press_event = gtk_range_key_press; widget_class->enter_notify_event = gtk_range_enter_notify; widget_class->leave_notify_event = gtk_range_leave_notify; widget_class->focus_in_event = gtk_range_focus_in; widget_class->focus_out_event = gtk_range_focus_out; class->slider_width = 11; class->stepper_size = 11; class->stepper_slider_spacing = 1; class->min_slider_size = 7; class->trough = 1; class->slider = 2; class->step_forw = 3; class->step_back = 4; class->draw_background = NULL; class->draw_trough = gtk_real_range_draw_trough; class->draw_slider = gtk_real_range_draw_slider; class->draw_step_forw = NULL; class->draw_step_back = NULL; class->trough_click = NULL; class->trough_keys = NULL; class->motion = NULL; class->timer = gtk_real_range_timer; } static void gtk_range_init (GtkRange *range) { range->trough = NULL; range->slider = NULL; range->step_forw = NULL; range->step_back = NULL; range->x_click_point = 0; range->y_click_point = 0; range->button = 0; range->digits = -1; range->policy = GTK_UPDATE_CONTINUOUS; range->scroll_type = GTK_SCROLL_NONE; range->in_child = 0; range->click_child = 0; range->need_timer = FALSE; range->timer = 0; range->old_value = 0.0; range->old_lower = 0.0; range->old_upper = 0.0; range->old_page_size = 0.0; range->adjustment = NULL; } GtkAdjustment* gtk_range_get_adjustment (GtkRange *range) { g_return_val_if_fail (range != NULL, NULL); g_return_val_if_fail (GTK_IS_RANGE (range), NULL); return range->adjustment; } void gtk_range_set_update_policy (GtkRange *range, GtkUpdateType policy) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); range->policy = policy; } void gtk_range_set_adjustment (GtkRange *range, GtkAdjustment *adjustment) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->adjustment != adjustment) { if (range->adjustment) { gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), (gpointer) range); gtk_object_unref (GTK_OBJECT (range->adjustment)); } range->adjustment = adjustment; if (adjustment) { gtk_object_ref (GTK_OBJECT (adjustment)); gtk_signal_connect (GTK_OBJECT (adjustment), "changed", (GtkSignalFunc) gtk_range_adjustment_changed, (gpointer) range); gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", (GtkSignalFunc) gtk_range_adjustment_value_changed, (gpointer) range); range->old_value = adjustment->value; range->old_lower = adjustment->lower; range->old_upper = adjustment->upper; range->old_page_size = adjustment->page_size; gtk_range_adjustment_changed (adjustment, (gpointer) range); } } } void gtk_range_draw_background (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->trough && RANGE_CLASS (range)->draw_background) (* RANGE_CLASS (range)->draw_background) (range); } void gtk_range_draw_trough (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->trough && RANGE_CLASS (range)->draw_trough) (* RANGE_CLASS (range)->draw_trough) (range); } void gtk_range_draw_slider (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->slider && RANGE_CLASS (range)->draw_slider) (* RANGE_CLASS (range)->draw_slider) (range); } void gtk_range_draw_step_forw (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->step_forw && RANGE_CLASS (range)->draw_step_forw) (* RANGE_CLASS (range)->draw_step_forw) (range); } void gtk_range_draw_step_back (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->step_back && RANGE_CLASS (range)->draw_step_back) (* RANGE_CLASS (range)->draw_step_back) (range); } void gtk_range_slider_update (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (RANGE_CLASS (range)->slider_update) (* RANGE_CLASS (range)->slider_update) (range); } gint gtk_range_trough_click (GtkRange *range, gint x, gint y) { g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); if (RANGE_CLASS (range)->trough_click) return (* RANGE_CLASS (range)->trough_click) (range, x, y); return GTK_TROUGH_NONE; } void gtk_range_default_hslider_update (GtkRange *range) { gint left; gint right; gint x; g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (GTK_WIDGET_REALIZED (range)) { gtk_range_trough_hdims (range, &left, &right); x = left; if (range->adjustment->value < range->adjustment->lower) { range->adjustment->value = range->adjustment->lower; gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else if (range->adjustment->value > range->adjustment->upper) { range->adjustment->value = range->adjustment->upper; gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) x += ((right - left) * (range->adjustment->value - range->adjustment->lower) / (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); if (x < left) x = left; else if (x > right) x = right; gdk_window_move (range->slider, x, GTK_WIDGET (range)->style->klass->ythickness); } } void gtk_range_default_vslider_update (GtkRange *range) { gint top; gint bottom; gint y; g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (GTK_WIDGET_REALIZED (range)) { gtk_range_trough_vdims (range, &top, &bottom); y = top; if (range->adjustment->value < range->adjustment->lower) { range->adjustment->value = range->adjustment->lower; gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else if (range->adjustment->value > range->adjustment->upper) { range->adjustment->value = range->adjustment->upper; gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) / (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); if (y < top) y = top; else if (y > bottom) y = bottom; gdk_window_move (range->slider, GTK_WIDGET (range)->style->klass->ythickness, y); } } gint gtk_range_default_htrough_click (GtkRange *range, gint x, gint y) { gint xthickness; gint ythickness; gint trough_width; gint trough_height; gint slider_x; g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); xthickness = GTK_WIDGET (range)->style->klass->xthickness; ythickness = GTK_WIDGET (range)->style->klass->ythickness; if ((x > xthickness) && (y > ythickness)) { gdk_window_get_size (range->trough, &trough_width, &trough_height); if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) { gdk_window_get_position (range->slider, &slider_x, NULL); if (x < slider_x) return GTK_TROUGH_START; else return GTK_TROUGH_END; } } return GTK_TROUGH_NONE; } gint gtk_range_default_vtrough_click (GtkRange *range, gint x, gint y) { gint xthickness; gint ythickness; gint trough_width; gint trough_height; gint slider_y; g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); xthickness = GTK_WIDGET (range)->style->klass->xthickness; ythickness = GTK_WIDGET (range)->style->klass->ythickness; if ((x > xthickness) && (y > ythickness)) { gdk_window_get_size (range->trough, &trough_width, &trough_height); if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) { gdk_window_get_position (range->slider, NULL, &slider_y); if (y < slider_y) return GTK_TROUGH_START; else return GTK_TROUGH_END; } } return GTK_TROUGH_NONE; } void gtk_range_default_hmotion (GtkRange *range, gint xdelta, gint ydelta) { gdouble old_value; gint left, right; gint slider_x, slider_y; gint new_pos; g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); range = GTK_RANGE (range); gdk_window_get_position (range->slider, &slider_x, &slider_y); gtk_range_trough_hdims (range, &left, &right); if (left == right) return; new_pos = slider_x + xdelta; if (new_pos < left) new_pos = left; else if (new_pos > right) new_pos = right; old_value = range->adjustment->value; range->adjustment->value = ((range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size) * (new_pos - left) / (right - left) + range->adjustment->lower); if (range->digits >= 0) { char buffer[64]; sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); sscanf (buffer, "%f", &range->adjustment->value); } if (old_value != range->adjustment->value) { if (range->policy == GTK_UPDATE_CONTINUOUS) { gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else { gtk_range_slider_update (range); gtk_range_draw_background (range); if (range->policy == GTK_UPDATE_DELAYED) { gtk_range_remove_timer (range); range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, (GtkFunction) RANGE_CLASS (range)->timer, (gpointer) range); } } } } void gtk_range_default_vmotion (GtkRange *range, gint xdelta, gint ydelta) { gdouble old_value; gint top, bottom; gint slider_x, slider_y; gint new_pos; g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); range = GTK_RANGE (range); gdk_window_get_position (range->slider, &slider_x, &slider_y); gtk_range_trough_vdims (range, &top, &bottom); if (bottom == top) return; new_pos = slider_y + ydelta; if (new_pos < top) new_pos = top; else if (new_pos > bottom) new_pos = bottom; old_value = range->adjustment->value; range->adjustment->value = ((range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size) * (new_pos - top) / (bottom - top) + range->adjustment->lower); if (range->digits >= 0) { char buffer[64]; sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); sscanf (buffer, "%f", &range->adjustment->value); } if (old_value != range->adjustment->value) { if (range->policy == GTK_UPDATE_CONTINUOUS) { gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else { gtk_range_slider_update (range); gtk_range_draw_background (range); if (range->policy == GTK_UPDATE_DELAYED) { gtk_range_remove_timer (range); range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, (GtkFunction) RANGE_CLASS (range)->timer, (gpointer) range); } } } } gfloat gtk_range_calc_value (GtkRange *range, gint position) { return 0.0; } static void gtk_range_destroy (GtkObject *object) { GtkRange *range; g_return_if_fail (object != NULL); g_return_if_fail (GTK_IS_RANGE (object)); range = GTK_RANGE (object); if (range->adjustment) gtk_object_unref (GTK_OBJECT (range->adjustment)); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void gtk_range_draw (GtkWidget *widget, GdkRectangle *area) { GtkRange *range; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_RANGE (widget)); g_return_if_fail (area != NULL); if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) { range = GTK_RANGE (widget); gtk_range_draw_background (range); gtk_range_draw_trough (range); gtk_range_draw_slider (range); gtk_range_draw_step_forw (range); gtk_range_draw_step_back (range); } } static void gtk_range_draw_focus (GtkWidget *widget) { g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_RANGE (widget)); if (GTK_WIDGET_DRAWABLE (widget)) gtk_range_draw_trough (GTK_RANGE (widget)); } static void gtk_range_unrealize (GtkWidget *widget) { GtkRange *range; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_RANGE (widget)); GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); range = GTK_RANGE (widget); gtk_style_detach (widget->style); if (range->slider) gdk_window_destroy (range->slider); if (range->trough) gdk_window_destroy (range->trough); if (range->step_forw) gdk_window_destroy (range->step_forw); if (range->step_back) gdk_window_destroy (range->step_back); if (widget->window) gdk_window_destroy (widget->window); range->slider = NULL; range->trough = NULL; range->step_forw = NULL; range->step_back = NULL; widget->window = NULL; } static gint gtk_range_expose (GtkWidget *widget, GdkEventExpose *event) { GtkRange *range; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); if (event->window == range->trough) { gtk_range_draw_trough (range); } else if (event->window == widget->window) { gtk_range_draw_background (range); } else if (event->window == range->slider) { gtk_range_draw_slider (range); } else if (event->window == range->step_forw) { gtk_range_draw_step_forw (range); } else if (event->window == range->step_back) { gtk_range_draw_step_back (range); } return FALSE; } static gint gtk_range_button_press (GtkWidget *widget, GdkEventButton *event) { GtkRange *range; gint trough_part; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); range = GTK_RANGE (widget); if (!range->button) { gtk_grab_add (widget); range->button = event->button; range->x_click_point = event->x; range->y_click_point = event->y; if (event->window == range->trough) { range->click_child = RANGE_CLASS (range)->trough; trough_part = gtk_range_trough_click (range, event->x, event->y); range->scroll_type = GTK_SCROLL_NONE; if (trough_part == GTK_TROUGH_START) range->scroll_type = GTK_SCROLL_PAGE_BACKWARD; else if (trough_part == GTK_TROUGH_END) range->scroll_type = GTK_SCROLL_PAGE_FORWARD; if (range->scroll_type != GTK_SCROLL_NONE) { gtk_range_scroll (range); gtk_range_add_timer (range); } } else if (event->window == range->slider) { range->click_child = RANGE_CLASS (range)->slider; range->scroll_type = GTK_SCROLL_NONE; } else if (event->window == range->step_forw) { range->click_child = RANGE_CLASS (range)->step_forw; range->scroll_type = GTK_SCROLL_STEP_FORWARD; gtk_range_scroll (range); gtk_range_add_timer (range); gtk_range_draw_step_forw (range); } else if (event->window == range->step_back) { range->click_child = RANGE_CLASS (range)->step_back; range->scroll_type = GTK_SCROLL_STEP_BACKWARD; gtk_range_scroll (range); gtk_range_add_timer (range); gtk_range_draw_step_back (range); } } return FALSE; } static gint gtk_range_button_release (GtkWidget *widget, GdkEventButton *event) { GtkRange *range; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); if (range->button == event->button) { gtk_grab_remove (widget); range->button = 0; range->x_click_point = -1; range->y_click_point = -1; if (range->click_child == RANGE_CLASS (range)->slider) { if (range->policy == GTK_UPDATE_DELAYED) gtk_range_remove_timer (range); if ((range->policy != GTK_UPDATE_CONTINUOUS) && (range->old_value != range->adjustment->value)) gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else if ((range->click_child == RANGE_CLASS (range)->trough) || (range->click_child == RANGE_CLASS (range)->step_forw) || (range->click_child == RANGE_CLASS (range)->step_back)) { gtk_range_remove_timer (range); if ((range->policy != GTK_UPDATE_CONTINUOUS) && (range->old_value != range->adjustment->value)) gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); if (range->click_child == RANGE_CLASS (range)->step_forw) { range->click_child = 0; gtk_range_draw_step_forw (range); } else if (range->click_child == RANGE_CLASS (range)->step_back) { range->click_child = 0; gtk_range_draw_step_back (range); } } range->click_child = 0; } return FALSE; } static gint gtk_range_motion_notify (GtkWidget *widget, GdkEventMotion *event) { GtkRange *range; GdkModifierType mods; gint x, y, mask; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); if (range->click_child == RANGE_CLASS (range)->slider) { x = event->x; y = event->y; if (event->is_hint || (event->window != range->slider)) gdk_window_get_pointer (range->slider, &x, &y, &mods); switch (range->button) { case 1: mask = GDK_BUTTON1_MASK; break; case 2: mask = GDK_BUTTON2_MASK; break; case 3: mask = GDK_BUTTON3_MASK; break; default: mask = 0; break; } if (mods & mask) { if (RANGE_CLASS (range)->motion) (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point); } } return FALSE; } static gint gtk_range_key_press (GtkWidget *widget, GdkEventKey *event) { GtkRange *range; gint return_val; GtkScrollType scroll = GTK_SCROLL_NONE; GtkTroughType pos = GTK_TROUGH_NONE; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); return_val = FALSE; if (RANGE_CLASS (range)->trough_keys) return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos); if (return_val) { if (scroll != GTK_SCROLL_NONE) { range->scroll_type = scroll; gtk_range_scroll (range); if (range->old_value != range->adjustment->value) { gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); switch (range->scroll_type) { case GTK_SCROLL_STEP_BACKWARD: gtk_range_draw_step_back (range); break; case GTK_SCROLL_STEP_FORWARD: gtk_range_draw_step_forw (range); break; } } } if (pos != GTK_TROUGH_NONE) { if (pos == GTK_TROUGH_START) range->adjustment->value = range->adjustment->lower; else range->adjustment->value = range->adjustment->upper - range->adjustment->page_size; if (range->old_value != range->adjustment->value) { gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); gtk_range_slider_update (range); gtk_range_draw_background (range); } } } return return_val; } static gint gtk_range_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkRange *range; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); if (event->window == range->trough) { range->in_child = RANGE_CLASS (range)->trough; } else if (event->window == range->slider) { range->in_child = RANGE_CLASS (range)->slider; if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_slider (range); } else if (event->window == range->step_forw) { range->in_child = RANGE_CLASS (range)->step_forw; if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_step_forw (range); } else if (event->window == range->step_back) { range->in_child = RANGE_CLASS (range)->step_back; if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_step_back (range); } return FALSE; } static gint gtk_range_leave_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkRange *range; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); range->in_child = 0; if (event->window == range->trough) { } else if (event->window == range->slider) { if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_slider (range); } else if (event->window == range->step_forw) { if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_step_forw (range); } else if (event->window == range->step_back) { if ((range->click_child == 0) || (range->click_child == RANGE_CLASS (range)->trough)) gtk_range_draw_step_back (range); } return FALSE; } static gint gtk_range_focus_in (GtkWidget *widget, GdkEventFocus *event) { g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); gtk_widget_draw_focus (widget); return FALSE; } static gint gtk_range_focus_out (GtkWidget *widget, GdkEventFocus *event) { g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); gtk_widget_draw_focus (widget); return FALSE; } static void gtk_real_range_draw_trough (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->trough) { gtk_draw_shadow (GTK_WIDGET (range)->style, range->trough, GTK_STATE_NORMAL, GTK_SHADOW_IN, 0, 0, -1, -1); if (GTK_WIDGET_HAS_FOCUS (range)) gdk_draw_rectangle (GTK_WIDGET (range)->window, GTK_WIDGET (range)->style->black_gc, FALSE, 0, 0, GTK_WIDGET (range)->allocation.width - 1, GTK_WIDGET (range)->allocation.height - 1); else if (range->trough != GTK_WIDGET (range)->window) gdk_draw_rectangle (GTK_WIDGET (range)->window, GTK_WIDGET (range)->style->bg_gc[GTK_STATE_NORMAL], FALSE, 0, 0, GTK_WIDGET (range)->allocation.width - 1, GTK_WIDGET (range)->allocation.height - 1); } } static void gtk_real_range_draw_slider (GtkRange *range) { GtkStateType state_type; g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->slider) { if ((range->in_child == RANGE_CLASS (range)->slider) || (range->click_child == RANGE_CLASS (range)->slider)) state_type = GTK_STATE_PRELIGHT; else state_type = GTK_STATE_NORMAL; gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); gdk_window_clear (range->slider); gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, state_type, GTK_SHADOW_OUT, 0, 0, -1, -1); } } static gint gtk_real_range_timer (GtkRange *range) { gint return_val; g_return_val_if_fail (range != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); return_val = TRUE; if (range->click_child == RANGE_CLASS (range)->slider) { if (range->policy == GTK_UPDATE_DELAYED) gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); return_val = FALSE; } else { if (!range->timer) { return_val = FALSE; if (range->need_timer) range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH, (GtkFunction) RANGE_CLASS (range)->timer, (gpointer) range); else return FALSE; range->need_timer = FALSE; } if (gtk_range_scroll (range)) return return_val; } return return_val; } static gint gtk_range_scroll (GtkRange *range) { gfloat new_value; gint return_val; g_return_val_if_fail (range != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); new_value = range->adjustment->value; return_val = TRUE; switch (range->scroll_type) { case GTK_SCROLL_NONE: break; case GTK_SCROLL_STEP_BACKWARD: new_value -= range->adjustment->step_increment; if (new_value <= range->adjustment->lower) { new_value = range->adjustment->lower; return_val = FALSE; range->timer = 0; } break; case GTK_SCROLL_STEP_FORWARD: new_value += range->adjustment->step_increment; if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) { new_value = range->adjustment->upper - range->adjustment->page_size; return_val = FALSE; range->timer = 0; } break; case GTK_SCROLL_PAGE_BACKWARD: new_value -= range->adjustment->page_increment; if (new_value <= range->adjustment->lower) { new_value = range->adjustment->lower; return_val = FALSE; range->timer = 0; } break; case GTK_SCROLL_PAGE_FORWARD: new_value += range->adjustment->page_increment; if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) { new_value = range->adjustment->upper - range->adjustment->page_size; return_val = FALSE; range->timer = 0; } break; } if (new_value != range->adjustment->value) { range->adjustment->value = new_value; if ((range->policy == GTK_UPDATE_CONTINUOUS) || (!return_val && (range->policy == GTK_UPDATE_DELAYED))) { gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); } else { gtk_range_slider_update (range); gtk_range_draw_background (range); } } return return_val; } static void gtk_range_add_timer (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (!range->timer) { range->need_timer = TRUE; range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY, (GtkFunction) RANGE_CLASS (range)->timer, (gpointer) range); } } static void gtk_range_remove_timer (GtkRange *range) { g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); if (range->timer) { gtk_timeout_remove (range->timer); range->timer = 0; } range->need_timer = FALSE; } static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, gpointer data) { GtkRange *range; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); range = GTK_RANGE (data); if (((range->old_lower != adjustment->lower) || (range->old_upper != adjustment->upper) || (range->old_page_size != adjustment->page_size)) && (range->old_value == adjustment->value)) { if ((adjustment->lower == adjustment->upper) || (range->old_lower == (range->old_upper - range->old_page_size))) { adjustment->value = adjustment->lower; gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed"); } } if ((range->old_value != adjustment->value) || (range->old_lower != adjustment->lower) || (range->old_upper != adjustment->upper) || (range->old_page_size != adjustment->page_size)) { gtk_range_slider_update (range); gtk_range_draw_background (range); range->old_value = adjustment->value; range->old_lower = adjustment->lower; range->old_upper = adjustment->upper; range->old_page_size = adjustment->page_size; } } static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) { GtkRange *range; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); range = GTK_RANGE (data); if (range->old_value != adjustment->value) { gtk_range_slider_update (range); gtk_range_draw_background (range); range->old_value = adjustment->value; } } static void gtk_range_trough_hdims (GtkRange *range, gint *left, gint *right) { gint trough_width; gint slider_length; gint tmp_width; gint tleft; gint tright; g_return_if_fail (range != NULL); gdk_window_get_size (range->trough, &trough_width, NULL); gdk_window_get_size (range->slider, &slider_length, NULL); tleft = GTK_WIDGET (range)->style->klass->xthickness; tright = trough_width - slider_length - GTK_WIDGET (range)->style->klass->xthickness; if (range->step_back) { gdk_window_get_size (range->step_back, &tmp_width, NULL); tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); } if (range->step_forw) { gdk_window_get_size (range->step_forw, &tmp_width, NULL); tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); } if (left) *left = tleft; if (right) *right = tright; } static void gtk_range_trough_vdims (GtkRange *range, gint *top, gint *bottom) { gint trough_height; gint slider_length; gint tmp_height; gint ttop; gint tbottom; g_return_if_fail (range != NULL); gdk_window_get_size (range->trough, NULL, &trough_height); gdk_window_get_size (range->slider, NULL, &slider_length); ttop = GTK_WIDGET (range)->style->klass->xthickness; tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->klass->ythickness; if (range->step_back) { gdk_window_get_size (range->step_back, NULL, &tmp_height); ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); } if (range->step_forw) { gdk_window_get_size (range->step_forw, NULL, &tmp_height); tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); } if (top) *top = ttop; if (bottom) *bottom = tbottom; }