diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-06-28 02:28:29 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-06-29 02:11:18 -0400 |
commit | b457c1d7cd88accb22c690b69baefe8a48d805ff (patch) | |
tree | bb1c691c1514114a03975b1dba2660b9298be4aa | |
parent | b3b861c9d652f35ef865ef642a435291993adca0 (diff) | |
download | gtk+-b457c1d7cd88accb22c690b69baefe8a48d805ff.tar.gz |
Proof-of-concept: Animated scrolling
This is a proof-of-concept patch to make scrolled windows animate
motion. The implementation of the tick callback is in GtkAdjustment,
so we can animate both scrollbar clicks and key bindings.
Still to do: figure out what to do about duration - does it need to
depend on the distance of the jump ? Is the easing function the right
choice ? Do we want to animate all range jumps, or just scrollbars ?
https://bugzilla.gnome.org/show_bug.cgi?id=732376
-rw-r--r-- | gtk/Makefile.am | 1 | ||||
-rw-r--r-- | gtk/gtkadjustment.c | 137 | ||||
-rw-r--r-- | gtk/gtkadjustmentprivate.h | 34 | ||||
-rw-r--r-- | gtk/gtkscrolledwindow.c | 31 |
4 files changed, 197 insertions, 6 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 39284111fa..cdb4a20d2f 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -498,6 +498,7 @@ gtk_private_h_sources = \ gtkactionmuxer.h \ gtkactionobserver.h \ gtkactionobservable.h \ + gtkadjustmentprivate.h \ gtkapplicationprivate.h \ gtkaccelgroupprivate.h \ gtkaccelmapprivate.h \ diff --git a/gtk/gtkadjustment.c b/gtk/gtkadjustment.c index 9a5087dd23..51714177dd 100644 --- a/gtk/gtkadjustment.c +++ b/gtk/gtkadjustment.c @@ -57,6 +57,15 @@ struct _GtkAdjustmentPrivate { gdouble step_increment; gdouble page_increment; gdouble page_size; + + gdouble source; + gdouble target; + + guint duration; + gint64 start_time; + gint64 end_time; + guint tick_id; + GdkFrameClock *clock; }; enum @@ -97,10 +106,25 @@ static guint64 adjustment_changed_stamp = 0; /* protected by global gdk lock */ G_DEFINE_TYPE_WITH_PRIVATE (GtkAdjustment, gtk_adjustment, G_TYPE_INITIALLY_UNOWNED) static void +gtk_adjustment_finalize (GObject *object) +{ + GtkAdjustment *adjustment = GTK_ADJUSTMENT (object); + GtkAdjustmentPrivate *priv = adjustment->priv; + + if (priv->tick_id) + g_signal_handler_disconnect (priv->clock, priv->tick_id); + if (priv->clock) + g_object_unref (priv->clock); + + G_OBJECT_CLASS (gtk_adjustment_parent_class)->finalize (object); +} + +static void gtk_adjustment_class_init (GtkAdjustmentClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = gtk_adjustment_finalize; gobject_class->set_property = gtk_adjustment_set_property; gobject_class->get_property = gtk_adjustment_get_property; gobject_class->dispatch_properties_changed = gtk_adjustment_dispatch_properties_changed; @@ -404,6 +428,95 @@ gtk_adjustment_get_value (GtkAdjustment *adjustment) return adjustment->priv->value; } +static void +adjustment_set_value (GtkAdjustment *adjustment, + gdouble value) +{ + if (value != adjustment->priv->value) + { + adjustment->priv->value = value; + gtk_adjustment_value_changed (adjustment); + } +} + +/* From clutter-easing.c, based on Robert Penner's + * infamous easing equations, MIT license. + */ +static gdouble +ease_out_cubic (gdouble t) +{ + gdouble p = t - 1; + + return p * p * p + 1; +} + +static gboolean +gtk_adjustment_animate_step (GtkAdjustment *adjustment, + gint64 now) +{ + GtkAdjustmentPrivate *priv = adjustment->priv; + + if (now < priv->end_time) + { + gdouble t; + + t = (now - priv->start_time) / (gdouble) (priv->end_time - priv->start_time); + t = ease_out_cubic (t); + adjustment_set_value (adjustment, priv->source + t * (priv->target - priv->source)); + + return TRUE; + } + else + { + adjustment_set_value (adjustment, priv->target); + + return FALSE; + } +} + +static void +gtk_adjustment_on_frame_clock_update (GdkFrameClock *clock, + GtkAdjustment *adjustment) +{ + GtkAdjustmentPrivate *priv = adjustment->priv; + gint64 now; + + now = gdk_frame_clock_get_frame_time (clock); + if (!gtk_adjustment_animate_step (adjustment, now)) + { + g_signal_handler_disconnect (priv->clock, priv->tick_id); + priv->tick_id = 0; + gdk_frame_clock_end_updating (priv->clock); + } +} + +static void +gtk_adjustment_maybe_animate (GtkAdjustment *adjustment, + gdouble target) +{ + GtkAdjustmentPrivate *priv = adjustment->priv; + + if (priv->target == target) + return; + + priv->target = target; + + if (priv->duration != 0 && priv->clock != NULL) + { + priv->source = priv->value; + priv->start_time = gdk_frame_clock_get_frame_time (priv->clock); + priv->end_time = priv->start_time + 1000 * priv->duration; + if (priv->tick_id == 0) + { + priv->tick_id = g_signal_connect (priv->clock, "update", + G_CALLBACK (gtk_adjustment_on_frame_clock_update), adjustment); + gdk_frame_clock_begin_updating (priv->clock); + } + } + else + adjustment_set_value (adjustment, target); +} + /** * gtk_adjustment_set_value: * @adjustment: a #GtkAdjustment. @@ -432,12 +545,7 @@ gtk_adjustment_set_value (GtkAdjustment *adjustment, value = MIN (value, priv->upper - priv->page_size); value = MAX (value, priv->lower); - if (value != priv->value) - { - priv->value = value; - - gtk_adjustment_value_changed (adjustment); - } + gtk_adjustment_maybe_animate (adjustment, value); } /** @@ -847,3 +955,20 @@ gtk_adjustment_get_minimum_increment (GtkAdjustment *adjustment) return minimum_increment; } +void +gtk_adjustment_enable_animation (GtkAdjustment *adjustment, + GdkFrameClock *clock, + guint duration) +{ + GtkAdjustmentPrivate *priv = adjustment->priv; + + if (priv->clock) + g_object_unref (priv->clock); + + priv->clock = clock; + + if (priv->clock) + g_object_ref (priv->clock); + + priv->duration = duration; +} diff --git a/gtk/gtkadjustmentprivate.h b/gtk/gtkadjustmentprivate.h new file mode 100644 index 0000000000..bc9c810152 --- /dev/null +++ b/gtk/gtkadjustmentprivate.h @@ -0,0 +1,34 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2014 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GTK_ADJUSTMENT_PRIVATE_H__ +#define __GTK_ADJUSTMENT_PRIVATE_H__ + + +#include <gtk/gtkadjustment.h> + + +G_BEGIN_DECLS + +void gtk_adjustment_enable_animation (GtkAdjustment *adjustment, + GdkFrameClock *clock, + guint duration); + +G_END_DECLS + + +#endif /* __GTK_ADJUSTMENT_PRIVATE_H__ */ diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index f9d9e29b6a..db23f2d8fe 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -27,6 +27,7 @@ #include "gtkscrolledwindow.h" #include "gtkadjustment.h" +#include "gtkadjustmentprivate.h" #include "gtkbindings.h" #include "gtkdnd.h" #include "gtkintl.h" @@ -3123,12 +3124,40 @@ gtk_scrolled_window_unrealize (GtkWidget *widget) } static void +gtk_scrolled_window_enable_animation (GtkScrolledWindow *sw) +{ + GtkAdjustment *adjustment; + GdkFrameClock *clock; + + clock = gtk_widget_get_frame_clock (GTK_WIDGET (sw)), + adjustment = gtk_range_get_adjustment (GTK_RANGE (sw->priv->hscrollbar)); + gtk_adjustment_enable_animation (adjustment, clock, 200); + + adjustment = gtk_range_get_adjustment (GTK_RANGE (sw->priv->vscrollbar)); + gtk_adjustment_enable_animation (adjustment, clock, 200); +} + +static void +gtk_scrolled_window_disable_animation (GtkScrolledWindow *sw) +{ + GtkAdjustment *adjustment; + + adjustment = gtk_range_get_adjustment (GTK_RANGE (sw->priv->hscrollbar)); + gtk_adjustment_enable_animation (adjustment, NULL, 0); + + adjustment = gtk_range_get_adjustment (GTK_RANGE (sw->priv->vscrollbar)); + gtk_adjustment_enable_animation (adjustment, NULL, 0); +} + +static void gtk_scrolled_window_map (GtkWidget *widget) { GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget); gdk_window_show (scrolled_window->priv->overshoot_window); + gtk_scrolled_window_enable_animation (scrolled_window); + GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget); } @@ -3137,6 +3166,8 @@ gtk_scrolled_window_unmap (GtkWidget *widget) { GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget); + gtk_scrolled_window_disable_animation (scrolled_window); + gdk_window_hide (scrolled_window->priv->overshoot_window); GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget); |