X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkrange.c;h=8339e52b70c195a829185fd0ddad7217012e3d79;hb=HEAD;hp=2e4331610d37668f14d2bc6b9f32139782ab3900;hpb=d4b992506ad83a6482f836cb77a24ac24dbecc8e;p=~andy%2Fgtk diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index 2e4331610..8339e52b7 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -30,16 +28,19 @@ #include #include -#include "gtkmainprivate.h" +#include "gtkrange.h" + +#include "gtkadjustment.h" +#include "gtkcolorscaleprivate.h" +#include "gtkintl.h" +#include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkorientableprivate.h" -#include "gtkrange.h" +#include "gtkprivate.h" #include "gtkscale.h" #include "gtkscrollbar.h" -#include "gtkwindow.h" -#include "gtkprivate.h" -#include "gtkintl.h" #include "gtktypebuiltins.h" +#include "gtkwindow.h" #include "a11y/gtkrangeaccessible.h" /** @@ -115,8 +116,6 @@ struct _GtkRangePrivate gint slider_start; /* Slider range along the long dimension, in widget->window coords */ gint slider_end; - guint repaint_id; - /* Steppers are: < > ---- < > * a b c d */ @@ -136,6 +135,12 @@ struct _GtkRangePrivate guint lower_sensitive : 1; guint upper_sensitive : 1; + /* The range has an origin, should be drawn differently. Used by GtkScale */ + guint has_origin : 1; + + /* Whether we're doing fine adjustment */ + guint zoom : 1; + /* Fill level */ guint show_fill_level : 1; guint restrict_to_fill_level : 1; @@ -376,8 +381,6 @@ gtk_range_class_init (GtkRangeClass *class) * @range: the #GtkRange that received the signal * @scroll: the type of scroll action that was performed * @value: the new value resulting from the scroll action - * @returns: %TRUE to prevent other handlers from being invoked for the - * signal, %FALSE to propagate the signal further * * The #GtkRange::change-value signal is emitted when a scroll action is * performed on a range. It allows an application to determine the @@ -395,6 +398,9 @@ gtk_range_class_init (GtkRangeClass *class) * It is not possible to use delayed update policies in an overridden * #GtkRange::change-value handler. * + * Returns: %TRUE to prevent other handlers from being invoked for + * the signal, %FALSE to propagate the signal further + * * Since: 2.6 */ signals[CHANGE_VALUE] = @@ -734,6 +740,7 @@ gtk_range_init (GtkRange *range) priv->upper_sensitivity = GTK_SENSITIVITY_AUTO; priv->lower_sensitive = TRUE; priv->upper_sensitive = TRUE; + priv->has_origin = FALSE; priv->show_fill_level = FALSE; priv->restrict_to_fill_level = TRUE; priv->fill_level = G_MAXDOUBLE; @@ -1493,10 +1500,6 @@ gtk_range_destroy (GtkWidget *widget) gtk_range_remove_step_timer (range); - if (priv->repaint_id) - g_source_remove (priv->repaint_id); - priv->repaint_id = 0; - if (priv->adjustment) { g_signal_handlers_disconnect_by_func (priv->adjustment, @@ -1618,7 +1621,7 @@ modify_allocation_for_window_grip (GtkWidget *widget, translated_rect = *allocation; else { - gtk_widget_translate_coordinates (gtk_widget_get_parent (widget), + gtk_widget_translate_coordinates (parent, window, allocation->x, allocation->y, &x, &y); @@ -1629,7 +1632,7 @@ modify_allocation_for_window_grip (GtkWidget *widget, } /* If the stepper button intersects the window resize grip.. */ - if (gdk_rectangle_intersect (&grip_rect, &translated_rect, NULL)) + if (gdk_rectangle_intersect (&grip_rect, &translated_rect, &grip_rect)) { if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { @@ -1723,9 +1726,11 @@ gtk_range_realize (GtkWidget *widget) attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | + GDK_SMOOTH_SCROLL_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); @@ -1733,7 +1738,7 @@ gtk_range_realize (GtkWidget *widget) priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->event_window, range); + gtk_widget_register_window (widget, priv->event_window); } static void @@ -1744,7 +1749,7 @@ gtk_range_unrealize (GtkWidget *widget) gtk_range_remove_step_timer (range); - gdk_window_set_user_data (priv->event_window, NULL); + gtk_widget_unregister_window (widget, priv->event_window); gdk_window_destroy (priv->event_window); priv->event_window = NULL; @@ -1850,11 +1855,11 @@ draw_stepper (GtkRange *range, cairo_t *cr, GtkArrowType arrow_type, gboolean clicked, - gboolean prelighted) + gboolean prelighted, + GtkStateFlags state) { GtkRangePrivate *priv = range->priv; GtkAllocation allocation; - GtkStateFlags state = 0; GtkStyleContext *context; GtkWidget *widget = GTK_WIDGET (range); gfloat arrow_scaling; @@ -1898,8 +1903,12 @@ draw_stepper (GtkRange *range, arrow_sensitive = priv->lower_sensitive; } - if (!gtk_widget_is_sensitive (GTK_WIDGET (range)) || !arrow_sensitive) - state = GTK_STATE_FLAG_INSENSITIVE; + state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT); + + if ((state & GTK_STATE_FLAG_INSENSITIVE) || !arrow_sensitive) + { + state |= GTK_STATE_FLAG_INSENSITIVE; + } else { if (clicked) @@ -1921,6 +1930,23 @@ draw_stepper (GtkRange *range, gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); gtk_style_context_set_state (context, state); + switch (arrow_type) + { + case GTK_ARROW_RIGHT: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + break; + case GTK_ARROW_DOWN: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM); + break; + case GTK_ARROW_LEFT: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + break; + case GTK_ARROW_UP: + default: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP); + break; + } + gtk_render_background (context, cr, rect->x, rect->y, rect->width, rect->height); @@ -1978,22 +2004,27 @@ gtk_range_draw (GtkWidget *widget, { GtkRange *range = GTK_RANGE (widget); GtkRangePrivate *priv = range->priv; - gboolean sensitive; - GtkStateFlags state = 0; + GtkStateFlags widget_state; gint focus_line_width = 0; gint focus_padding = 0; - gboolean touchscreen; gboolean draw_trough = TRUE; + gboolean draw_slider = TRUE; GtkStyleContext *context; + GtkBorder margin; context = gtk_widget_get_style_context (widget); - g_object_get (gtk_widget_get_settings (widget), - "gtk-touchscreen-mode", &touchscreen, - NULL); if (GTK_IS_SCALE (widget) && gtk_adjustment_get_upper (priv->adjustment) == gtk_adjustment_get_lower (priv->adjustment)) - draw_trough = FALSE; + { + draw_trough = TRUE; + draw_slider = FALSE; + } + if (GTK_IS_COLOR_SCALE (widget)) + { + draw_trough = FALSE; + draw_slider = TRUE; + } if (gtk_widget_get_can_focus (GTK_WIDGET (range))) gtk_widget_style_get (GTK_WIDGET (range), @@ -2001,15 +2032,10 @@ gtk_range_draw (GtkWidget *widget, "focus-padding", &focus_padding, NULL); - /* we're now exposing, so there's no need to force early repaints */ - if (priv->repaint_id) - g_source_remove (priv->repaint_id); - priv->repaint_id = 0; - gtk_range_calc_marks (range); gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment)); - sensitive = gtk_widget_is_sensitive (widget); + widget_state = gtk_widget_get_state_flags (widget); /* Just to be confusing, we draw the trough for the whole * range rectangle, not the trough rectangle (the trough @@ -2038,11 +2064,6 @@ gtk_range_draw (GtkWidget *widget, "stepper-spacing", &stepper_spacing, NULL); - gtk_style_context_save (context); - - if (!sensitive) - gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE); - if (!trough_under_steppers) { gint offset = 0; @@ -2087,47 +2108,91 @@ gtk_range_draw (GtkWidget *widget, gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_margin (context, widget_state, &margin); + + x += margin.left; + y += margin.top; + width -= margin.left + margin.right; + height -= margin.top + margin.bottom; if (draw_trough) { - gint trough_change_pos_x = width; - gint trough_change_pos_y = height; - - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - trough_change_pos_x = (priv->slider.x + - priv->slider.width / 2 - - x); - else - trough_change_pos_y = (priv->slider.y + - priv->slider.height / 2 - - y); - - /* FIXME: was trough-upper and trough-lower really used, - * in that case, it should still be exposed somehow. - */ - gtk_render_background (context, cr, x, y, - trough_change_pos_x, - trough_change_pos_y); + if (!priv->has_origin || !draw_slider) + { + gtk_render_background (context, cr, + x, y, width, height); - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - trough_change_pos_y = 0; + gtk_render_frame (context, cr, + x, y, width, height); + } else - trough_change_pos_x = 0; - - gtk_render_background (context, cr, - x + trough_change_pos_x, y + trough_change_pos_y, - width - trough_change_pos_x, - height - trough_change_pos_y); - - gtk_render_frame (context, cr, - x, y, width, height); - } - else - { - gtk_render_background (context, cr, - x, y, width, height); - gtk_render_frame (context, cr, - x, y, width, height); + { + gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; + + gint trough_change_pos_x = width; + gint trough_change_pos_y = height; + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + trough_change_pos_x = (priv->slider.x + + priv->slider.width / 2 - + x); + else + trough_change_pos_y = (priv->slider.y + + priv->slider.height / 2 - + y); + + gtk_style_context_save (context); + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + + if (!is_rtl) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + } + else + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP); + + gtk_render_background (context, cr, x, y, + trough_change_pos_x, + trough_change_pos_y); + + gtk_render_frame (context, cr, x, y, + trough_change_pos_x, + trough_change_pos_y); + + gtk_style_context_restore (context); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + trough_change_pos_y = 0; + else + trough_change_pos_x = 0; + + gtk_style_context_save (context); + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + + if (is_rtl) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + } + else + { + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + } + + gtk_render_background (context, cr, + x + trough_change_pos_x, y + trough_change_pos_y, + width - trough_change_pos_x, + height - trough_change_pos_y); + + gtk_render_frame (context, cr, + x + trough_change_pos_x, y + trough_change_pos_y, + width - trough_change_pos_x, + height - trough_change_pos_y); + + gtk_style_context_restore (context); + } } gtk_style_context_restore (context); @@ -2178,13 +2243,6 @@ gtk_range_draw (GtkWidget *widget, fill_y += priv->trough.height - fill_height; } -#if 0 - if (fill_level < gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment)) - fill_detail = "trough-fill-level-full"; - else - fill_detail = "trough-fill-level"; -#endif - gtk_render_activity (context, cr, fill_x, fill_y, fill_width, fill_height); @@ -2192,40 +2250,34 @@ gtk_range_draw (GtkWidget *widget, gtk_style_context_restore (context); } - gtk_style_context_restore (context); - - if (sensitive && gtk_widget_has_focus (widget)) + if (!(widget_state & GTK_STATE_FLAG_INSENSITIVE) && gtk_widget_has_visible_focus (widget)) { - gtk_style_context_save (context); - gtk_style_context_set_state (context, - gtk_widget_get_state_flags (widget)); - gtk_render_focus (context, cr, priv->range_rect.x, priv->range_rect.y, priv->range_rect.width, priv->range_rect.height); - - gtk_style_context_restore (context); } } cairo_restore (cr); - if (!sensitive) - state = GTK_STATE_FLAG_INSENSITIVE; - else if (!touchscreen && priv->mouse_location == MOUSE_SLIDER) - state = GTK_STATE_FLAG_PRELIGHT; + if (draw_slider) + { + GtkStateFlags state = widget_state; - if (priv->grab_location == MOUSE_SLIDER) - state |= GTK_STATE_FLAG_ACTIVE; + state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE); - cairo_save (cr); - gdk_cairo_rectangle (cr, &priv->slider); - cairo_clip (cr); + if (priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE)) + state |= GTK_STATE_FLAG_PRELIGHT; + + if (priv->grab_location == MOUSE_SLIDER) + state |= GTK_STATE_FLAG_ACTIVE; + + cairo_save (cr); + gdk_cairo_rectangle (cr, &priv->slider); + cairo_clip (cr); - if (draw_trough) - { gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_set_state (context, state); @@ -2238,33 +2290,37 @@ gtk_range_draw (GtkWidget *widget, priv->orientation); gtk_style_context_restore (context); - } - cairo_restore (cr); + cairo_restore (cr); + } if (priv->has_stepper_a) draw_stepper (range, STEPPER_A, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, priv->grab_location == MOUSE_STEPPER_A, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_A); + priv->mouse_location == MOUSE_STEPPER_A, + widget_state); if (priv->has_stepper_b) draw_stepper (range, STEPPER_B, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, priv->grab_location == MOUSE_STEPPER_B, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_B); + priv->mouse_location == MOUSE_STEPPER_B, + widget_state); if (priv->has_stepper_c) draw_stepper (range, STEPPER_C, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, priv->grab_location == MOUSE_STEPPER_C, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_C); + priv->mouse_location == MOUSE_STEPPER_C, + widget_state); if (priv->has_stepper_d) draw_stepper (range, STEPPER_D, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, priv->grab_location == MOUSE_STEPPER_D, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_D); + priv->mouse_location == MOUSE_STEPPER_D, + widget_state); return FALSE; } @@ -2280,15 +2336,11 @@ range_grab_add (GtkRange *range, if (device == priv->grab_device) return; - if (priv->grab_device != NULL) - { - g_warning ("GtkRange already had a grab device, releasing device grab"); - gtk_device_grab_remove (GTK_WIDGET (range), priv->grab_device); - } - - /* we don't actually gdk_grab, since a button is down */ - gtk_device_grab_add (GTK_WIDGET (range), device, TRUE); - + /* Don't perform any GDK/GTK+ grab here. Since a button + * is down, there's an ongoing implicit grab on + * priv->event_window, which pretty much guarantees this + * is the only widget receiving the pointer events. + */ priv->grab_location = location; priv->grab_button = button; priv->grab_device = device; @@ -2305,9 +2357,10 @@ range_grab_remove (GtkRange *range) if (priv->grab_device) { - gtk_device_grab_remove (GTK_WIDGET (range), - priv->grab_device); + GdkDevice *grab_device = priv->grab_device; + priv->grab_device = NULL; + gtk_device_grab_remove (GTK_WIDGET (range), grab_device); } location = priv->grab_location; @@ -2317,6 +2370,8 @@ range_grab_remove (GtkRange *range) if (gtk_range_update_mouse_location (range) || location != MOUSE_OUTSIDE) gtk_widget_queue_draw (GTK_WIDGET (range)); + + priv->zoom = FALSE; } static GtkScrollType @@ -2333,13 +2388,13 @@ range_get_scroll_for_grab (GtkRange *range) case MOUSE_STEPPER_C: switch (priv->grab_button) { - case 1: + case GDK_BUTTON_PRIMARY: return invert ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD; break; - case 2: + case GDK_BUTTON_MIDDLE: return invert ? GTK_SCROLL_PAGE_FORWARD : GTK_SCROLL_PAGE_BACKWARD; break; - case 3: + case GDK_BUTTON_SECONDARY: return invert ? GTK_SCROLL_END : GTK_SCROLL_START; break; } @@ -2350,13 +2405,13 @@ range_get_scroll_for_grab (GtkRange *range) case MOUSE_STEPPER_D: switch (priv->grab_button) { - case 1: + case GDK_BUTTON_PRIMARY: return invert ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD; break; - case 2: + case GDK_BUTTON_MIDDLE: return invert ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD; break; - case 3: + case GDK_BUTTON_SECONDARY: return invert ? GTK_SCROLL_START : GTK_SCROLL_END; break; } @@ -2383,7 +2438,7 @@ range_get_scroll_for_grab (GtkRange *range) static gdouble coord_to_value (GtkRange *range, - gint coord) + gdouble coord) { GtkRangePrivate *priv = range->priv; gdouble frac; @@ -2465,7 +2520,10 @@ gtk_range_button_press (GtkWidget *widget, { GtkRange *range = GTK_RANGE (widget); GtkRangePrivate *priv = range->priv; - GdkDevice *device; + GdkDevice *device, *source_device; + GdkInputSource source; + gboolean primary_warps; + gint page_increment_button, warp_button; if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); @@ -2475,29 +2533,57 @@ gtk_range_button_press (GtkWidget *widget, return FALSE; device = gdk_event_get_device ((GdkEvent *) event); + source_device = gdk_event_get_source_device ((GdkEvent *) event); + source = gdk_device_get_source (source_device); + priv->mouse_x = event->x; priv->mouse_y = event->y; if (gtk_range_update_mouse_location (range)) gtk_widget_queue_draw (widget); - if (priv->mouse_location == MOUSE_TROUGH && - event->button == 1) + g_object_get (gtk_widget_get_settings (widget), + "gtk-primary-button-warps-slider", &primary_warps, + NULL); + if (primary_warps) { - /* button 1 steps by page increment, as with button 2 on a stepper + warp_button = GDK_BUTTON_PRIMARY; + page_increment_button = GDK_BUTTON_SECONDARY; + } + else + { + warp_button = GDK_BUTTON_MIDDLE; + page_increment_button = GDK_BUTTON_PRIMARY; + } + + if (priv->mouse_location == MOUSE_SLIDER && + gdk_event_triggers_context_menu ((GdkEvent *)event)) + { + gboolean handled; + + g_signal_emit_by_name (widget, "popup-menu", &handled); + + return TRUE; + } + + if (source != GDK_SOURCE_TOUCHSCREEN && + priv->mouse_location == MOUSE_TROUGH && + event->button == page_increment_button) + { + /* button 2 steps by page increment, as with button 2 on a stepper */ GtkScrollType scroll; gdouble click_value; - + click_value = coord_to_value (range, priv->orientation == GTK_ORIENTATION_VERTICAL ? event->y : event->x); priv->trough_click_forward = click_value > gtk_adjustment_get_value (priv->adjustment); range_grab_add (range, device, MOUSE_TROUGH, event->button); - + scroll = range_get_scroll_for_grab (range); - + gtk_range_add_step_timer (range, scroll); return TRUE; @@ -2506,7 +2592,9 @@ gtk_range_button_press (GtkWidget *widget, priv->mouse_location == MOUSE_STEPPER_B || priv->mouse_location == MOUSE_STEPPER_C || priv->mouse_location == MOUSE_STEPPER_D) && - (event->button == 1 || event->button == 2 || event->button == 3)) + (event->button == GDK_BUTTON_PRIMARY || + event->button == GDK_BUTTON_MIDDLE || + event->button == GDK_BUTTON_SECONDARY)) { GtkAllocation allocation; GdkRectangle *stepper_area; @@ -2530,17 +2618,17 @@ gtk_range_button_press (GtkWidget *widget, return TRUE; } else if ((priv->mouse_location == MOUSE_TROUGH && - event->button == 2) || + (source == GDK_SOURCE_TOUCHSCREEN || + event->button == warp_button)) || priv->mouse_location == MOUSE_SLIDER) { gboolean need_value_update = FALSE; /* Any button can be used to drag the slider, but you can start - * dragging the slider with a trough click using button 2; - * On button 2 press, we warp the slider to mouse position, - * then begin the slider drag. + * dragging the slider with a trough click using button 1; + * we warp the slider to mouse position, then begin the slider drag. */ - if (event->button == 2) + if (priv->mouse_location != MOUSE_SLIDER) { gdouble slider_low_value, slider_high_value, new_value; @@ -2568,6 +2656,12 @@ gtk_range_button_press (GtkWidget *widget, */ need_value_update = TRUE; } + else + { + /* Shift-click in the slider = fine adjustment */ + if (event->state & GDK_SHIFT_MASK) + priv->zoom = TRUE; + } if (priv->orientation == GTK_ORIENTATION_VERTICAL) { @@ -2600,13 +2694,14 @@ update_slider_position (GtkRange *range, gint mouse_y) { GtkRangePrivate *priv = range->priv; - gint delta; - gint c; + gdouble delta; + gdouble c; gdouble new_value; gboolean handled; gdouble next_value; gdouble mark_value; gdouble mark_delta; + gdouble zoom; gint i; if (priv->orientation == GTK_ORIENTATION_VERTICAL) @@ -2614,11 +2709,25 @@ update_slider_position (GtkRange *range, else delta = mouse_x - priv->slide_initial_coordinate; - c = priv->slide_initial_slider_position + delta; + if (priv->zoom) + { + zoom = MIN(1.0, (priv->orientation == GTK_ORIENTATION_VERTICAL ? + priv->trough.height : priv->trough.width) / + (gtk_adjustment_get_upper (priv->adjustment) - + gtk_adjustment_get_lower (priv->adjustment) - + gtk_adjustment_get_page_size (priv->adjustment))); + /* the above is ineffective for scales, so just set a zoom factor */ + if (zoom == 1.0) + zoom = 0.25; + } + else + zoom = 1.0; + + c = priv->slide_initial_slider_position + zoom * delta; new_value = coord_to_value (range, c); next_value = coord_to_value (range, c + 1); - mark_delta = fabs (next_value - new_value); + mark_delta = fabs (next_value - new_value); for (i = 0; i < priv->n_marks; i++) { @@ -2632,13 +2741,13 @@ update_slider_position (GtkRange *range, break; } } - } + } g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, new_value, &handled); } -static void +static void stop_scrolling (GtkRange *range) { range_grab_remove (range); @@ -2659,7 +2768,7 @@ gtk_range_grab_broken (GtkWidget *widget, priv->grab_location != MOUSE_OUTSIDE) { if (priv->grab_location == MOUSE_SLIDER) - update_slider_position (range, priv->mouse_x, priv->mouse_y); + update_slider_position (range, priv->mouse_x, priv->mouse_y); stop_scrolling (range); @@ -2710,37 +2819,57 @@ gtk_range_button_release (GtkWidget *widget, /** * _gtk_range_get_wheel_delta: * @range: a #GtkRange - * @direction: A #GdkScrollDirection - * + * @event: A #GdkEventScroll + * * Returns a good step value for the mouse wheel. - * - * Return value: A good step value for the mouse wheel. - * + * + * Return value: A good step value for the mouse wheel. + * * Since: 2.4 **/ gdouble -_gtk_range_get_wheel_delta (GtkRange *range, - GdkScrollDirection direction) +_gtk_range_get_wheel_delta (GtkRange *range, + GdkEventScroll *event) { GtkRangePrivate *priv = range->priv; GtkAdjustment *adjustment = priv->adjustment; + gdouble dx, dy; gdouble delta; + gdouble page_size; + gdouble page_increment; + gdouble scroll_unit; + + page_size = gtk_adjustment_get_page_size (adjustment); + page_increment = gtk_adjustment_get_page_increment (adjustment); if (GTK_IS_SCROLLBAR (range)) - delta = pow (gtk_adjustment_get_page_size (adjustment), 2.0 / 3.0); + scroll_unit = pow (page_size, 2.0 / 3.0); else - delta = gtk_adjustment_get_step_increment (adjustment) * 2; - - if (direction == GDK_SCROLL_UP || - direction == GDK_SCROLL_LEFT) - delta = - delta; - + scroll_unit = page_increment; + + if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy)) + { + if (dx != 0 && + gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL) + delta = dx * scroll_unit; + else + delta = dy * scroll_unit; + } + else + { + if (event->direction == GDK_SCROLL_UP || + event->direction == GDK_SCROLL_LEFT) + delta = - scroll_unit; + else + delta = scroll_unit; + } + if (priv->inverted) delta = - delta; return delta; } - + static gboolean gtk_range_scroll_event (GtkWidget *widget, GdkEventScroll *event) @@ -2753,7 +2882,7 @@ gtk_range_scroll_event (GtkWidget *widget, gdouble delta; gboolean handled; - delta = _gtk_range_get_wheel_delta (range, event->direction); + delta = _gtk_range_get_wheel_delta (range, event); g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, gtk_adjustment_get_value (priv->adjustment) + delta, @@ -2886,20 +3015,6 @@ gtk_range_adjustment_changed (GtkAdjustment *adjustment, */ } -static gboolean -force_repaint (gpointer data) -{ - GtkRange *range = GTK_RANGE (data); - GtkRangePrivate *priv = range->priv; - GtkWidget *widget = GTK_WIDGET (range); - - priv->repaint_id = 0; - if (gtk_widget_is_drawable (widget)) - gdk_window_process_updates (gtk_widget_get_window (widget), FALSE); - - return FALSE; -} - static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) @@ -2916,11 +3031,6 @@ gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, (GTK_IS_SCALE (range) && gtk_scale_get_draw_value (GTK_SCALE (range)))) { gtk_widget_queue_draw (GTK_WIDGET (range)); - /* setup a timer to ensure the range isn't lagging too much behind the scroll position */ - if (!priv->repaint_id) - priv->repaint_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS, - 181, force_repaint, - range, NULL); } /* Note that we don't round off to priv->round_digits here. @@ -3489,13 +3599,15 @@ gtk_range_calc_layout (GtkRange *range, GtkRangePrivate *priv = range->priv; gint slider_width, stepper_size, focus_width, trough_border, stepper_spacing; gint slider_length; - GtkBorder border; + GtkBorder border, trough_margin; gint n_steppers; gboolean has_steppers_ab; gboolean has_steppers_cd; gboolean trough_under_steppers; GdkRectangle range_rect; GtkWidget *widget; + GtkStyleContext *context; + GtkStateFlags state; if (!priv->need_recalc) return; @@ -3511,6 +3623,13 @@ gtk_range_calc_layout (GtkRange *range, */ widget = GTK_WIDGET (range); + context = gtk_widget_get_style_context (widget); + + state = gtk_widget_get_state_flags (widget); + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_margin (context, state, &trough_margin); + gtk_style_context_restore (context); gtk_range_get_props (range, &slider_width, &stepper_size, @@ -3779,7 +3898,6 @@ gtk_range_calc_layout (GtkRange *range, */ priv->trough.x = priv->stepper_b.x + priv->stepper_b.width + stepper_spacing * has_steppers_ab; priv->trough.y = range_rect.y; - priv->trough.width = priv->stepper_c.x - priv->trough.x - stepper_spacing * has_steppers_cd; priv->trough.height = range_rect.height; @@ -4043,6 +4161,19 @@ gtk_range_remove_step_timer (GtkRange *range) } } +void +_gtk_range_set_has_origin (GtkRange *range, + gboolean has_origin) +{ + range->priv->has_origin = has_origin; +} + +gboolean +_gtk_range_get_has_origin (GtkRange *range) +{ + return range->priv->has_origin; +} + void _gtk_range_set_stop_values (GtkRange *range, gdouble *values,