[libhandy/wip/haecker-felix/flap-widget: 15/20] animation: Add HdyAnimation
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libhandy/wip/haecker-felix/flap-widget: 15/20] animation: Add HdyAnimation
- Date: Tue, 15 Dec 2020 12:09:57 +0000 (UTC)
commit 819d147c3a032e5aa43732c710f5b17be1cf9fc6
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Wed Nov 25 15:22:21 2020 +0500
animation: Add HdyAnimation
Add a tweener helper, this will make it significantly easier to do
animations.
Keep it private because the API is very barebones and we probably don't
want anything for GTK 3 at this point anyway.
src/hdy-animation-private.h | 30 ++++++++
src/hdy-animation.c | 169 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 198 insertions(+), 1 deletion(-)
---
diff --git a/src/hdy-animation-private.h b/src/hdy-animation-private.h
index f31002ad..ed6362f0 100644
--- a/src/hdy-animation-private.h
+++ b/src/hdy-animation-private.h
@@ -14,6 +14,36 @@
G_BEGIN_DECLS
+#define HDY_TYPE_ANIMATION (hdy_animation_get_type())
+
+typedef struct _HdyAnimation HdyAnimation;
+
+typedef void (*HdyAnimationValueCallback) (gdouble value,
+ gpointer user_data);
+typedef void (*HdyAnimationDoneCallback) (gpointer user_data);
+typedef double (*HdyAnimationEasingFunc) (gdouble t);
+
+GType hdy_animation_get_type (void) G_GNUC_CONST;
+
+HdyAnimation *hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ HdyAnimationEasingFunc easing_func,
+ HdyAnimationValueCallback value_cb,
+ HdyAnimationDoneCallback done_cb,
+ gpointer user_data);
+
+HdyAnimation *hdy_animation_ref (HdyAnimation *self);
+void hdy_animation_unref (HdyAnimation *self);
+
+void hdy_animation_start (HdyAnimation *self);
+void hdy_animation_stop (HdyAnimation *self);
+
+gdouble hdy_animation_get_value (HdyAnimation *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (HdyAnimation, hdy_animation_unref)
+
gdouble hdy_lerp (gdouble a, gdouble b, gdouble t);
G_END_DECLS
diff --git a/src/hdy-animation.c b/src/hdy-animation.c
index ce5bf64f..66ed3d64 100644
--- a/src/hdy-animation.c
+++ b/src/hdy-animation.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 Purism SPC
+ * Copyright (C) 2019-2020 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -18,6 +18,173 @@
* Since: 0.0.11
*/
+G_DEFINE_BOXED_TYPE (HdyAnimation, hdy_animation, hdy_animation_ref, hdy_animation_unref)
+
+struct _HdyAnimation
+{
+ gatomicrefcount ref_count;
+
+ GtkWidget *widget;
+
+ gdouble value;
+
+ gdouble value_from;
+ gdouble value_to;
+ gint64 duration; /* ms */
+
+ gint64 start_time; /* ms */
+ guint tick_cb_id;
+
+ HdyAnimationEasingFunc easing_func;
+ HdyAnimationValueCallback value_cb;
+ HdyAnimationDoneCallback done_cb;
+ gpointer user_data;
+};
+
+static void
+set_value (HdyAnimation *self,
+ gdouble value)
+{
+ self->value = value;
+ self->value_cb (value, self->user_data);
+}
+
+static gboolean
+tick_cb (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ HdyAnimation *self)
+{
+ gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock) / 1000; /* ms */
+ gdouble t = (gdouble) (frame_time - self->start_time) / self->duration;
+
+ if (t >= 1) {
+ self->tick_cb_id = 0;
+
+ set_value (self, self->value_to);
+
+ g_signal_handlers_disconnect_by_func (self->widget, hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+
+ return G_SOURCE_REMOVE;
+ }
+
+ set_value (self, hdy_lerp (self->value_from, self->value_to, self->easing_func (t)));
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+hdy_animation_free (HdyAnimation *self)
+{
+ hdy_animation_stop (self);
+
+ g_slice_free (HdyAnimation, self);
+}
+
+HdyAnimation *
+hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ HdyAnimationEasingFunc easing_func,
+ HdyAnimationValueCallback value_cb,
+ HdyAnimationDoneCallback done_cb,
+ gpointer user_data)
+{
+ HdyAnimation *self;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (easing_func != NULL, NULL);
+ g_return_val_if_fail (value_cb != NULL, NULL);
+ g_return_val_if_fail (done_cb != NULL, NULL);
+
+ self = g_slice_new0 (HdyAnimation);
+
+ g_atomic_ref_count_init (&self->ref_count);
+
+ self->widget = widget;
+ self->value_from = from;
+ self->value_to = to;
+ self->duration = duration;
+ self->easing_func = easing_func;
+ self->value_cb = value_cb;
+ self->done_cb = done_cb;
+ self->user_data = user_data;
+
+ self->value = from;
+
+ return self;
+}
+
+HdyAnimation *
+hdy_animation_ref (HdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ g_atomic_ref_count_inc (&self->ref_count);
+
+ return self;
+}
+
+void
+hdy_animation_unref (HdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (g_atomic_ref_count_dec (&self->ref_count))
+ hdy_animation_free (self);
+}
+
+void
+hdy_animation_start (HdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (!hdy_get_enable_animations (self->widget) ||
+ !gtk_widget_get_mapped (self->widget) ||
+ self->duration <= 0) {
+ set_value (self, self->value_to);
+
+ self->done_cb (self->user_data);
+
+ return;
+ }
+
+ self->start_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (self->widget)) / 1000;
+
+ if (self->tick_cb_id)
+ return;
+
+ g_signal_connect_swapped (self->widget, "unmap",
+ G_CALLBACK (hdy_animation_stop), self);
+ self->tick_cb_id = gtk_widget_add_tick_callback (self->widget, (GtkTickCallback) tick_cb, self, NULL);
+}
+
+void
+hdy_animation_stop (HdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (!self->tick_cb_id)
+ return;
+
+ gtk_widget_remove_tick_callback (self->widget, self->tick_cb_id);
+ self->tick_cb_id = 0;
+
+ g_signal_handlers_disconnect_by_func (self->widget, hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+}
+
+gdouble
+hdy_animation_get_value (HdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+
+ return self->value;
+}
+
/**
* hdy_get_enable_animations:
* @widget: a #GtkWidget
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]