[libadwaita] demo: add demo for AdwTimedAnimation



commit 278d46554408cdb1a01d4c88f318c779e9698c80
Author: Manuel Genovés <manuel genoves gmail com>
Date:   Fri Aug 6 02:41:26 2021 +0200

    demo: add demo for AdwTimedAnimation

 demo/adw-demo-window.c  | 240 ++++++++++++++++++++++++++++++++++++++++++++++++
 demo/adw-demo-window.ui | 225 +++++++++++++++++++++++++++++++++++++++++++++
 demo/style.css          |  30 +++++-
 3 files changed, 491 insertions(+), 4 deletions(-)
---
diff --git a/demo/adw-demo-window.c b/demo/adw-demo-window.c
index 44205045..2812ee7a 100644
--- a/demo/adw-demo-window.c
+++ b/demo/adw-demo-window.c
@@ -29,10 +29,24 @@ struct _AdwDemoWindow
   GtkListBox *avatar_contacts;
   int toast_undo_items;
   AdwToast *undo_toast;
+  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;
 };
 
 G_DEFINE_TYPE (AdwDemoWindow, adw_demo_window, ADW_TYPE_APPLICATION_WINDOW)
 
+enum {
+  PROP_0,
+  PROP_TIMED_ANIMATION,
+  LAST_PROP,
+};
+
 static char *
 get_color_scheme_icon_name (gpointer user_data,
                             gboolean dark)
@@ -40,6 +54,44 @@ 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;
+
+  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;
+
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
 static void
 color_scheme_button_clicked_cb (AdwDemoWindow *self)
 {
@@ -391,6 +443,119 @@ tab_view_demo_clicked_cb (GtkButton     *btn,
   gtk_window_present (GTK_WINDOW (window));
 }
 
+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_EASING_EASE_IN_CUBIC:
+    return g_strdup (_("Ease-in (Cubic)"));
+  case ADW_EASING_EASE_OUT_CUBIC:
+    return g_strdup (_("Ease-out (Cubic)"));
+  case ADW_EASING_EASE_IN_OUT_CUBIC:
+    return g_strdup (_("Ease-in-out (Cubic)"));
+  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);
+  double progress;
+  int child_width, offset;
+
+  if (!child)
+    return;
+
+  progress = adw_animation_get_value (self->timed_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);
+}
+
+static void
+timed_animation_play_pause (AdwDemoWindow *self)
+{
+  switch (adw_animation_get_state (self->timed_animation)) {
+  case ADW_ANIMATION_IDLE:
+  case ADW_ANIMATION_FINISHED:
+    adw_animation_play (self->timed_animation);
+    break;
+  case ADW_ANIMATION_PAUSED:
+    adw_animation_resume (self->timed_animation);
+    break;
+  case ADW_ANIMATION_PLAYING:
+    adw_animation_pause (self->timed_animation);
+    break;
+  default:
+    g_assert_not_reached ();
+  }
+}
+
+static void
+timed_animation_skip (AdwDemoWindow *self)
+{
+  adw_animation_skip (self->timed_animation);
+}
+
+static char *
+get_play_pause_icon_name (gpointer          user_data,
+                          AdwAnimationState state)
+{
+  return g_strdup (state == ADW_ANIMATION_PLAYING ? "media-playback-pause-symbolic" : 
"media-playback-start-symbolic");
+}
+
+static gboolean
+timed_animation_can_reset (gpointer          user_data,
+                           AdwAnimationState state)
+{
+  return state != ADW_ANIMATION_IDLE;
+}
+
+static gboolean
+timed_animation_can_skip (gpointer          user_data,
+                          AdwAnimationState state)
+{
+  return state != ADW_ANIMATION_FINISHED;
+}
+
 static void
 style_classes_demo_clicked_cb (GtkButton     *btn,
                                AdwDemoWindow *self)
@@ -485,8 +650,12 @@ toast_dismiss_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_install_action (widget_class, "toast.undo", NULL, (GtkWidgetActionActivateFunc) 
toast_undo_cb);
@@ -509,6 +678,13 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_remove_button);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_contacts);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, toast_overlay);
+  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_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);
@@ -532,6 +708,22 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, add_toast_cb);
   gtk_widget_class_bind_template_callback (widget_class, add_toast_with_button_cb);
   gtk_widget_class_bind_template_callback (widget_class, add_toast_with_long_title_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);
