[libadwaita/wip/exalm/demo-cleanups: 17/21] demo: Split animations page into a separate class




commit 30d1855b88acc1362aee0987b5aa3e3945327427
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Thu Dec 9 19:12:47 2021 +0500

    demo: Split animations page into a separate class

 demo/adw-demo-window.c                            | 394 +--------------------
 demo/adw-demo-window.ui                           | 372 +-------------------
 demo/adwaita-demo.gresources.xml                  |   1 +
 demo/meson.build                                  |   1 +
 demo/pages/animations/adw-demo-page-animations.c  | 409 ++++++++++++++++++++++
 demo/pages/animations/adw-demo-page-animations.h  |  11 +
 demo/pages/animations/adw-demo-page-animations.ui | 379 ++++++++++++++++++++
 7 files changed, 804 insertions(+), 763 deletions(-)
---
diff --git a/demo/adw-demo-window.c b/demo/adw-demo-window.c
index 08a4ad4a..85422dc5 100644
--- a/demo/adw-demo-window.c
+++ b/demo/adw-demo-window.c
@@ -1,6 +1,7 @@
 #include "adw-demo-window.h"
 
 #include <glib/gi18n.h>
+#include "pages/animations/adw-demo-page-animations.h"
 #include "pages/avatar/adw-demo-page-avatar.h"
 #include "pages/buttons/adw-demo-page-buttons.h"
 #include "pages/carousel/adw-demo-page-carousel.h"
@@ -25,33 +26,10 @@ struct _AdwDemoWindow
   GtkStack *stack;
   AdwLeaflet *subpage_leaflet;
   AdwDemoPageToasts *toasts_page;
-  GtkStack *animation_preferences_stack;
-  AdwAnimation *timed_animation;
-  GtkWidget *timed_animation_sample;
-  GtkWidget *timed_animation_button_box;
-  GtkSpinButton *timed_animation_repeat_count;
-  GtkSwitch *timed_animation_reverse;
-  GtkSwitch *timed_animation_alternate;
-  GtkSpinButton *timed_animation_duration;
-  AdwComboRow *timed_animation_easing;
-  AdwAnimation *spring_animation;
-  GtkSpinButton *spring_animation_velocity;
-  GtkSpinButton *spring_animation_damping;
-  GtkSpinButton *spring_animation_mass;
-  GtkSpinButton *spring_animation_stiffness;
-  GtkSpinButton *spring_animation_epsilon;
-  GtkSwitch *spring_animation_clamp_switch;
 };
 
 G_DEFINE_TYPE (AdwDemoWindow, adw_demo_window, ADW_TYPE_APPLICATION_WINDOW)
 
-enum {
-  PROP_0,
-  PROP_TIMED_ANIMATION,
-  PROP_SPRING_ANIMATION,
-  LAST_PROP,
-};
-
 static char *
 get_color_scheme_icon_name (gpointer user_data,
                             gboolean dark)
@@ -59,52 +37,6 @@ get_color_scheme_icon_name (gpointer user_data,
   return g_strdup (dark ? "light-mode-symbolic" : "dark-mode-symbolic");
 }
 
-static GParamSpec *props[LAST_PROP];
-
-static void
-adw_demo_window_get_property (GObject    *object,
-                              guint       prop_id,
-                              GValue     *value,
-                              GParamSpec *pspec)
-{
-  AdwDemoWindow *self = ADW_DEMO_WINDOW (object);
-
-  switch (prop_id) {
-  case PROP_TIMED_ANIMATION:
-    g_value_set_object (value, self->timed_animation);
-    break;
-
-  case PROP_SPRING_ANIMATION:
-    g_value_set_object (value, self->spring_animation);
-    break;
-
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-  }
-}
-
-static void
-adw_demo_window_set_property (GObject      *object,
-                              guint         prop_id,
-                              const GValue *value,
-                              GParamSpec   *pspec)
-{
-  AdwDemoWindow *self = ADW_DEMO_WINDOW (object);
-
-  switch (prop_id) {
-  case PROP_TIMED_ANIMATION:
-    g_set_object (&self->timed_animation, g_value_get_object (value));
-    break;
-
-  case PROP_SPRING_ANIMATION:
-    g_set_object (&self->spring_animation, g_value_get_object (value));
-    break;
-
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-  }
-}
-
 static void
 color_scheme_button_clicked_cb (AdwDemoWindow *self)
 {
@@ -162,223 +94,6 @@ adw_demo_window_new (GtkApplication *application)
   return g_object_new (ADW_TYPE_DEMO_WINDOW, "application", application, NULL);
 }
 
