phosh-arch/gtk3-mobile/Add-GtkHdyAnimation.patch
2024-08-13 08:17:11 -07:00

348 lines
9.1 KiB
Diff

From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 16 Dec 2020 18:54:47 +0500
Subject: Add GtkHdyAnimation
This is imported from HdyAnimation from libhandy 1.0.2.
---
gtk/hdy-animation-private.h | 53 ++++++++++
gtk/hdy-animation.c | 250 ++++++++++++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
3 files changed, 305 insertions(+)
create mode 100644 gtk/hdy-animation-private.h
create mode 100644 gtk/hdy-animation.c
diff --git a/gtk/hdy-animation-private.h b/gtk/hdy-animation-private.h
new file mode 100644
index 0000000..6816f6e
--- /dev/null
+++ b/gtk/hdy-animation-private.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkwidget.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_ANIMATION (gtk_hdy_animation_get_type())
+
+typedef struct _GtkHdyAnimation GtkHdyAnimation;
+
+typedef void (*GtkHdyAnimationValueCallback) (gdouble value,
+ gpointer user_data);
+typedef void (*GtkHdyAnimationDoneCallback) (gpointer user_data);
+typedef double (*GtkHdyAnimationEasingFunc) (gdouble t);
+
+GType gtk_hdy_animation_get_type (void) G_GNUC_CONST;
+
+GtkHdyAnimation *gtk_hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ GtkHdyAnimationEasingFunc easing_func,
+ GtkHdyAnimationValueCallback value_cb,
+ GtkHdyAnimationDoneCallback done_cb,
+ gpointer user_data);
+
+GtkHdyAnimation *gtk_hdy_animation_ref (GtkHdyAnimation *self);
+void gtk_hdy_animation_unref (GtkHdyAnimation *self);
+
+void gtk_hdy_animation_start (GtkHdyAnimation *self);
+void gtk_hdy_animation_stop (GtkHdyAnimation *self);
+
+gdouble gtk_hdy_animation_get_value (GtkHdyAnimation *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkHdyAnimation, gtk_hdy_animation_unref)
+
+gboolean gtk_hdy_get_enable_animations (GtkWidget *widget);
+
+gdouble gtk_hdy_lerp (gdouble a, gdouble b, gdouble t);
+
+gdouble gtk_hdy_ease_out_cubic (gdouble t);
+
+G_END_DECLS
diff --git a/gtk/hdy-animation.c b/gtk/hdy-animation.c
new file mode 100644
index 0000000..0de1128
--- /dev/null
+++ b/gtk/hdy-animation.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2019-2020 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "hdy-animation-private.h"
+
+/**
+ * SECTION:hdy-animation
+ * @short_description: Animation helpers
+ * @title: Animation Helpers
+ *
+ * Animation helpers.
+ *
+ * Since: 0.0.11
+ */
+
+G_DEFINE_BOXED_TYPE (GtkHdyAnimation, gtk_hdy_animation, gtk_hdy_animation_ref, gtk_hdy_animation_unref)
+
+struct _GtkHdyAnimation
+{
+ gatomicrefcount ref_count;
+
+ GtkWidget *widget;
+
+ gdouble value;
+
+ gdouble value_from;
+ gdouble value_to;
+ gint64 duration; /* ms */
+
+ gint64 start_time; /* ms */
+ guint tick_cb_id;
+
+ GtkHdyAnimationEasingFunc easing_func;
+ GtkHdyAnimationValueCallback value_cb;
+ GtkHdyAnimationDoneCallback done_cb;
+ gpointer user_data;
+};
+
+static void
+set_value (GtkHdyAnimation *self,
+ gdouble value)
+{
+ self->value = value;
+ self->value_cb (value, self->user_data);
+}
+
+static gboolean
+tick_cb (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ GtkHdyAnimation *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, gtk_hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+
+ return G_SOURCE_REMOVE;
+ }
+
+ set_value (self, gtk_hdy_lerp (self->value_from, self->value_to, self->easing_func (t)));
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+gtk_hdy_animation_free (GtkHdyAnimation *self)
+{
+ gtk_hdy_animation_stop (self);
+
+ g_slice_free (GtkHdyAnimation, self);
+}
+
+GtkHdyAnimation *
+gtk_hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ GtkHdyAnimationEasingFunc easing_func,
+ GtkHdyAnimationValueCallback value_cb,
+ GtkHdyAnimationDoneCallback done_cb,
+ gpointer user_data)
+{
+ GtkHdyAnimation *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 (GtkHdyAnimation);
+
+ 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;
+}
+
+GtkHdyAnimation *
+gtk_hdy_animation_ref (GtkHdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ g_atomic_ref_count_inc (&self->ref_count);
+
+ return self;
+}
+
+void
+gtk_hdy_animation_unref (GtkHdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (g_atomic_ref_count_dec (&self->ref_count))
+ gtk_hdy_animation_free (self);
+}
+
+void
+gtk_hdy_animation_start (GtkHdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (!gtk_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 (gtk_hdy_animation_stop), self);
+ self->tick_cb_id = gtk_widget_add_tick_callback (self->widget, (GtkTickCallback) tick_cb, self, NULL);
+}
+
+void
+gtk_hdy_animation_stop (GtkHdyAnimation *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, gtk_hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+}
+
+gdouble
+gtk_hdy_animation_get_value (GtkHdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+
+ return self->value;
+}
+
+/**
+ * gtk_hdy_get_enable_animations:
+ * @widget: a #GtkWidget
+ *
+ * Returns whether animations are enabled for that widget. This should be used
+ * when implementing an animated widget to know whether to animate it or not.
+ *
+ * Returns: %TRUE if animations are enabled for @widget.
+ *
+ * Since: 0.0.11
+ */
+gboolean
+gtk_hdy_get_enable_animations (GtkWidget *widget)
+{
+ gboolean enable_animations = TRUE;
+
+ g_assert (GTK_IS_WIDGET (widget));
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-enable-animations", &enable_animations,
+ NULL);
+
+ return enable_animations;
+}
+
+/**
+ * gtk_hdy_lerp: (skip)
+ * @a: the start
+ * @b: the end
+ * @t: the interpolation rate
+ *
+ * Computes the linear interpolation between @a and @b for @t.
+ *
+ * Returns: the linear interpolation between @a and @b for @t.
+ *
+ * Since: 0.0.11
+ */
+gdouble
+gtk_hdy_lerp (gdouble a, gdouble b, gdouble t)
+{
+ return a * (1.0 - t) + b * t;
+}
+
+/* From clutter-easing.c, based on Robert Penner's
+ * infamous easing equations, MIT license.
+ */
+
+/**
+ * gtk_hdy_ease_out_cubic:
+ * @t: the term
+ *
+ * Computes the ease out for @t.
+ *
+ * Returns: the ease out for @t.
+ *
+ * Since: 0.0.11
+ */
+gdouble
+gtk_hdy_ease_out_cubic (gdouble t)
+{
+ gdouble p = t - 1;
+ return p * p * p + 1;
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 1d35e83..9fe7c4d 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -383,6 +383,7 @@ gtk_sources = files(
'gtkwin32draw.c',
'gtkwin32theme.c',
'gdkpixbufutils.c',
+ 'hdy-animation.c',
'hdy-css.c',
'hdy-view-switcher-bar.c',
'hdy-view-switcher-button.c',
@@ -394,6 +395,7 @@ gtk_sources = files(
gtk_private_type_headers = files(
'gtkcsstypesprivate.h',
'gtktexthandleprivate.h',
+ 'hdy-animation-private.h',
'hdy-css-private.h',
'hdy-view-switcher-bar-private.h',
'hdy-view-switcher-button-private.h',