* 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 <http://www.gnu.org/licenses/>.
*/
/*
#include <stdio.h>
#include <math.h>
-#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"
/**
* SECTION:gtkrange
gint mouse_x;
gint mouse_y;
MouseLocation grab_location; /* "grabbed" mouse location, OUTSIDE for no grab */
- guint grab_button : 8; /* 0 if none */
GtkRangeStepTimer *timer;
GtkAdjustment *adjustment;
- GtkOrientation orientation;
GtkSensitivityType lower_sensitivity;
GtkSensitivityType upper_sensitivity;
GQuark slider_detail_quark;
GQuark stepper_detail_quark[4];
- gboolean recalc_marks;
+ GtkOrientation orientation;
gdouble fill_level;
gdouble *marks;
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
*/
guint flippable : 1;
guint inverted : 1;
guint need_recalc : 1;
+ guint recalc_marks : 1;
guint slider_size_fixed : 1;
guint trough_click_forward : 1; /* trough click was on the forward side of slider */
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;
+
+ guint grab_button : 8; /* 0 if none */
};
* @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
* 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] =
* GtkRange:stepper-spacing:
*
* The spacing between the stepper buttons and thumb. Note that
- * setting this value to anything > 0 will automatically set the
- * trough-under-steppers style property to %TRUE as well. Also,
* stepper-spacing won't have any effect if there are no steppers.
*/
gtk_widget_class_install_style_property (widget_class,
* GtkRange:trough-under-steppers:
*
* Whether to draw the trough across the full length of the range or
- * to exclude the steppers and their spacing. Note that setting the
- * #GtkRange:stepper-spacing style property to any value > 0 will
- * automatically enable trough-under-steppers too.
+ * to exclude the steppers and their spacing.
*
* Since: 2.10
*/
GTK_PARAM_READABLE));
g_type_class_add_private (class, sizeof (GtkRangePrivate));
+
+ gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
}
static void
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;
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,
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);
}
/* 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)
{
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);
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
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;
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;
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)
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);
{
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),
"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
"stepper-spacing", &stepper_spacing,
NULL);
- gtk_style_context_save (context);
-
- if (!sensitive)
- gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
-
- if (stepper_spacing > 0)
- trough_under_steppers = FALSE;
-
if (!trough_under_steppers)
{
gint offset = 0;
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);
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);
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);
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;
}
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;
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;
if (gtk_range_update_mouse_location (range) ||
location != MOUSE_OUTSIDE)
gtk_widget_queue_draw (GTK_WIDGET (range));
+
+ priv->zoom = FALSE;
}
static GtkScrollType
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;
}
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;
}
static gdouble
coord_to_value (GtkRange *range,
- gint coord)
+ gdouble coord)
{
GtkRangePrivate *priv = range->priv;
gdouble frac;
{
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);
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)
+ {
+ 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))
{
- /* button 1 steps by page increment, as with button 2 on a stepper
+ 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;
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;
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;
*/
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)
{
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)
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++)
{
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);
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);
/**
* _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)
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,
*/
}
-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)
(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.
"arrow-displacement-y", &tmp_arrow_displacement_y,
NULL);
- if (tmp_stepper_spacing > 0)
- tmp_trough_under_steppers = FALSE;
-
if (gtk_widget_get_can_focus (GTK_WIDGET (range)))
{
gint focus_line_width;
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;
*/
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,
*/
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;
}
}
+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,