-static AdwAnimation *
-get_current_animation (AdwDemoWindow *self)
-{
-  const char *current_animation;
-
-  current_animation = gtk_stack_get_visible_child_name (self->animation_preferences_stack);
-
-  if (!g_strcmp0 (current_animation, "Timed")) {
-    return self->timed_animation;
-  } else if (!g_strcmp0 (current_animation, "Spring")) {
-    return self->spring_animation;
-  } else {
-    g_assert_not_reached ();
-  }
-}
-
-static char *
-animations_easing_name (AdwEnumListItem *value,
-                        gpointer         user_data)
-{
-  g_return_val_if_fail (ADW_IS_ENUM_LIST_ITEM (value), NULL);
-
-  switch (adw_enum_list_item_get_value (value)) {
-  case ADW_LINEAR:
-    return g_strdup (_("Linear"));
-  case ADW_EASE_IN_QUAD:
-    return g_strdup (_("Ease-in (Quadratic)"));
-  case ADW_EASE_OUT_QUAD:
-    return g_strdup (_("Ease-out (Quadratic)"));
-  case ADW_EASE_IN_OUT_QUAD:
-    return g_strdup (_("Ease-in-out (Quadratic)"));
-  case ADW_EASE_IN_CUBIC:
-    return g_strdup (_("Ease-in (Cubic)"));
-  case ADW_EASE_OUT_CUBIC:
-    return g_strdup (_("Ease-out (Cubic)"));
-  case ADW_EASE_IN_OUT_CUBIC:
-    return g_strdup (_("Ease-in-out (Cubic)"));
-  case ADW_EASE_IN_QUART:
-    return g_strdup (_("Ease-in (Quartic)"));
-  case ADW_EASE_OUT_QUART:
-    return g_strdup (_("Ease-out (Quartic)"));
-  case ADW_EASE_IN_OUT_QUART:
-    return g_strdup (_("Ease-in-out (Quartic)"));
-  case ADW_EASE_IN_QUINT:
-    return g_strdup (_("Ease-in (Quintic)"));
-  case ADW_EASE_OUT_QUINT:
-    return g_strdup (_("Ease-out (Quintic)"));
-  case ADW_EASE_IN_OUT_QUINT:
-    return g_strdup (_("Ease-in-out (Quintic)"));
-  case ADW_EASE_IN_SINE:
-    return g_strdup (_("Ease-in (Sine)"));
-  case ADW_EASE_OUT_SINE:
-    return g_strdup (_("Ease-out (Sine)"));
-  case ADW_EASE_IN_OUT_SINE:
-    return g_strdup (_("Ease-in-out (Sine)"));
-  case ADW_EASE_IN_EXPO:
-    return g_strdup (_("Ease-in (Exponential)"));
-  case ADW_EASE_OUT_EXPO:
-    return g_strdup (_("Ease-out (Exponential)"));
-  case ADW_EASE_IN_OUT_EXPO:
-    return g_strdup (_("Ease-in-out (Exponential)"));
-  case ADW_EASE_IN_CIRC:
-    return g_strdup (_("Ease-in (Circular)"));
-  case ADW_EASE_OUT_CIRC:
-    return g_strdup (_("Ease-out (Circular)"));
-  case ADW_EASE_IN_OUT_CIRC:
-    return g_strdup (_("Ease-in-out (Circular)"));
-  case ADW_EASE_IN_ELASTIC:
-    return g_strdup (_("Ease-in (Elastic)"));
-  case ADW_EASE_OUT_ELASTIC:
-    return g_strdup (_("Ease-out (Elastic)"));
-  case ADW_EASE_IN_OUT_ELASTIC:
-    return g_strdup (_("Ease-in-out (Elastic)"));
-  case ADW_EASE_IN_BACK:
-    return g_strdup (_("Ease-in (Back)"));
-  case ADW_EASE_OUT_BACK:
-    return g_strdup (_("Ease-out (Back)"));
-  case ADW_EASE_IN_OUT_BACK:
-    return g_strdup (_("Ease-in-out (Back)"));
-  case ADW_EASE_IN_BOUNCE:
-    return g_strdup (_("Ease-in (Bounce)"));
-  case ADW_EASE_OUT_BOUNCE:
-    return g_strdup (_("Ease-out (Bounce)"));
-  case ADW_EASE_IN_OUT_BOUNCE:
-    return g_strdup (_("Ease-in-out (Bounce)"));
-  default:
-    return NULL;
-  }
-}
-
-static void
-timed_animation_measure (GtkWidget      *widget,
-                         GtkOrientation  orientation,
-                         int             for_size,
-                         int            *minimum,
-                         int            *natural,
-                         int            *minimum_baseline,
-                         int            *natural_baseline)
-{
-  GtkWidget *child = gtk_widget_get_first_child (widget);
-
-  if (!child)
-    return;
-
-  gtk_widget_measure (child, orientation, for_size, minimum, natural,
-                      minimum_baseline, natural_baseline);
-}
-
-static void
-timed_animation_allocate (GtkWidget *widget,
-                          int        width,
-                          int        height,
-                          int        baseline)
-{
-  AdwDemoWindow *self = ADW_DEMO_WINDOW (gtk_widget_get_root (widget));
-  GtkWidget *child = gtk_widget_get_first_child (widget);
-  AdwAnimation *animation = get_current_animation (self);
-  double progress;
-  int child_width, offset;
-
-  if (!child)
-    return;
-
-  progress = adw_animation_get_value (animation);
-
-  gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1,
-                      &child_width, NULL, NULL, NULL);
-
-  offset = (int) ((width - child_width) * (progress - 0.5));
-
-  gtk_widget_allocate (child, width, height, baseline,
-                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (offset, 0)));
-}
-
-static void
-timed_animation_reset (AdwDemoWindow *self)
-{
-  adw_animation_reset (self->timed_animation);
-  adw_animation_reset (self->spring_animation);
-}
-
-static void
-timed_animation_play_pause (AdwDemoWindow *self)
-{
-  AdwAnimation *animation = get_current_animation (self);
-
-  switch (adw_animation_get_state (animation)) {
-  case ADW_ANIMATION_IDLE:
-  case ADW_ANIMATION_FINISHED:
-    adw_animation_play (animation);
-    break;
-  case ADW_ANIMATION_PAUSED:
-    adw_animation_resume (animation);
-    break;
-  case ADW_ANIMATION_PLAYING:
-    adw_animation_pause (animation);
-    break;
-  default:
-    g_assert_not_reached ();
-  }
-
-}
-
-static void
-timed_animation_skip (AdwDemoWindow *self)
-{
-  adw_animation_skip (self->timed_animation);
-  adw_animation_skip (self->spring_animation);
-}
-
-static char *
-get_play_pause_icon_name (gpointer          user_data,
-                           AdwAnimationState timed_state,
-                           AdwAnimationState spring_state)
-{
-  gboolean playing = timed_state  == ADW_ANIMATION_PLAYING ||
-                     spring_state == ADW_ANIMATION_PLAYING;
-
-  return g_strdup (playing ? "media-playback-pause-symbolic" : "media-playback-start-symbolic");
-}
-
-static gboolean
-timed_animation_can_reset (gpointer          user_data,
-                           AdwAnimationState timed_state,
-                           AdwAnimationState spring_state)
-{
-  return timed_state  != ADW_ANIMATION_IDLE ||
-         spring_state != ADW_ANIMATION_IDLE;
-}
-
-static gboolean
-timed_animation_can_skip (gpointer          user_data,
-                          AdwAnimationState timed_state,
-                          AdwAnimationState spring_state)
-{
-  return timed_state  != ADW_ANIMATION_FINISHED &&
-         spring_state != ADW_ANIMATION_FINISHED;
-}
-
-static void
-timed_animation_cb (double     value,
-                    GtkWidget *self)
-{
-  gtk_widget_queue_allocate (self);
-}
-
-static void
-notify_spring_params_change (AdwDemoWindow *self)
-{
-  g_autoptr (AdwSpringParams) spring_params =
-    adw_spring_params_new_full (gtk_spin_button_get_value (self->spring_animation_damping),
-                                gtk_spin_button_get_value (self->spring_animation_mass),
-                                gtk_spin_button_get_value (self->spring_animation_stiffness));
-
-  adw_spring_animation_set_spring_params (ADW_SPRING_ANIMATION (self->spring_animation), spring_params);
-}
-
 static void
 toast_undo_cb (AdwDemoWindow *self)
 {
@@ -388,12 +103,8 @@ toast_undo_cb (AdwDemoWindow *self)
 static void
 adw_demo_window_class_init (AdwDemoWindowClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->set_property = adw_demo_window_set_property;
-  object_class->get_property = adw_demo_window_get_property;
-
   gtk_widget_class_add_binding_action (widget_class, GDK_KEY_q, GDK_CONTROL_MASK, "window.close", NULL);
 
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Adwaita1/Demo/ui/adw-demo-window.ui");
@@ -404,121 +115,22 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, stack);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, subpage_leaflet);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, toasts_page);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, animation_preferences_stack);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_sample);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_button_box);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_repeat_count);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_reverse);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_alternate);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_duration);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_easing);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_velocity);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_damping);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_mass);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_stiffness);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_epsilon);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, spring_animation_clamp_switch);
   gtk_widget_class_bind_template_callback (widget_class, notify_visible_child_cb);
   gtk_widget_class_bind_template_callback (widget_class, back_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, leaflet_back_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, leaflet_next_page_cb);
   gtk_widget_class_bind_template_callback (widget_class, get_color_scheme_icon_name);
   gtk_widget_class_bind_template_callback (widget_class, color_scheme_button_clicked_cb);