+
+  props[PROP_TIMED_ANIMATION] =
+    g_param_spec_object ("timed_animation",
+                         "Timed animation",
+                         "Timed animation",
+                         ADW_TYPE_ANIMATION,
+                         G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, LAST_PROP, props);
 }
 
 static void
@@ -558,6 +750,52 @@ avatar_page_init (AdwDemoWindow *self)
   avatar_file_remove_cb (self);
 }
 
+static void
+animation_page_init (AdwDemoWindow *self)
+{
+  GtkLayoutManager *manager;
+  AdwAnimationTarget *target =
+    adw_callback_animation_target_new ((AdwAnimationTargetFunc)
+                                       gtk_widget_queue_allocate,
+                                       self->timed_animation_sample, NULL);
+
+  self->timed_animation =
+    adw_timed_animation_new (GTK_WIDGET (self->timed_animation_sample),
+                             0, 1, 100, target);
+
+  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);
+
+  adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->timed_animation),
+                                  ADW_EASING_EASE_IN_OUT_CUBIC);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIMED_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)
 {
@@ -578,4 +816,6 @@ adw_demo_window_init (AdwDemoWindow *self)
   adw_leaflet_set_visible_child (self->content_box, GTK_WIDGET (self->right_box));
 
   gtk_widget_action_set_enabled (GTK_WIDGET (self), "toast.dismiss", FALSE);
+
+  animation_page_init (self);
 }
diff --git a/demo/adw-demo-window.ui b/demo/adw-demo-window.ui
index 90768e02..33851e48 100644
--- a/demo/adw-demo-window.ui
+++ b/demo/adw-demo-window.ui
@@ -992,6 +992,231 @@
                             </property>
                           </object>
                         </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="child">
+                                                      <object class="AdwBin" id="timed_animation_widget">
+                                                        <property name="halign">center</property>
+                                                        <property name="valign">center</property>
+                                                        <style>
+                                                          <class name="htranslate"/>
+                                                        </style>
+                                                      </object>
+                                                    </property>
+                                                  </object>
+                                                </property>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkLabel">
+                                                <property name="label" 
translatable="yes">Animations</property>
+                                                <property name="halign">center</property>
+                                                <property name="xalign">0</property>
+                                                <property name="wrap">True</property>
+                                                <property name="wrap-mode">word-char</property>
+                                                <property name="justify">center</property>
+                                                <style>
+                                                  <class name="title"/>
+                                                  <class name="large-title"/>
+                                                </style>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkLabel">
+                                                <property name="label" translatable="yes">Simpe timed 
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>
+                                                  </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>
+                                                  </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>
+                                                  </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="AdwClamp">
+                                            <property name="maximum-size">400</property>
+                                            <property name="tightening-threshold">300</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>
+                                      </object>
+                                    </property>
+                                  </object>
+                                </property>
+                              </object>
+                            </property>
+                          </object>
+                        </child>
                       </object>
                     </child>
                   </object>
diff --git a/demo/style.css b/demo/style.css
index ce2676cd..b20e8815 100644
--- a/demo/style.css
+++ b/demo/style.css
@@ -12,10 +12,23 @@ carousel.vertical .carousel-icon {
 }
 
 /* Mimic the status page. */
-box.avatar-page { margin: 36px 12px; }
-box.avatar-page > box > avatar { margin-bottom: 36px; }
-box.avatar-page > box > label.title { margin-bottom: 12px; }
-box.avatar-page > box > label.description { margin-bottom: 36px; }
+.avatar-page,
+.timed-animation-page {
+  margin: 36px 12px;
+}
+
+.avatar-page > box > label.title,
+.timed-animation-page > box > label.title {
+  margin-bottom: 12px;
+}
+
+.avatar-page > box > label.description {
+  margin-bottom: 36px;
+}
+
+.avatar-page > box > avatar {
+  margin-bottom: 36px;
+}
 
 flowbox.inline flowboxchild {
   padding: 0;
@@ -40,3 +53,12 @@ flowbox.inline flowboxchild {
   color: white;
   background-color: @orange_4;
 }
+
+.htranslate {
+  min-width: 30px;
+  min-height: 30px;
+  border-radius: 24px;
+  background: #33d17a;
+  background: linear-gradient(to bottom, @green_2, @green_5);
+  margin-bottom: 36px;
+}


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