Smooth scrolling
- From: Soeren Sandmann <sandmann daimi au dk>
- To: gtk-devel-list gnome org
- Subject: Smooth scrolling
- Date: 17 Jan 2003 22:26:44 +0100
I am attaching a patch that changes gtk+ scrolling to work much like
it does in Internet Explorer. That is the widgets seem to scroll one
pixel at the time. Scrolling this way makes it easier to track the
content of the widgets. You can actually scroll and read the text at
the same time.
The main disadvantage is that it requires much more CPU than before.
The expose method is called much more often, and not all widgets are
prepared for this. When a widget has trouble keeping up with the
screen's refresh rate, the result is jitter.
Another disadvantage is that self-scrolling widgets have to be updated
to make their keyboard navigation take advantage of the smooth
scrolling. Until third-party widgets are updated, they will scroll
smoothly when you are using the scrollbar or the mouse wheel, but
jerky when using the widget's own keyboard navigation.
Also, this patch changes how far a click with the mouse wheel moves a
widget. Currently, a wheel step is half a page, which is far too much,
cf. bug 89259. The new value is
pow (adj->page_size, 2.0/3.0),
ie. the third root of the square of the page size. I got this strange
formula by plotting good values for the scroll amount at different
page sizes. Much to my suprise, the third root of the squared page
size was an almost perfect fit to the points.
The patch introduces this new API:
void gtk_adjustment_goto_value (GtkAdjustment *adjustment,
gdouble value);
void gtk_adjustment_home (GtkAdjustment *adjustment);
void gtk_adjustment_end (GtkAdjustment *adjustment);
void gtk_adjustment_step_up (GtkAdjustment *adjustment);
void gtk_adjustment_step_down (GtkAdjustment *adjustment);
void gtk_adjustment_wheel_up (GtkAdjustment *adjustment);
void gtk_adjustment_wheel_down (GtkAdjustment *adjustment);
void gtk_adjustment_page_up (GtkAdjustment *adjustment);
void gtk_adjustment_page_down (GtkAdjustment *adjustment);
To do smooth scrolling, it is necessary for the adjustment to keep
track of how far it has already scrolled. This means that clients of
the adjustment can't any longer just call gtk_adjustment_set_value().
Most of these functions are just trivial wrappers around
gtk_adjustment_change_value(). It would be possible to just export
that function instead, but having the wrappers seem cleaner to
me. Also, without the wheel_up/down() wrappers, the pow (size, 2/3)
formula would have to appear both in gtkscrolledwindow.c and in
gtkrange.c.
In fact pow (size, 2/3) does appear in gtkrange.c even with the
wrapper. This is because GtkRange has a feature (round_digits) that
allows it to filter the values it can input into an adjustment. When
this feature is used, smooth scrolling can't be used because there is
no guarantee that the intermediate points are valid according to the
filter.
In addition, this patch makes GtkRange scroll slightly faster when you
press a stepper and hold it. This is just something I think is an
improvement. It doesn't really have much to do with smooth scrolling.
This patch is not final because
- it should be possible to turn off smooth scrolling. Some
people don't like the effect, and some may not have a fast
enough computer for it. There are probably also
acccessibility reasons to turn it off.
- the TreeView and the TextView should be updated so that
their keyboard navigation smooth scrolls.
Søren
Index: gtkadjustment.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkadjustment.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 gtkadjustment.c
--- gtkadjustment.c 9 Oct 2002 22:25:17 -0000 1.27
+++ gtkadjustment.c 17 Jan 2003 20:04:30 -0000
@@ -26,7 +26,7 @@
#include "gtkadjustment.h"
#include "gtkmarshalers.h"
-
+#include <math.h>
enum {
CHANGED,
@@ -35,9 +35,19 @@ enum {
};
-static void gtk_adjustment_class_init (GtkAdjustmentClass *klass);
-static void gtk_adjustment_init (GtkAdjustment *adjustment);
+typedef struct _GtkAdjustmentPrivate GtkAdjustmentPrivate;
+struct _GtkAdjustmentPrivate
+{
+ GTimer *timer;
+ gdouble start_value;
+ gdouble goal_value;
+ guint idle_id;
+};
+static void gtk_adjustment_private_finalize (GtkAdjustmentPrivate *private);
+static void gtk_adjustment_class_init (GtkAdjustmentClass *klass);
+static void gtk_adjustment_init (GtkAdjustment *adjustment);
+static GtkAdjustmentPrivate *gtk_adjustment_get_private (GtkAdjustment *adjustment);
static guint adjustment_signals[LAST_SIGNAL] = { 0 };
@@ -75,7 +85,7 @@ gtk_adjustment_class_init (GtkAdjustment
{
class->changed = NULL;
class->value_changed = NULL;
-
+
adjustment_signals[CHANGED] =
g_signal_new ("changed",
G_OBJECT_CLASS_TYPE (class),
@@ -105,6 +115,44 @@ gtk_adjustment_init (GtkAdjustment *adju
adjustment->page_size = 0.0;
}
+static GtkAdjustmentPrivate *
+gtk_adjustment_get_private (GtkAdjustment *adjustment)
+{
+ GtkAdjustmentPrivate *private;
+ static GQuark private_quark = 0;
+
+ if (!private_quark)
+ private_quark = g_quark_from_static_string ("gtk-adjustment-private");
+
+ private = g_object_get_qdata (G_OBJECT (adjustment), private_quark);
+
+ if (!private)
+ {
+ private = g_new0 (GtkAdjustmentPrivate, 1);
+
+ private->timer = g_timer_new ();
+ private->start_value = 0.0;
+ private->goal_value = 0.0;
+ private->idle_id = 0;
+
+ g_object_set_qdata_full (G_OBJECT (adjustment), private_quark,
+ private,
+ (GDestroyNotify) gtk_adjustment_private_finalize);
+ }
+
+ return private;
+}
+
+static void
+gtk_adjustment_private_finalize (GtkAdjustmentPrivate *private)
+{
+ if (private->idle_id)
+ g_source_remove (private->idle_id);
+
+ g_timer_destroy (private->timer);
+ g_free (private);
+}
+
GtkObject*
gtk_adjustment_new (gdouble value,
gdouble lower,
@@ -168,12 +216,27 @@ gtk_adjustment_changed (GtkAdjustment
g_signal_emit (adjustment, adjustment_signals[CHANGED], 0);
}
+static void
+gtk_adjustment_value_changed_unchecked (GtkAdjustment *adjustment)
+{
+ g_signal_emit (adjustment, adjustment_signals[VALUE_CHANGED], 0);
+}
+
void
gtk_adjustment_value_changed (GtkAdjustment *adjustment)
{
+ GtkAdjustmentPrivate *priv;
+
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
- g_signal_emit (adjustment, adjustment_signals[VALUE_CHANGED], 0);
+ priv = gtk_adjustment_get_private (adjustment);
+ if (priv->idle_id)
+ {
+ g_source_remove (priv->idle_id);
+ priv->idle_id = 0;
+ }
+
+ gtk_adjustment_value_changed_unchecked (adjustment);
}
void
@@ -203,4 +266,160 @@ gtk_adjustment_clamp_page (GtkAdjustment
if (need_emission)
gtk_adjustment_value_changed (adjustment);
+}
+
+#define UPDATE_TIME 0.1
+
+static gboolean
+adjustment_update_idle (gpointer data)
+{
+ GtkAdjustment *adj = data;
+ GtkAdjustmentPrivate *priv = gtk_adjustment_get_private (adj);
+
+ gdouble new_value;
+ gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
+
+ new_value = priv->start_value +
+ (elapsed / UPDATE_TIME) * (priv->goal_value - priv->start_value);
+
+ /* make sure new_value is betweeen start_value and goal_value */
+ if (!((new_value >= priv->start_value && new_value <= priv->goal_value) ||
+ (new_value <= priv->start_value && new_value >= priv->goal_value)))
+ {
+ new_value = priv->goal_value;
+ }
+
+ if (new_value > adj->upper - adj->page_size)
+ new_value = adj->upper - adj->page_size;
+
+ if (new_value < adj->lower)
+ new_value = adj->lower;
+
+ if (new_value != adj->value)
+ {
+ adj->value = new_value;
+
+ GDK_THREADS_ENTER();
+ gtk_adjustment_value_changed_unchecked (adj);
+ GDK_THREADS_LEAVE();
+ }
+
+ if (adj->value == priv->goal_value ||
+ adj->value == adj->lower ||
+ adj->value == adj->upper - adj->page_size)
+ {
+ priv->idle_id = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gtk_adjustment_change_value (GtkAdjustment *adjustment,
+ gdouble delta)
+{
+ GtkAdjustmentPrivate *priv;
+
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ priv = gtk_adjustment_get_private (adjustment);
+
+ if (delta > -1 && delta < 1)
+ return;
+
+ priv->start_value = adjustment->value;
+ g_timer_reset (priv->timer);
+
+ if (!priv->idle_id)
+ {
+ priv->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW + 3, adjustment_update_idle, adjustment, NULL);
+ priv->goal_value = adjustment->value + delta;
+ }
+ else
+ priv->goal_value = priv->goal_value + delta;
+}
+
+void
+gtk_adjustment_step_up (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment, -adjustment->step_increment);
+}
+
+void
+gtk_adjustment_step_down (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment, adjustment->step_increment);
+}
+
+void
+gtk_adjustment_wheel_up (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment,
+ -pow (adjustment->page_size, 2.0/3.0));
+}
+
+void
+gtk_adjustment_wheel_down (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment,
+ pow (adjustment->page_size, 2.0/3.0));
+}
+
+void
+gtk_adjustment_page_up (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment, -adjustment->page_increment);
+}
+
+void
+gtk_adjustment_page_down (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_change_value (adjustment, adjustment->page_increment);
+}
+
+void
+gtk_adjustment_home (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_goto_value (adjustment, 0.0);
+}
+
+void
+gtk_adjustment_end (GtkAdjustment *adjustment)
+{
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ gtk_adjustment_goto_value (adjustment, adjustment->upper - adjustment->page_size);
+}
+
+void
+gtk_adjustment_goto_value (GtkAdjustment *adjustment,
+ gdouble value)
+{
+ GtkAdjustmentPrivate *priv;
+
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ priv = gtk_adjustment_get_private (adjustment);
+
+ priv->start_value = adjustment->value;
+ priv->goal_value = value;
+ g_timer_reset (priv->timer);
+
+ if (!priv->idle_id)
+ priv->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW + 3, adjustment_update_idle, adjustment, NULL);
}
Index: gtkadjustment.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkadjustment.h,v
retrieving revision 1.18
diff -u -p -u -r1.18 gtkadjustment.h
--- gtkadjustment.h 9 Oct 2002 22:25:17 -0000 1.18
+++ gtkadjustment.h 17 Jan 2003 20:04:30 -0000
@@ -75,21 +75,32 @@ struct _GtkAdjustmentClass
};
-GType gtk_adjustment_get_type (void) G_GNUC_CONST;
-GtkObject* gtk_adjustment_new (gdouble value,
- gdouble lower,
- gdouble upper,
- gdouble step_increment,
- gdouble page_increment,
- gdouble page_size);
-void gtk_adjustment_changed (GtkAdjustment *adjustment);
-void gtk_adjustment_value_changed (GtkAdjustment *adjustment);
-void gtk_adjustment_clamp_page (GtkAdjustment *adjustment,
- gdouble lower,
- gdouble upper);
-gdouble gtk_adjustment_get_value (GtkAdjustment *adjustment);
-void gtk_adjustment_set_value (GtkAdjustment *adjustment,
- gdouble value);
+GType gtk_adjustment_get_type (void) G_GNUC_CONST;
+GtkObject* gtk_adjustment_new (gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size);
+void gtk_adjustment_changed (GtkAdjustment *adjustment);
+void gtk_adjustment_value_changed (GtkAdjustment *adjustment);
+void gtk_adjustment_clamp_page (GtkAdjustment *adjustment,
+ gdouble lower,
+ gdouble upper);
+gdouble gtk_adjustment_get_value (GtkAdjustment *adjustment);
+void gtk_adjustment_set_value (GtkAdjustment *adjustment,
+ gdouble value);
+
+void gtk_adjustment_goto_value (GtkAdjustment *adjustment,
+ gdouble value);
+void gtk_adjustment_home (GtkAdjustment *adjustment);
+void gtk_adjustment_end (GtkAdjustment *adjustment);
+void gtk_adjustment_step_up (GtkAdjustment *adjustment);
+void gtk_adjustment_step_down (GtkAdjustment *adjustment);
+void gtk_adjustment_wheel_up (GtkAdjustment *adjustment);
+void gtk_adjustment_wheel_down (GtkAdjustment *adjustment);
+void gtk_adjustment_page_up (GtkAdjustment *adjustment);
+void gtk_adjustment_page_down (GtkAdjustment *adjustment);
#ifdef __cplusplus
}
Index: gtkscrolledwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkscrolledwindow.c,v
retrieving revision 1.66
diff -u -p -u -r1.66 gtkscrolledwindow.c
--- gtkscrolledwindow.c 20 Oct 2002 19:08:17 -0000 1.66
+++ gtkscrolledwindow.c 17 Jan 2003 20:04:34 -0000
@@ -793,98 +793,65 @@ gtk_scrolled_window_scroll_child (GtkScr
GtkScrollType scroll,
gboolean horizontal)
{
- GtkAdjustment *adjustment = NULL;
+ GtkAdjustment *hadj = NULL;
+ GtkAdjustment *vadj = NULL;
+
+ if (scrolled_window->hscrollbar)
+ hadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+
+ if (scrolled_window->vscrollbar)
+ vadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
switch (scroll)
{
case GTK_SCROLL_STEP_UP:
- scroll = GTK_SCROLL_STEP_BACKWARD;
- horizontal = FALSE;
+ case GTK_SCROLL_STEP_BACKWARD:
+ if (vadj)
+ gtk_adjustment_step_up (vadj);
break;
case GTK_SCROLL_STEP_DOWN:
- scroll = GTK_SCROLL_STEP_FORWARD;
- horizontal = FALSE;
+ case GTK_SCROLL_STEP_FORWARD:
+ if (vadj)
+ gtk_adjustment_step_down (vadj);
break;
case GTK_SCROLL_STEP_LEFT:
- scroll = GTK_SCROLL_STEP_BACKWARD;
- horizontal = TRUE;
+ if (hadj)
+ gtk_adjustment_step_up (hadj);
break;
case GTK_SCROLL_STEP_RIGHT:
- scroll = GTK_SCROLL_STEP_FORWARD;
- horizontal = TRUE;
+ if (hadj)
+ gtk_adjustment_step_down (hadj);
break;
case GTK_SCROLL_PAGE_UP:
- scroll = GTK_SCROLL_PAGE_BACKWARD;
- horizontal = FALSE;
+ case GTK_SCROLL_PAGE_BACKWARD:
+ if (vadj)
+ gtk_adjustment_page_up (vadj);
break;
case GTK_SCROLL_PAGE_DOWN:
- scroll = GTK_SCROLL_PAGE_FORWARD;
- horizontal = FALSE;
+ case GTK_SCROLL_PAGE_FORWARD:
+ if (vadj)
+ gtk_adjustment_page_down (vadj);
break;
case GTK_SCROLL_PAGE_LEFT:
- scroll = GTK_SCROLL_STEP_BACKWARD;
- horizontal = TRUE;
+ if (hadj)
+ gtk_adjustment_page_up (hadj);
break;
case GTK_SCROLL_PAGE_RIGHT:
- scroll = GTK_SCROLL_STEP_FORWARD;
- horizontal = TRUE;
+ if (hadj)
+ gtk_adjustment_page_down (hadj);
break;
- case GTK_SCROLL_STEP_BACKWARD:
- case GTK_SCROLL_STEP_FORWARD:
- case GTK_SCROLL_PAGE_BACKWARD:
- case GTK_SCROLL_PAGE_FORWARD:
case GTK_SCROLL_START:
+ if (vadj)
+ gtk_adjustment_home (vadj);
+ break;
case GTK_SCROLL_END:
+ if (vadj)
+ gtk_adjustment_end (vadj);
break;
default:
g_warning ("Invalid scroll type %d for GtkSpinButton::change-value", scroll);
return;
}
-
- if (horizontal)
- {
- if (scrolled_window->hscrollbar)
- adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
- }
- else
- {
- if (scrolled_window->vscrollbar)
- adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
- }
-
- if (adjustment)
- {
- gdouble value = adjustment->value;
-
- switch (scroll)
- {
- case GTK_SCROLL_STEP_FORWARD:
- value += adjustment->step_increment;
- break;
- case GTK_SCROLL_STEP_BACKWARD:
- value -= adjustment->step_increment;
- break;
- case GTK_SCROLL_PAGE_FORWARD:
- value += adjustment->page_increment;
- break;
- case GTK_SCROLL_PAGE_BACKWARD:
- value -= adjustment->page_increment;
- break;
- case GTK_SCROLL_START:
- value = adjustment->lower;
- break;
- case GTK_SCROLL_END:
- value = adjustment->upper;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- value = CLAMP (value, adjustment->lower, adjustment->upper - adjustment->page_size);
-
- gtk_adjustment_set_value (adjustment, value);
- }
}
static void
@@ -1214,16 +1181,17 @@ gtk_scrolled_window_scroll_event (GtkWid
if (range && GTK_WIDGET_VISIBLE (range))
{
- GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
- gdouble new_value;
+ GtkAdjustment *adjustment = GTK_RANGE (range)->adjustment;
- if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT)
- new_value = adj->value - adj->page_increment / 2;
+ if (event->direction == GDK_SCROLL_UP ||
+ event->direction == GDK_SCROLL_LEFT)
+ {
+ gtk_adjustment_wheel_up (adjustment);
+ }
else
- new_value = adj->value + adj->page_increment / 2;
-
- new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
- gtk_adjustment_set_value (adj, new_value);
+ {
+ gtk_adjustment_wheel_down (adjustment);
+ }
return TRUE;
}
Index: gtkrange.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrange.c,v
retrieving revision 1.88
diff -u -p -u -r1.88 gtkrange.c
--- gtkrange.c 4 Oct 2002 08:02:14 -0000 1.88
+++ gtkrange.c 17 Jan 2003 20:04:40 -0000
@@ -31,9 +31,10 @@
#include "gtkmarshalers.h"
#include "gtkrange.h"
#include "gtkintl.h"
+#include <math.h>
-#define SCROLL_INITIAL_DELAY 250 /* must hold button this long before ... */
-#define SCROLL_LATER_DELAY 100 /* ... it starts repeating at this rate */
+#define SCROLL_INITIAL_DELAY 225 /* must hold button this long before ... */
+#define SCROLL_LATER_DELAY 75 /* ... it starts repeating at this rate */
#define UPDATE_DELAY 300 /* Delay for queued update */
enum {
@@ -693,6 +694,12 @@ should_invert (GtkRange *range)
return range->inverted;
}
+static gboolean
+can_be_smooth (GtkRange *range)
+{
+ return (range->round_digits < 0 && range->update_policy == GTK_UPDATE_CONTINUOUS);
+}
+
static void
gtk_range_finalize (GObject *object)
{
@@ -1365,22 +1372,52 @@ gtk_range_scroll_event (GtkWidget *
if (GTK_WIDGET_REALIZED (range))
{
GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
- gdouble increment = ((event->direction == GDK_SCROLL_UP ||
- event->direction == GDK_SCROLL_LEFT) ?
- -adj->page_increment / 2:
- adj->page_increment / 2);
-
- if (range->inverted)
- increment = -increment;
+ GdkScrollDirection direction = event->direction;
- gtk_range_internal_set_value (range, adj->value + increment);
+ if (direction == GDK_SCROLL_UP ||
+ direction == GDK_SCROLL_LEFT)
+ {
+ direction = GDK_SCROLL_UP;
+ }
+ else
+ {
+ direction = GDK_SCROLL_DOWN;
+ }
+
+ if (should_invert (range))
+ {
+ if (direction == GDK_SCROLL_UP)
+ direction = GDK_SCROLL_DOWN;
+ else
+ direction = GDK_SCROLL_UP;
+ }
- /* Policy DELAYED makes sense with scroll events,
- * but DISCONTINUOUS doesn't, so we update immediately
- * for DISCONTINOUS
- */
- if (range->update_policy == GTK_UPDATE_DISCONTINUOUS)
- gtk_range_update_value (range);
+ if (can_be_smooth (range))
+ {
+ if (direction == GDK_SCROLL_UP)
+ gtk_adjustment_wheel_up (adj);
+ else
+ gtk_adjustment_wheel_down (adj);
+
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ {
+ gdouble increment = pow (adj->page_size, 2.0/3.0);
+
+ if (direction == GDK_SCROLL_UP)
+ increment *= -1;
+
+ gtk_range_internal_set_value (range, adj->value + increment);
+
+ /* Policy DELAYED makes sense with scroll events,
+ * but DISCONTINUOUS doesn't, so we update immediately
+ * for DISCONTINUOUS
+ */
+ if (range->update_policy == GTK_UPDATE_DISCONTINUOUS)
+ gtk_range_update_value (range);
+ }
}
return TRUE;
@@ -1496,40 +1533,81 @@ gtk_range_style_set (GtkWidget *widget,
static void
step_back (GtkRange *range)
{
- gdouble newval;
-
- newval = range->adjustment->value - range->adjustment->step_increment;
- gtk_range_internal_set_value (range, newval);
+ GtkAdjustment *adj = range->adjustment;
+
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_step_up (adj);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ {
+ gdouble newval;
+
+ newval = adj->value - adj->step_increment;
+ gtk_range_internal_set_value (range, newval);
+ }
}
static void
step_forward (GtkRange *range)
{
- gdouble newval;
+ GtkAdjustment *adj = range->adjustment;
- newval = range->adjustment->value + range->adjustment->step_increment;
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_step_down (adj);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ {
+ gdouble newval;
- gtk_range_internal_set_value (range, newval);
+ newval = adj->value + adj->step_increment;
+ gtk_range_internal_set_value (range, newval);
+ }
}
-
static void
page_back (GtkRange *range)
{
- gdouble newval;
+ GtkAdjustment *adj = range->adjustment;
+
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_page_up (adj);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ {
+ gdouble newval;
- newval = range->adjustment->value - range->adjustment->page_increment;
- gtk_range_internal_set_value (range, newval);
+ newval = adj->value - adj->page_increment;
+ gtk_range_internal_set_value (range, newval);
+ }
}
static void
page_forward (GtkRange *range)
{
- gdouble newval;
+ GtkAdjustment *adj = range->adjustment;
- newval = range->adjustment->value + range->adjustment->page_increment;
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_page_down (adj);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ {
+ gdouble newval;
- gtk_range_internal_set_value (range, newval);
+ newval = adj->value - adj->page_increment;
+ gtk_range_internal_set_value (range, newval);
+ }
}
static void
@@ -1611,13 +1689,27 @@ gtk_range_scroll (GtkRange *range,
break;
case GTK_SCROLL_START:
- gtk_range_internal_set_value (range,
- range->adjustment->lower);
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_home (range->adjustment);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ gtk_range_internal_set_value (range,
+ range->adjustment->lower);
break;
case GTK_SCROLL_END:
- gtk_range_internal_set_value (range,
- range->adjustment->upper - range->adjustment->page_size);
+ if (can_be_smooth (range))
+ {
+ gtk_adjustment_end (range->adjustment);
+ range->need_recalc = TRUE;
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+ else
+ gtk_range_internal_set_value (range,
+ range->adjustment->upper - range->adjustment->page_size);
break;
case GTK_SCROLL_JUMP:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]