-  gtk_widget_class_bind_template_callback (widget_class, animations_easing_name);
-  gtk_widget_class_bind_template_callback (widget_class, timed_animation_reset);
-  gtk_widget_class_bind_template_callback (widget_class, timed_animation_play_pause);
-  gtk_widget_class_bind_template_callback (widget_class, timed_animation_skip);
-  gtk_widget_class_bind_template_callback (widget_class, get_play_pause_icon_name);
-  gtk_widget_class_bind_template_callback (widget_class, timed_animation_can_reset);
-  gtk_widget_class_bind_template_callback (widget_class, timed_animation_can_skip);
-  gtk_widget_class_bind_template_callback (widget_class, notify_spring_params_change);
-
-  props[PROP_TIMED_ANIMATION] =
-    g_param_spec_object ("timed_animation",
-                         "Timed animation",
-                         "Timed animation",
-                         ADW_TYPE_ANIMATION,
-                         G_PARAM_READWRITE);
-
-  props[PROP_SPRING_ANIMATION] =
-    g_param_spec_object ("spring_animation",
-                         "Spring animation",
-                         "Spring animation",
-                         ADW_TYPE_ANIMATION,
-                         G_PARAM_READWRITE);
-
-  g_object_class_install_properties (object_class, LAST_PROP, props);
 
   gtk_widget_class_install_action (widget_class, "toast.undo", NULL, (GtkWidgetActionActivateFunc) 
toast_undo_cb);
 }
 
-static void
-animation_page_init (AdwDemoWindow *self)
-{
-  GtkLayoutManager *manager;
-  AdwAnimationTarget *target;
-
-  target = adw_callback_animation_target_new ((AdwAnimationTargetFunc)
-                                              timed_animation_cb,
-                                              self->timed_animation_sample,
-                                              NULL);
-
-  self->timed_animation =
-    adw_timed_animation_new (GTK_WIDGET (self->timed_animation_sample),
-                             0, 1, 100, g_object_ref (target));
-
-  self->spring_animation =
-    adw_spring_animation_new (GTK_WIDGET (self->timed_animation_sample), 0, 1,
-                              adw_spring_params_new_full (10, 1, 100),
-                              target);
-
-  notify_spring_params_change (self);
-
-  g_object_bind_property (self->timed_animation_repeat_count, "value",
-                          self->timed_animation, "repeat-count",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->timed_animation_reverse, "state",
-                          self->timed_animation, "reverse",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->timed_animation_alternate, "state",
-                          self->timed_animation, "alternate",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->timed_animation_duration, "value",
-                          self->timed_animation, "duration",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->timed_animation_easing, "selected",
-                          self->timed_animation, "easing",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-
-  g_object_bind_property (self->spring_animation_velocity, "value",
-                          self->spring_animation, "initial_velocity",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->spring_animation_epsilon, "value",
-                          self->spring_animation, "epsilon",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (self->spring_animation_clamp_switch, "active",
-                          self->spring_animation, "clamp",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-
-  adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->timed_animation),
-                                  ADW_EASE_IN_OUT_CUBIC);
-
-  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIMED_ANIMATION]);
-  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SPRING_ANIMATION]);
-
-  manager = gtk_custom_layout_new (NULL, timed_animation_measure,
-                                   timed_animation_allocate);
-
-  gtk_widget_set_layout_manager (self->timed_animation_sample, manager);
-
-  gtk_widget_set_direction (self->timed_animation_button_box, GTK_TEXT_DIR_LTR);
-}
-
 static void
 adw_demo_window_init (AdwDemoWindow *self)
 {
   AdwStyleManager *manager = adw_style_manager_get_default ();
 
+  g_type_ensure (ADW_TYPE_DEMO_PAGE_ANIMATIONS);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_AVATAR);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_BUTTONS);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_CAROUSEL);
@@ -543,6 +155,4 @@ adw_demo_window_init (AdwDemoWindow *self)
   notify_system_supports_color_schemes_cb (self);
 
   adw_leaflet_set_visible_child (self->content_box, GTK_WIDGET (self->right_box));
-
-  animation_page_init (self);
 }
diff --git a/demo/adw-demo-window.ui b/demo/adw-demo-window.ui
index 9d769d8d..f4ad1256 100644
--- a/demo/adw-demo-window.ui
+++ b/demo/adw-demo-window.ui
@@ -210,379 +210,9 @@
                         </child>
                         <child>
                           <object class="GtkStackPage">
-                            <property name="name">animations</property>
                             <property name="title" translatable="yes">Animations</property>
                             <property name="child">
