#include <stdio.h>
#include <math.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 "gtkcolorscaleprivate.h"
#include "gtkscrollbar.h"
-#include "gtkwindow.h"
-#include "gtkprivate.h"
-#include "gtkintl.h"
-#include "gtkmain.h"
#include "gtktypebuiltins.h"
+#include "gtkwindow.h"
#include "a11y/gtkrangeaccessible.h"
/**
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
*/
/* 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;
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,
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;
gboolean draw_trough = TRUE;
gboolean draw_slider = TRUE;
GtkStyleContext *context;
+ GtkBorder margin;
context = gtk_widget_get_style_context (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));
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)
{
- if (!priv->has_origin)
+ if (!priv->has_origin || !draw_slider)
{
gtk_render_background (context, cr,
x, y, width, height);
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);
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
static gdouble
coord_to_value (GtkRange *range,
- gint coord)
+ gdouble coord)
{
GtkRangePrivate *priv = range->priv;
gdouble frac;
GtkRangePrivate *priv = range->priv;
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);
if (gtk_range_update_mouse_location (range))
gtk_widget_queue_draw (widget);
+ 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))
{
if (source != GDK_SOURCE_TOUCHSCREEN &&
priv->mouse_location == MOUSE_TROUGH &&
- event->button == GDK_BUTTON_PRIMARY)
+ event->button == page_increment_button)
{
- /* button 1 steps by page increment, as with button 2 on a stepper
+ /* button 2 steps by page increment, as with button 2 on a stepper
*/
GtkScrollType scroll;
gdouble click_value;
return TRUE;
}
else if ((priv->mouse_location == MOUSE_TROUGH &&
- (source == GDK_SOURCE_TOUCHSCREEN || event->button == GDK_BUTTON_MIDDLE)) ||
+ (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 and touch devices, 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 == GDK_BUTTON_MIDDLE || source == GDK_SOURCE_TOUCHSCREEN)
+ 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
* @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
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))
+ scroll_unit = pow (page_size, 2.0 / 3.0);
+ else
+ scroll_unit = page_increment;
if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy))
{
- GtkAllocation allocation;
-
- gtk_widget_get_allocation (GTK_WIDGET (range), &allocation);
-
if (dx != 0 &&
gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
- {
- if (GTK_IS_SCROLLBAR (range) && page_size > 0)
- delta = dx * page_size / allocation.width;
- else
- delta = dx * (gtk_adjustment_get_upper (adjustment) -
- gtk_adjustment_get_lower (adjustment)) / allocation.width;
- }
+ delta = dx * scroll_unit;
else
- {
- if (GTK_IS_SCROLLBAR (range) && page_size > 0)
- delta = dy * page_size / allocation.height;
- else
- delta = dy * (gtk_adjustment_get_upper (adjustment) -
- gtk_adjustment_get_lower (adjustment)) / allocation.height;
- }
+ delta = dy * scroll_unit;
}
else
{
- if (GTK_IS_SCROLLBAR (range))
- delta = pow (page_size, 2.0 / 3.0);
- else
- delta = gtk_adjustment_get_page_increment (adjustment) * 2;
-
if (event->direction == GDK_SCROLL_UP ||
event->direction == GDK_SCROLL_LEFT)
- delta = - delta;
+ delta = - scroll_unit;
+ else
+ delta = scroll_unit;
}
if (priv->inverted)
*/
}
-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.
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;