-                              <object class="GtkScrolledWindow">
-                                <property name="hscrollbar-policy">never</property>
-                                <property name="child">
-                                  <object class="GtkViewport">
-                                    <property name="scroll-to-focus">True</property>
-                                    <property name="child">
-                                      <object class="GtkBox">
-                                        <property name="orientation">vertical</property>
-                                        <property name="valign">center</property>
-                                        <style>
-                                          <class name="timed-animation-page"/>
-                                        </style>
-                                        <child>
-                                          <object class="GtkBox">
-                                            <property name="orientation">vertical</property>
-                                            <child>
-                                              <object class="AdwClamp">
-                                                <property name="maximum-size">400</property>
-                                                <property name="tightening-threshold">300</property>
-                                                <property name="child">
-                                                  <object class="AdwBin" id="timed_animation_sample">
-                                                    <property name="margin-bottom">36</property>
-                                                    <property name="child">
-                                                      <object class="AdwBin" id="timed_animation_widget">
-                                                        <property name="halign">center</property>
-                                                        <property name="valign">center</property>
-                                                        <property name="name">animation-sample</property>
-                                                      </object>
-                                                    </property>
-                                                  </object>
-                                                </property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkLabel">
-                                                <property name="label" 
translatable="yes">Animations</property>
-                                                <property name="wrap">True</property>
-                                                <property name="wrap-mode">word-char</property>
-                                                <property name="justify">center</property>
-                                                <style>
-                                                  <class name="title"/>
-                                                  <class name="title-1"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkLabel">
-                                                <property name="label" translatable="yes">Simple 
transitions.</property>
-                                                <property name="justify">center</property>
-                                                <property name="use_markup">true</property>
-                                                <property name="wrap">True</property>
-                                                <style>
-                                                  <class name="body"/>
-                                                  <class name="description"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child>
-                                          <object class="GtkBox" id="timed_animation_button_box">
-                                            <property name="valign">center</property>
-                                            <property name="halign">center</property>
-                                            <property name="margin-top">30</property>
-                                            <property name="margin-bottom">30</property>
-                                            <property name="spacing">18</property>
-                                            <child>
-                                              <object class="GtkButton">
-                                                <property 
name="icon-name">media-skip-backward-symbolic</property>
-                                                <property name="valign">center</property>
-                                                <binding name="sensitive">
-                                                  <closure type="gboolean" 
function="timed_animation_can_reset">
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="timed-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="spring-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                  </closure>
-                                                </binding>
-                                                <signal name="clicked" handler="timed_animation_reset" 
swapped="true"/>
-                                                <style>
-                                                  <class name="circular"/>
-                                                  <class name="flat"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkButton">
-                                                <binding name="icon-name">
-                                                  <closure type="gchararray" 
function="get_play_pause_icon_name">
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="timed-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="spring-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                  </closure>
-                                                </binding>
-                                                <property name="width-request">48</property>
-                                                <property name="height-request">48</property>
-                                                <signal name="clicked" handler="timed_animation_play_pause" 
swapped="true"/>
-                                                <style>
-                                                  <class name="circular"/>
-                                                  <class name="suggested-action"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkButton">
-                                                <property 
name="icon-name">media-skip-forward-symbolic</property>
-                                                <property name="valign">center</property>
-                                                <binding name="sensitive">
-                                                  <closure type="gboolean" 
function="timed_animation_can_skip">
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="timed-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                    <lookup name="state" type="AdwAnimation">
-                                                      <lookup name="spring-animation">AdwDemoWindow</lookup>
-                                                    </lookup>
-                                                  </closure>
-                                                </binding>
-                                                <signal name="clicked" handler="timed_animation_skip" 
swapped="true"/>
-                                                <style>
-                                                  <class name="circular"/>
-                                                  <class name="flat"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child>
-                                          <object class="AdwPreferencesGroup">
-                                            <child>
-                                              <object class="GtkStackSwitcher">
-                                                <property name="stack">animation_preferences_stack</property>
-                                                <property name="margin-bottom">32</property>
-                                                <property name="halign">center</property>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child>
-                                          <object class="AdwClamp">
-                                            <property name="maximum-size">400</property>
-                                            <property name="tightening-threshold">300</property>
-                                            <property name="child">
-                                              <object class="GtkStack" id="animation_preferences_stack">
-                                                <signal name="notify::visible-child-name" 
handler="timed_animation_reset" swapped="true"/>
-                                                <child>
-                                                  <object class="GtkStackPage">
-                                                    <property name="title" 
translatable="yes">Timed</property>
-                                                    <property name="name">Timed</property>
-                                                    <property name="child">
-                                                      <object class="AdwPreferencesGroup">
-                                                        <child>
-                                                          <object class="AdwComboRow" 
id="timed_animation_easing">
-                                                            <property name="title" 
translatable="yes">Easing</property>
-                                                            <property name="model">
-                                                              <object class="AdwEnumListModel">
-                                                                <property 
name="enum-type">AdwEasing</property>
-                                                              </object>
-                                                            </property>
-                                                            <property name="expression">
-                                                              <closure type="gchararray" 
function="animations_easing_name"/>
-                                                            </property>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Duration</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="timed_animation_duration">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">100</property>
-                                                                    <property name="upper">4000</property>
-                                                                    <property name="value">500</property>
-                                                                    <property 
name="page-increment">100</property>
-                                                                    <property 
name="step-increment">50</property>
-                                                                  </object>
-                                                                </property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" translatable="yes">Repeat 
Count</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="timed_animation_repeat_count">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">0</property>
-                                                                    <property name="upper">10</property>
-                                                                    <property name="value">1</property>
-                                                                    <property 
name="page-increment">1</property>
-                                                                    <property 
name="step-increment">1</property>
-                                                                  </object>
-                                                                </property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Reverse</property>
-                                                            <property 
name="activatable_widget">timed_animation_reverse</property>
-                                                            <child>
-                                                              <object class="GtkSwitch" 
id="timed_animation_reverse">
-                                                                <property name="valign">center</property>
-                                                                <property name="state">False</property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Alternate</property>
-                                                            <property 
name="activatable_widget">timed_animation_alternate</property>
-                                                            <child>
-                                                              <object class="GtkSwitch" 
id="timed_animation_alternate">
-                                                                <property name="valign">center</property>
-                                                                <property name="state">False</property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </property>
-                                                  </object>
-                                                </child>
-                                                <child>
-                                                  <object class="GtkStackPage">
-                                                    <property name="title" 
translatable="yes">Spring</property>
-                                                    <property name="name">Spring</property>
-                                                    <property name="child">
-                                                      <object class="AdwPreferencesGroup">
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Initial Velocity</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="spring_animation_velocity">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">-1000</property>
-                                                                    <property name="upper">1000</property>
-                                                                    <property name="value">0</property>
-                                                                    <property 
name="page-increment">10</property>
-                                                                    <property 
name="step-increment">1</property>
-                                                                  </object>
-                                                                </property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Damping</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="spring_animation_damping">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">0</property>
-                                                                    <property name="upper">1000</property>
-                                                                    <property name="value">10</property>
-                                                                    <property 
name="page-increment">10</property>
-                                                                    <property 
name="step-increment">1</property>
-                                                                  </object>
-                                                                </property>
-                                                                <signal name="value-changed" 
handler="notify_spring_params_change" swapped="yes"/>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Mass</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="spring_animation_mass">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">0</property>
-                                                                    <property name="upper">100</property>
-                                                                    <property name="value">1</property>
-                                                                    <property 
name="page-increment">10</property>
-                                                                    <property 
name="step-increment">1</property>
-                                                                  </object>
-                                                                </property>
-                                                                <signal name="value-changed" 
handler="notify_spring_params_change" swapped="yes"/>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Stiffness</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="spring_animation_stiffness">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">0</property>
-                                                                    <property name="upper">1000</property>
-                                                                    <property name="value">100</property>
-                                                                    <property 
name="page-increment">10</property>
-                                                                    <property 
name="step-increment">1</property>
-                                                                  </object>
-                                                                </property>
-                                                                <signal name="value-changed" 
handler="notify_spring_params_change" swapped="yes"/>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Epsilon</property>
-                                                            <child>
-                                                              <object class="GtkSpinButton" 
id="spring_animation_epsilon">
-                                                                <property name="valign">center</property>
-                                                                <property name="numeric">True</property>
-                                                                <property name="digits">5</property>
-                                                                <property name="adjustment">
-                                                                  <object class="GtkAdjustment">
-                                                                    <property name="lower">0.0001</property>
-                                                                    <property name="upper">0.01</property>
-                                                                    <property name="value">0.001</property>
-                                                                    <property 
name="page-increment">0.001</property>
-                                                                    <property 
name="step-increment">0.001</property>
-                                                                  </object>
-                                                                </property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="AdwActionRow">
-                                                            <property name="title" 
translatable="yes">Clamp</property>
-                                                            <property 
name="activatable-widget">spring_animation_clamp_switch</property>
-                                                            <child>
-                                                              <object class="GtkSwitch" 
id="spring_animation_clamp_switch">
-                                                                <property name="valign">center</property>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </property>
-                                                  </object>
-                                                </child>
-                                              </object>
-                                            </property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                    </property>
-                                  </object>
-                                </property>
-                              </object>
+                              <object class="AdwDemoPageAnimations"/>
                             </property>
                           </object>
                         </child>
diff --git a/demo/adwaita-demo.gresources.xml b/demo/adwaita-demo.gresources.xml
index d4cc311f..390e7b09 100644
--- a/demo/adwaita-demo.gresources.xml
+++ b/demo/adwaita-demo.gresources.xml
@@ -41,6 +41,7 @@
     <file compressed="true">style-dark.css</file>
   </gresource>
   <gresource prefix="/org/gnome/Adwaita1/Demo/ui">
+    <file preprocess="xml-stripblanks">pages/animations/adw-demo-page-animations.ui</file>
     <file preprocess="xml-stripblanks">pages/avatar/adw-demo-page-avatar.ui</file>
     <file preprocess="xml-stripblanks">pages/buttons/adw-demo-page-buttons.ui</file>
     <file preprocess="xml-stripblanks">pages/carousel/adw-demo-page-carousel.ui</file>
diff --git a/demo/meson.build b/demo/meson.build
index 6e1bb587..6af941fe 100644
--- a/demo/meson.build
+++ b/demo/meson.build
@@ -12,6 +12,7 @@ adwaita_demo_resources = gnome.compile_resources(
 adwaita_demo_sources = [
   adwaita_demo_resources,
 
+  'pages/animations/adw-demo-page-animations.c',
   'pages/avatar/adw-demo-page-avatar.c',
   'pages/buttons/adw-demo-page-buttons.c',
   'pages/carousel/adw-demo-page-carousel.c',
diff --git a/demo/pages/animations/adw-demo-page-animations.c 
b/demo/pages/animations/adw-demo-page-animations.c
new file mode 100644
index 00000000..62476053
--- /dev/null
+++ b/demo/pages/animations/adw-demo-page-animations.c
@@ -0,0 +1,409 @@
+#include "adw-demo-page-animations.h"
+
+#include <glib/gi18n.h>
+
+struct _AdwDemoPageAnimations
+{
+  AdwBin parent_instance;
+
+  GtkStack *animation_preferences_stack;
+  AdwAnimation *timed_animation;
+  GtkWidget *timed_animation_sample;
+  GtkWidget *timed_animation_button_box;
+  GtkSpinButton *timed_animation_repeat_count;
+  GtkSwitch *timed_animation_reverse;
+  GtkSwitch *timed_animation_alternate;
+  GtkSpinButton *timed_animation_duration;
+  AdwComboRow *timed_animation_easing;
+  AdwAnimation *spring_animation;
+  GtkSpinButton *spring_animation_velocity;
+  GtkSpinButton *spring_animation_damping;
+  GtkSpinButton *spring_animation_mass;
+  GtkSpinButton *spring_animation_stiffness;
+  GtkSpinButton *spring_animation_epsilon;
+  GtkSwitch *spring_animation_clamp_switch;
+};
+
+enum {
+  PROP_0,
+  PROP_TIMED_ANIMATION,
+  PROP_SPRING_ANIMATION,
+  LAST_PROP,
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (AdwDemoPageAnimations, adw_demo_page_animations, ADW_TYPE_BIN)
+
+static AdwAnimation *
+get_current_animation (AdwDemoPageAnimations *self)
+{
+  const char *current_animation;
+
+  current_animation = gtk_stack_get_visible_child_name (self->animation_preferences_stack);
+
+  if (!g_strcmp0 (current_animation, "Timed")) {
+    return self->timed_animation;
+  } else if (!g_strcmp0 (current_animation, "Spring")) {
+    return self->spring_animation;
+  } else {
+    g_assert_not_reached ();
+  }
+}
+
+static char *
+animations_easing_name (AdwEnumListItem *value,
+                        gpointer         user_data)
+{
+  switch (adw_enum_list_item_get_value (value)) {
+  case ADW_LINEAR:
+    return g_strdup (_("Linear"));
+  case ADW_EASE_IN_QUAD:
+    return g_strdup (_("Ease-in (Quadratic)"));
+  case ADW_EASE_OUT_QUAD:
+    return g_strdup (_("Ease-out (Quadratic)"));
+  case ADW_EASE_IN_OUT_QUAD:
+    return g_strdup (_("Ease-in-out (Quadratic)"));
+  case ADW_EASE_IN_CUBIC:
+    return g_strdup (_("Ease-in (Cubic)"));
+  case ADW_EASE_OUT_CUBIC:
+    return g_strdup (_("Ease-out (Cubic)"));
+  case ADW_EASE_IN_OUT_CUBIC:
+    return g_strdup (_("Ease-in-out (Cubic)"));
+  case ADW_EASE_IN_QUART:
+    return g_strdup (_("Ease-in (Quartic)"));
+  case ADW_EASE_OUT_QUART:
+    return g_strdup (_("Ease-out (Quartic)"));
+  case ADW_EASE_IN_OUT_QUART:
+    return g_strdup (_("Ease-in-out (Quartic)"));
+  case ADW_EASE_IN_QUINT:
+    return g_strdup (_("Ease-in (Quintic)"));
+  case ADW_EASE_OUT_QUINT:
+    return g_strdup (_("Ease-out (Quintic)"));
+  case ADW_EASE_IN_OUT_QUINT:
+    return g_strdup (_("Ease-in-out (Quintic)"));
+  case ADW_EASE_IN_SINE:
+    return g_strdup (_("Ease-in (Sine)"));
+  case ADW_EASE_OUT_SINE:
+    return g_strdup (_("Ease-out (Sine)"));
+  case ADW_EASE_IN_OUT_SINE:
+    return g_strdup (_("Ease-in-out (Sine)"));
+  case ADW_EASE_IN_EXPO:
+    return g_strdup (_("Ease-in (Exponential)"));
+  case ADW_EASE_OUT_EXPO:
+    return g_strdup (_("Ease-out (Exponential)"));
+  case ADW_EASE_IN_OUT_EXPO:
+    return g_strdup (_("Ease-in-out (Exponential)"));
+  case ADW_EASE_IN_CIRC:
+    return g_strdup (_("Ease-in (Circular)"));
+  case ADW_EASE_OUT_CIRC:
+    return g_strdup (_("Ease-out (Circular)"));
+  case ADW_EASE_IN_OUT_CIRC:
+    return g_strdup (_("Ease-in-out (Circular)"));
+  case ADW_EASE_IN_ELASTIC:
+    return g_strdup (_("Ease-in (Elastic)"));
+  case ADW_EASE_OUT_ELASTIC:
+    return g_strdup (_("Ease-out (Elastic)"));
+  case ADW_EASE_IN_OUT_ELASTIC:
+    return g_strdup (_("Ease-in-out (Elastic)"));
+  case ADW_EASE_IN_BACK:
+    return g_strdup (_("Ease-in (Back)"));
+  case ADW_EASE_OUT_BACK:
+    return g_strdup (_("Ease-out (Back)"));
+  case ADW_EASE_IN_OUT_BACK:
+    return g_strdup (_("Ease-in-out (Back)"));
+  case ADW_EASE_IN_BOUNCE:
+    return g_strdup (_("Ease-in (Bounce)"));
+  case ADW_EASE_OUT_BOUNCE:
+    return g_strdup (_("Ease-out (Bounce)"));
+  case ADW_EASE_IN_OUT_BOUNCE:
+    return g_strdup (_("Ease-in-out (Bounce)"));
+  default:
+    return NULL;
+  }
+}
+
+static void
+timed_animation_measure (GtkWidget      *widget,
+                         GtkOrientation  orientation,
+                         int             for_size,
+                         int            *minimum,
+                         int            *natural,
+                         int            *minimum_baseline,
+                         int            *natural_baseline)
+{
+  GtkWidget *child = gtk_widget_get_first_child (widget);
+
+  if (!child)
+    return;
+
+  gtk_widget_measure (child, orientation, for_size, minimum, natural,
+                      minimum_baseline, natural_baseline);
+}
+
+static void
+timed_animation_allocate (GtkWidget *widget,
+                          int        width,
+                          int        height,
+                          int        baseline)
+{
+  AdwDemoPageAnimations *self =
+    ADW_DEMO_PAGE_ANIMATIONS (gtk_widget_get_ancestor (widget, ADW_TYPE_DEMO_PAGE_ANIMATIONS));
+  GtkWidget *child = gtk_widget_get_first_child (widget);
+  AdwAnimation *animation = get_current_animation (self);
+  double progress;
+  int child_width, offset;
+
+  if (!child)
+    return;
+
+  progress = adw_animation_get_value (animation);
+
+  gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1,
+                      &child_width, NULL, NULL, NULL);
+
+  offset = (int) ((width - child_width) * (progress - 0.5));
+
+  gtk_widget_allocate (child, width, height, baseline,
+                       gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (offset, 0)));
+}
+
+static void
+timed_animation_reset (AdwDemoPageAnimations *self)
+{
+  adw_animation_reset (self->timed_animation);
+  adw_animation_reset (self->spring_animation);
+}
+
+static void
+timed_animation_play_pause (AdwDemoPageAnimations *self)
+{
+  AdwAnimation *animation = get_current_animation (self);
+
+  switch (adw_animation_get_state (animation)) {
+  case ADW_ANIMATION_IDLE:
+  case ADW_ANIMATION_FINISHED:
+    adw_animation_play (animation);
+    break;
+  case ADW_ANIMATION_PAUSED:
+    adw_animation_resume (animation);
+    break;
+  case ADW_ANIMATION_PLAYING:
+    adw_animation_pause (animation);
+    break;
+  default:
+    g_assert_not_reached ();
+  }
+}
+
+static void
+timed_animation_skip (AdwDemoPageAnimations *self)
+{
+  adw_animation_skip (self->timed_animation);
+  adw_animation_skip (self->spring_animation);
+}
+
+static char *
+get_play_pause_icon_name (gpointer          user_data,
+                          AdwAnimationState timed_state,
+                          AdwAnimationState spring_state)
+{
+  gboolean playing = timed_state  == ADW_ANIMATION_PLAYING ||
+                     spring_state == ADW_ANIMATION_PLAYING;
+
+  return g_strdup (playing ? "media-playback-pause-symbolic" : "media-playback-start-symbolic");
+}
+
+static gboolean
+timed_animation_can_reset (gpointer          user_data,
+                           AdwAnimationState timed_state,
+                           AdwAnimationState spring_state)
+{
+  return timed_state  != ADW_ANIMATION_IDLE ||
+         spring_state != ADW_ANIMATION_IDLE;
+}
+
+static gboolean
+timed_animation_can_skip (gpointer          user_data,
+                          AdwAnimationState timed_state,
+                          AdwAnimationState spring_state)
+{
+  return timed_state  != ADW_ANIMATION_FINISHED &&
+         spring_state != ADW_ANIMATION_FINISHED;
+}
+
+static void
+timed_animation_cb (double     value,
+                    GtkWidget *self)
+{
+  gtk_widget_queue_allocate (self);
+}
+
+static void
+notify_spring_params_change (AdwDemoPageAnimations *self)
+{
+  g_autoptr (AdwSpringParams) spring_params =
+    adw_spring_params_new_full (gtk_spin_button_get_value (self->spring_animation_damping),
+                                gtk_spin_button_get_value (self->spring_animation_mass),
+                                gtk_spin_button_get_value (self->spring_animation_stiffness));
+
+  adw_spring_animation_set_spring_params (ADW_SPRING_ANIMATION (self->spring_animation), spring_params);
+}
+
+static void
+adw_demo_page_animations_get_property (GObject    *object,
+                                       guint       prop_id,
+                                       GValue     *value,
+                                       GParamSpec *pspec)
+{
+  AdwDemoPageAnimations *self = ADW_DEMO_PAGE_ANIMATIONS (object);
+
+  switch (prop_id) {
+  case PROP_TIMED_ANIMATION:
+    g_value_set_object (value, self->timed_animation);
+    break;
+
+  case PROP_SPRING_ANIMATION:
+    g_value_set_object (value, self->spring_animation);
+    break;
+
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_demo_page_animations_set_property (GObject      *object,
+                                       guint         prop_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
+{
+  AdwDemoPageAnimations *self = ADW_DEMO_PAGE_ANIMATIONS (object);
+
+  switch (prop_id) {
+  case PROP_TIMED_ANIMATION:
+    g_set_object (&self->timed_animation, g_value_get_object (value));
+    break;
+
+  case PROP_SPRING_ANIMATION:
+    g_set_object (&self->spring_animation, g_value_get_object (value));
+    break;
+
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_demo_page_animations_class_init (AdwDemoPageAnimationsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->set_property = adw_demo_page_animations_set_property;
+  object_class->get_property = adw_demo_page_animations_get_property;
+
+  props[PROP_TIMED_ANIMATION] =
+    g_param_spec_object ("timed-animation",
+                         "Timed animation",
+                         "Timed animation",
+                         ADW_TYPE_ANIMATION,
+                         G_PARAM_READWRITE);
+
+  props[PROP_SPRING_ANIMATION] =
+    g_param_spec_object ("spring-animation",
+                         "Spring animation",
+                         "Spring animation",
+                         ADW_TYPE_ANIMATION,
+                         G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, LAST_PROP, props);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Adwaita1/Demo/ui/pages/animations/adw-demo-page-animations.ui");
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, animation_preferences_stack);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_sample);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_button_box);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_repeat_count);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_reverse);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_alternate);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_duration);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, timed_animation_easing);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_velocity);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_damping);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_mass);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_stiffness);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_epsilon);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAnimations, spring_animation_clamp_switch);
+  gtk_widget_class_bind_template_callback (widget_class, animations_easing_name);
+  gtk_widget_class_bind_template_callback (widget_class, timed_animation_reset);
+  gtk_widget_class_bind_template_callback (widget_class, timed_animation_play_pause);
+  gtk_widget_class_bind_template_callback (widget_class, timed_animation_skip);
+  gtk_widget_class_bind_template_callback (widget_class, get_play_pause_icon_name);
+  gtk_widget_class_bind_template_callback (widget_class, timed_animation_can_reset);
+  gtk_widget_class_bind_template_callback (widget_class, timed_animation_can_skip);
+  gtk_widget_class_bind_template_callback (widget_class, notify_spring_params_change);
+}
+
+static void
+adw_demo_page_animations_init (AdwDemoPageAnimations *self)
+{
+  GtkLayoutManager *manager;
+  AdwAnimationTarget *target;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  target = adw_callback_animation_target_new ((AdwAnimationTargetFunc)
+                                              timed_animation_cb,
+                                              self->timed_animation_sample,
+                                              NULL);
+
+  self->timed_animation =
+    adw_timed_animation_new (GTK_WIDGET (self->timed_animation_sample),
+                             0, 1, 100, g_object_ref (target));
+
+  self->spring_animation =
+    adw_spring_animation_new (GTK_WIDGET (self->timed_animation_sample), 0, 1,
+                              adw_spring_params_new_full (10, 1, 100),
+                              target);
+
+  notify_spring_params_change (self);
+
+  g_object_bind_property (self->timed_animation_repeat_count, "value",
+                          self->timed_animation, "repeat-count",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->timed_animation_reverse, "state",
+                          self->timed_animation, "reverse",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->timed_animation_alternate, "state",
+                          self->timed_animation, "alternate",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->timed_animation_duration, "value",
+                          self->timed_animation, "duration",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->timed_animation_easing, "selected",
+                          self->timed_animation, "easing",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+  g_object_bind_property (self->spring_animation_velocity, "value",
+                          self->spring_animation, "initial_velocity",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->spring_animation_epsilon, "value",
+                          self->spring_animation, "epsilon",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property (self->spring_animation_clamp_switch, "active",
+                          self->spring_animation, "clamp",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+  adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->timed_animation),
+                                  ADW_EASE_IN_OUT_CUBIC);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIMED_ANIMATION]);
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SPRING_ANIMATION]);
+
+  manager = gtk_custom_layout_new (NULL, timed_animation_measure,
+                                   timed_animation_allocate);
+
+  gtk_widget_set_layout_manager (self->timed_animation_sample, manager);
+
+  gtk_widget_set_direction (self->timed_animation_button_box, GTK_TEXT_DIR_LTR);
+}
diff --git a/demo/pages/animations/adw-demo-page-animations.h 
b/demo/pages/animations/adw-demo-page-animations.h
new file mode 100644
index 00000000..91d0fff4
--- /dev/null
+++ b/demo/pages/animations/adw-demo-page-animations.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_DEMO_PAGE_ANIMATIONS (adw_demo_page_animations_get_type())
+
+G_DECLARE_FINAL_TYPE (AdwDemoPageAnimations, adw_demo_page_animations, ADW, DEMO_PAGE_ANIMATIONS, AdwBin)
+
+G_END_DECLS
diff --git a/demo/pages/animations/adw-demo-page-animations.ui 
b/demo/pages/animations/adw-demo-page-animations.ui
new file mode 100644
index 00000000..4ed71e7c
--- /dev/null
+++ b/demo/pages/animations/adw-demo-page-animations.ui
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk" version="4.0"/>
+  <requires lib="libadwaita" version="1.0"/>
+  <template class="AdwDemoPageAnimations" parent="AdwBin">
+    <property name="child">
+      <object class="GtkScrolledWindow">
+        <property name="hscrollbar-policy">never</property>
+        <property name="child">
+          <object class="GtkViewport">
+            <property name="scroll-to-focus">True</property>
+            <property name="child">
+              <object class="GtkBox">
+                <property name="orientation">vertical</property>
+                <property name="valign">center</property>
+                <style>
+                  <class name="timed-animation-page"/>
+                </style>
+                <child>
+                  <object class="GtkBox">
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="AdwClamp">
+                        <property name="maximum-size">400</property>
+                        <property name="tightening-threshold">300</property>
+                        <property name="child">
+                          <object class="AdwBin" id="timed_animation_sample">
+                            <property name="margin-bottom">36</property>
+                            <property name="child">
+                              <object class="AdwBin" id="timed_animation_widget">
+                                <property name="halign">center</property>
+                                <property name="valign">center</property>
+                                <property name="name">animation-sample</property>
+                              </object>
+                            </property>
+                          </object>
+                        </property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="label" translatable="yes">Animations</property>
+                        <property name="wrap">True</property>
+                        <property name="wrap-mode">word-char</property>
+                        <property name="justify">center</property>
+                        <style>
+                          <class name="title"/>
+                          <class name="title-1"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="label" translatable="yes">Simple transitions.</property>
+                        <property name="justify">center</property>
+                        <property name="use_markup">true</property>
+                        <property name="wrap">True</property>
+                        <style>
+                          <class name="body"/>
+                          <class name="description"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="timed_animation_button_box">
+                    <property name="valign">center</property>
+                    <property name="halign">center</property>
+                    <property name="margin-top">30</property>
+                    <property name="margin-bottom">30</property>
+                    <property name="spacing">18</property>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="icon-name">media-skip-backward-symbolic</property>
+                        <property name="valign">center</property>
+                        <binding name="sensitive">
+                          <closure type="gboolean" function="timed_animation_can_reset">
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="timed-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="spring-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                          </closure>
+                        </binding>
+                        <signal name="clicked" handler="timed_animation_reset" swapped="true"/>
+                        <style>
+                          <class name="circular"/>
+                          <class name="flat"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <binding name="icon-name">
+                          <closure type="gchararray" function="get_play_pause_icon_name">
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="timed-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="spring-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                          </closure>
+                        </binding>
+                        <property name="width-request">48</property>
+                        <property name="height-request">48</property>
+                        <signal name="clicked" handler="timed_animation_play_pause" swapped="true"/>
+                        <style>
+                          <class name="circular"/>
+                          <class name="suggested-action"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton">
+                        <property name="icon-name">media-skip-forward-symbolic</property>
+                        <property name="valign">center</property>
+                        <binding name="sensitive">
+                          <closure type="gboolean" function="timed_animation_can_skip">
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="timed-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                            <lookup name="state" type="AdwAnimation">
+                              <lookup name="spring-animation">AdwDemoPageAnimations</lookup>
+                            </lookup>
+                          </closure>
+                        </binding>
+                        <signal name="clicked" handler="timed_animation_skip" swapped="true"/>
+                        <style>
+                          <class name="circular"/>
+                          <class name="flat"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="AdwPreferencesGroup">
+                    <child>
+                      <object class="GtkStackSwitcher">
+                        <property name="stack">animation_preferences_stack</property>
+                        <property name="margin-bottom">32</property>
+                        <property name="halign">center</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="AdwClamp">
+                    <property name="maximum-size">400</property>
+                    <property name="tightening-threshold">300</property>
+                    <property name="child">
+                      <object class="GtkStack" id="animation_preferences_stack">
+                        <signal name="notify::visible-child-name" handler="timed_animation_reset" 
swapped="true"/>
+                        <child>
+                          <object class="GtkStackPage">
+                            <property name="title" translatable="yes">Timed</property>
+                            <property name="name">Timed</property>
+                            <property name="child">
+                              <object class="AdwPreferencesGroup">
+                                <child>
+                                  <object class="AdwComboRow" id="timed_animation_easing">
+                                    <property name="title" translatable="yes">Easing</property>
+                                    <property name="model">
+                                      <object class="AdwEnumListModel">
+                                        <property name="enum-type">AdwEasing</property>
+                                      </object>
+                                    </property>
+                                    <property name="expression">
+                                      <closure type="gchararray" function="animations_easing_name"/>
+                                    </property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Duration</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="timed_animation_duration">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">100</property>
+                                            <property name="upper">4000</property>
+                                            <property name="value">500</property>
+                                            <property name="page-increment">100</property>
+                                            <property name="step-increment">50</property>
+                                          </object>
+                                        </property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Repeat Count</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="timed_animation_repeat_count">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">0</property>
+                                            <property name="upper">10</property>
+                                            <property name="value">1</property>
+                                            <property name="page-increment">1</property>
+                                            <property name="step-increment">1</property>
+                                          </object>
+                                        </property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Reverse</property>
+                                    <property name="activatable_widget">timed_animation_reverse</property>
+                                    <child>
+                                      <object class="GtkSwitch" id="timed_animation_reverse">
+                                        <property name="valign">center</property>
+                                        <property name="state">False</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Alternate</property>
+                                    <property name="activatable_widget">timed_animation_alternate</property>
+                                    <child>
+                                      <object class="GtkSwitch" id="timed_animation_alternate">
+                                        <property name="valign">center</property>
+                                        <property name="state">False</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </property>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkStackPage">
+                            <property name="title" translatable="yes">Spring</property>
+                            <property name="name">Spring</property>
+                            <property name="child">
+                              <object class="AdwPreferencesGroup">
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Initial Velocity</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="spring_animation_velocity">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">-1000</property>
+                                            <property name="upper">1000</property>
+                                            <property name="value">0</property>
+                                            <property name="page-increment">10</property>
+                                            <property name="step-increment">1</property>
+                                          </object>
+                                        </property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Damping</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="spring_animation_damping">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">0</property>
+                                            <property name="upper">1000</property>
+                                            <property name="value">10</property>
+                                            <property name="page-increment">10</property>
+                                            <property name="step-increment">1</property>
+                                          </object>
+                                        </property>
+                                        <signal name="value-changed" handler="notify_spring_params_change" 
swapped="yes"/>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Mass</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="spring_animation_mass">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">0</property>
+                                            <property name="upper">100</property>
+                                            <property name="value">1</property>
+                                            <property name="page-increment">10</property>
+                                            <property name="step-increment">1</property>
+                                          </object>
+                                        </property>
+                                        <signal name="value-changed" handler="notify_spring_params_change" 
swapped="yes"/>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Stiffness</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="spring_animation_stiffness">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">0</property>
+                                            <property name="upper">1000</property>
+                                            <property name="value">100</property>
+                                            <property name="page-increment">10</property>
+                                            <property name="step-increment">1</property>
+                                          </object>
+                                        </property>
+                                        <signal name="value-changed" handler="notify_spring_params_change" 
swapped="yes"/>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Epsilon</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="spring_animation_epsilon">
+                                        <property name="valign">center</property>
+                                        <property name="numeric">True</property>
+                                        <property name="digits">5</property>
+                                        <property name="adjustment">
+                                          <object class="GtkAdjustment">
+                                            <property name="lower">0.0001</property>
+                                            <property name="upper">0.01</property>
+                                            <property name="value">0.001</property>
+                                            <property name="page-increment">0.001</property>
+                                            <property name="step-increment">0.001</property>
+                                          </object>
+                                        </property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="AdwActionRow">
+                                    <property name="title" translatable="yes">Clamp</property>
+                                    <property 
name="activatable-widget">spring_animation_clamp_switch</property>
+                                    <child>
+                                      <object class="GtkSwitch" id="spring_animation_clamp_switch">
+                                        <property name="valign">center</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </property>
+                          </object>
+                        </child>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+              </object>
+            </property>
+          </object>
+        </property>
+      </object>
+    </property>
+  </template>
+</interface>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]