diff --git a/.gitmodules b/.gitmodules
index e69de29..018c244 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "animation/third_party/glm"]
+ path = animation/third_party/glm
+ url = git://github.com/g-truc/glm
diff --git a/.travis.yml b/.travis.yml
index df5b8a2..8bede8d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,12 +3,13 @@ language: cpp
services:
- docker
before_install:
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull ubuntu:bionic; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull ubuntu:disco; fi
script:
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM ubuntu:bionic > Dockerfile; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM ubuntu:disco > Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo RUN apt-get update >> Dockerfile; fi
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo RUN apt-get install -y meson ninja-build build-essential git pkg-config libglib2.0-dev gir1.2-glib-2.0 gobject-introspection libgirepository1.0-dev >> Dockerfile; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo RUN apt-get install --allow-unauthenticated -y meson ninja-build build-essential git pkg-config libglib2.0-dev gir1.2-glib-2.0 gobject-introspection libgirepository1.0-dev libmutter-4-dev git-core autoconf automake gjs >> Dockerfile; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo "RUN git clone git://github.com/ptomato/jasmine-gjs && cd jasmine-gjs && ./autogen.sh --prefix=/usr && make && make install && rm -rf jasmine-gjs" >> Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX meson -Db_sanitize=address,undefined -Dwerror=true builddir && ninja -C builddir && G_SLICE=always-malloc ./builddir/tests/animation_test --gtest_color=yes"; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX meson -Dwerror=true builddir && meson test -C builddir -v --num-processes=1"; fi
diff --git a/animation-clutter/animation-clutter-actor-box-query.c b/animation-clutter/animation-clutter-actor-box-query.c
new file mode 100644
index 0000000..df58dd9
--- /dev/null
+++ b/animation-clutter/animation-clutter-actor-box-query.c
@@ -0,0 +1,179 @@
+/*
+ * animation-clutter/animation-clutter-actor-box-query.cpp
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * AnimationClutterActorBoxQuery subclass for ClutterActor
+ */
+
+#include
+
+struct _AnimationClutterActorBoxQuery
+{
+ GObject parent_instance;
+};
+
+typedef struct _AnimationClutterActorBoxQueryPrivate
+{
+ ClutterActor *actor;
+} AnimationClutterActorBoxQueryPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationClutterActorBoxQuery,
+ animation_clutter_actor_box_query,
+ ANIMATION_TYPE_BOX_QUERY)
+
+
+enum {
+ PROP_0,
+ PROP_ACTOR,
+ NPROPS
+};
+
+static GParamSpec *animation_clutter_actor_box_query_props[NPROPS] = { NULL, };
+
+static void
+update_box_for_actor_geometry (AnimationClutterActorBoxQuery *box_query,
+ ClutterActor *actor)
+{
+ float x, y, width, height;
+
+ clutter_actor_get_position (actor, &x, &y);
+ clutter_actor_get_size (actor, &width, &height);
+
+ const AnimationBox box = {
+ .top_left = { x, y },
+ .bottom_right = { x + width, y + height }
+ };
+
+ animation_box_query_update (ANIMATION_BOX_QUERY (box_query), &box);
+}
+
+static void
+actor_geometry_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (object);
+ AnimationClutterActorBoxQuery *box_query = ANIMATION_CLUTTER_ACTOR_BOX_QUERY (user_data);
+
+ update_box_for_actor_geometry (box_query, actor);
+}
+
+static void
+disconnect_signals_and_unref (gpointer data)
+{
+ ClutterActor *actor = data;
+
+ g_signal_handlers_disconnect_by_data (actor, actor);
+ g_object_unref (actor);
+}
+
+static ClutterActor *
+connect_signals_and_update (ClutterActor *actor,
+ AnimationClutterActorBoxQuery *box_query)
+{
+ g_signal_connect_object (actor, "notify::x", G_CALLBACK (actor_geometry_changed), box_query, G_CONNECT_AFTER);
+ g_signal_connect_object (actor, "notify::y", G_CALLBACK (actor_geometry_changed), box_query, G_CONNECT_AFTER);
+ g_signal_connect_object (actor, "notify::width", G_CALLBACK (actor_geometry_changed), box_query, G_CONNECT_AFTER);
+ g_signal_connect_object (actor, "notify::height", G_CALLBACK (actor_geometry_changed), box_query, G_CONNECT_AFTER);
+
+ update_box_for_actor_geometry (box_query, actor);
+
+ return actor;
+}
+
+static void
+animation_clutter_actor_box_query_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationClutterActorBoxQuery *box_query = ANIMATION_CLUTTER_ACTOR_BOX_QUERY (object);
+ AnimationClutterActorBoxQueryPrivate *priv = animation_clutter_actor_box_query_get_instance_private (box_query);
+
+ switch (prop_id)
+ {
+ case PROP_ACTOR:
+ g_clear_pointer (&priv->actor, (GDestroyNotify) disconnect_signals_and_unref);
+ priv->actor = connect_signals_and_update (CLUTTER_ACTOR (g_value_dup_object (value)), box_query);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_clutter_actor_box_query_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationClutterActorBoxQuery *box_query = ANIMATION_CLUTTER_ACTOR_BOX_QUERY (object);
+ AnimationClutterActorBoxQueryPrivate *priv = animation_clutter_actor_box_query_get_instance_private (box_query);
+
+ switch (prop_id)
+ {
+ case PROP_ACTOR:
+ g_value_set_object (value, priv->actor);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_clutter_actor_box_query_dispose (GObject *object)
+{
+ AnimationClutterActorBoxQuery *box_query = ANIMATION_CLUTTER_ACTOR_BOX_QUERY (object);
+ AnimationClutterActorBoxQueryPrivate *priv = animation_clutter_actor_box_query_get_instance_private (box_query);
+
+ g_clear_object (&priv->actor);
+
+ G_OBJECT_CLASS (animation_clutter_actor_box_query_parent_class)->dispose (object);
+}
+
+static void
+animation_clutter_actor_box_query_class_init (AnimationClutterActorBoxQueryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = animation_clutter_actor_box_query_get_property;
+ object_class->set_property = animation_clutter_actor_box_query_set_property;
+ object_class->dispose = animation_clutter_actor_box_query_dispose;
+
+ animation_clutter_actor_box_query_props[PROP_ACTOR] =
+ g_param_spec_object ("actor",
+ "Clutter Actor",
+ "The ClutterActor to observe",
+ CLUTTER_TYPE_ACTOR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class,
+ NPROPS,
+ animation_clutter_actor_box_query_props);
+}
+
+static void
+animation_clutter_actor_box_query_init (AnimationClutterActorBoxQuery *box_query)
+{
+}
+
+AnimationBoxQuery *
+animation_clutter_actor_box_query_new_for_actor (ClutterActor *actor)
+{
+ return ANIMATION_BOX_QUERY (g_object_new (ANIMATION_CLUTTER_TYPE_ACTOR_BOX_QUERY,
+ "actor", actor,
+ NULL));
+}
diff --git a/animation-clutter/animation-clutter-actor-box-query.h b/animation-clutter/animation-clutter-actor-box-query.h
new file mode 100644
index 0000000..9da591e
--- /dev/null
+++ b/animation-clutter/animation-clutter-actor-box-query.h
@@ -0,0 +1,36 @@
+/*
+ * animation-clutter/animation-clutter-actor-box-query.h
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * Geometry query subclass for ClutterActor
+ */
+#pragma once
+
+#include
+
+#include
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_CLUTTER_TYPE_ACTOR_BOX_QUERY animation_clutter_actor_box_query_get_type ()
+G_DECLARE_FINAL_TYPE (AnimationClutterActorBoxQuery, animation_clutter_actor_box_query, ANIMATION_CLUTTER, ACTOR_BOX_QUERY, GObject)
+
+AnimationBoxQuery * animation_clutter_actor_box_query_new_for_actor (ClutterActor *actor);
+
+G_END_DECLS
diff --git a/animation-clutter/animation-clutter-affine-effect.c b/animation-clutter/animation-clutter-affine-effect.c
new file mode 100644
index 0000000..764f00d
--- /dev/null
+++ b/animation-clutter/animation-clutter-affine-effect.c
@@ -0,0 +1,312 @@
+/*
+ * animation-clutter/animation-clutter-affine-effect.c
+ *
+ * Copyright © 2013-2018 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "animation-clutter-affine-effect.h"
+#include "animation-clutter-common.h"
+
+struct _AnimationClutterAffineEffect {
+ ClutterEffect parent_instance;
+};
+
+typedef struct
+{
+ AnimationTransformAnimation *transform_animation;
+ gint64 last_usecs;
+ guint timeout_id;
+} AnimationClutterAffineEffectPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_TRANSFORM_ANIMATION,
+ PROP_LAST
+};
+
+static GParamSpec *object_properties[PROP_LAST];
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationClutterAffineEffect,
+ animation_clutter_affine_effect,
+ CLUTTER_TYPE_EFFECT)
+
+static gboolean
+animation_clutter_affine_effect_modify_paint_volume (ClutterEffect *effect,
+ ClutterPaintVolume *volume)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (effect);
+ ClutterActor *actor = clutter_actor_meta_get_actor (meta);
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (effect);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ /* We assume that the parent's get_paint_volume method always returns
+ * TRUE here. */
+ CLUTTER_EFFECT_CLASS (animation_clutter_affine_effect_parent_class)->modify_paint_volume (effect, volume);
+
+ if (priv->transform_animation && clutter_actor_meta_get_enabled (meta))
+ {
+ AnimationVector corners[4];
+ AnimationVector4D extremes[4];
+ AnimationVector offset;
+
+ animation_clutter_compute_corners_from_untransformed_paint_volume (actor,
+ volume,
+ corners,
+ &offset);
+
+ animation_transform_animation_extremes (priv->transform_animation,
+ corners,
+ extremes);
+
+ animation_clutter_expand_paint_volume_with_extremes (volume, extremes, &offset);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+animation_clutter_affine_effect_new_frame (gpointer user_data)
+{
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (user_data);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (affine_effect);
+ ClutterActor *actor = clutter_actor_meta_get_actor (meta);
+ gint64 usecs = g_get_monotonic_time ();
+
+ static const unsigned int ms_to_us = 1000;
+
+ g_assert (priv->transform_animation);
+
+ /* Wraparound, priv->last_usecs -= G_MAXINT64.
+ * We make priv->last_usecs negative so that subtracting it
+ * from usecs results in the correct delta */
+ if (G_UNLIKELY (priv->last_usecs > usecs))
+ priv->last_usecs -= G_MAXINT64;
+
+ gint64 msecs_delta = (usecs - priv->last_usecs) / ms_to_us;
+ priv->last_usecs = usecs;
+
+ /* If there was no time movement, then we can't really step or remove
+ * models in a way that makes sense, so don't do it */
+ if (msecs_delta == 0)
+ return G_SOURCE_CONTINUE;
+
+ if (!animation_transform_animation_step (priv->transform_animation, msecs_delta))
+ {
+ /* Reset the transform back to an identity matrix. This will
+ * also cause the transform-set property to be unset. We
+ * need to do this before the actor effect is disabled, since
+ * disabling it may cause the actor to be destroyed
+ * and the actor to be detached from the effect. */
+ graphene_matrix_t matrix;
+ graphene_matrix_init_identity (&matrix);
+ clutter_actor_set_opacity (actor, 255);
+ clutter_actor_set_transform (actor,
+ (const graphene_matrix_t *) &matrix);
+
+ /* Disable the effect */
+ clutter_actor_meta_set_enabled (meta, FALSE);
+
+ /* Finally, return false so that we don't keep animating */
+ priv->timeout_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+ else
+ {
+ /* We need to immediately set the opacity of the actor
+ * since if it is zero, then clutter_actor_paint will
+ * never get called, causing us to never be able to
+ * update the opacity of the actor */
+ float scaled_opacity = animation_transform_animation_progress (priv->transform_animation) * 255.0;
+ guint8 opacity = (guint8) (scaled_opacity);
+
+ clutter_actor_set_opacity (actor, opacity);
+ clutter_effect_queue_repaint (CLUTTER_EFFECT (affine_effect));
+ }
+
+ /* We always want to return true even if there was no time delta */
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+animation_clutter_affine_effect_paint (ClutterEffect *effect,
+ ClutterPaintContext *context,
+ ClutterEffectPaintFlags flags)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (effect);
+ ClutterActor *actor = clutter_actor_meta_get_actor (meta);
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (effect);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ /* Apply the transform to the actor */
+ graphene_matrix_t matrix;
+ graphene_matrix_init_from_float (&matrix,
+ animation_transform_animation_matrix (priv->transform_animation));
+
+ clutter_actor_set_pivot_point (actor, 0, 0);
+ clutter_actor_set_transform (actor, &matrix);
+ clutter_actor_continue_paint (actor, context);
+}
+
+static void
+animation_clutter_affine_effect_ensure_timeline (AnimationClutterAffineEffect *affine_effect)
+{
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ if (priv->timeout_id == 0)
+ {
+ static const unsigned int frame_length_ms = 16; /* 1000 / 60; */
+
+ priv->last_usecs = g_get_monotonic_time ();
+ priv->timeout_id = g_timeout_add (frame_length_ms, animation_clutter_affine_effect_new_frame, affine_effect);
+
+ /* We need to show the actor and set the initial transform now to prevent flicker */
+ graphene_matrix_t matrix;
+ graphene_matrix_init_from_float (&matrix,
+ animation_transform_animation_matrix (priv->transform_animation));
+
+ float scaled_opacity = animation_transform_animation_progress (priv->transform_animation) * 255.0;
+ guint8 opacity = (guint8) (scaled_opacity);
+
+ ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (affine_effect));
+
+ clutter_actor_set_opacity (actor, opacity);
+ clutter_actor_set_pivot_point (actor, 0, 0);
+ clutter_actor_set_transform (actor, &matrix);
+ clutter_actor_show (actor);
+ }
+}
+
+static void
+animation_clutter_affine_effect_notify (GObject *object,
+ GParamSpec *pspec)
+{
+ ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (object);
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (object);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ if (g_strcmp0 (pspec->name, "enabled") == 0)
+ {
+ if (clutter_actor_meta_get_enabled (actor_meta))
+ animation_clutter_affine_effect_ensure_timeline (affine_effect);
+ else
+ g_clear_handle_id (&priv->timeout_id, g_source_remove);
+ }
+
+ G_OBJECT_CLASS (animation_clutter_affine_effect_parent_class)->notify (object, pspec);
+}
+
+static void
+animation_clutter_affine_effect_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (object);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ switch (prop_id)
+ {
+ case PROP_TRANSFORM_ANIMATION:
+ g_set_object (&priv->transform_animation, g_value_dup_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+animation_clutter_affine_effect_dispose (GObject *object)
+{
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (object);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ g_clear_object (&priv->transform_animation);
+
+ G_OBJECT_CLASS (animation_clutter_affine_effect_parent_class)->dispose (object);
+}
+
+static void
+animation_clutter_affine_effect_finalize (GObject *object)
+{
+ AnimationClutterAffineEffect *affine_effect = ANIMATION_CLUTTER_AFFINE_EFFECT (object);
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (affine_effect);
+
+ g_clear_handle_id (&priv->timeout_id, g_source_remove);
+
+ G_OBJECT_CLASS (animation_clutter_affine_effect_parent_class)->finalize (object);
+}
+
+static void
+animation_clutter_affine_effect_init (AnimationClutterAffineEffect *effect)
+{
+ AnimationClutterAffineEffectPrivate *priv =
+ animation_clutter_affine_effect_get_instance_private (effect);
+
+ priv->timeout_id = 0;
+}
+
+static void
+animation_clutter_affine_effect_class_init (AnimationClutterAffineEffectClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
+
+ object_class->notify = animation_clutter_affine_effect_notify;
+ object_class->set_property = animation_clutter_affine_effect_set_property;
+ object_class->dispose = animation_clutter_affine_effect_dispose;
+ object_class->finalize = animation_clutter_affine_effect_finalize;
+ effect_class->modify_paint_volume = animation_clutter_affine_effect_modify_paint_volume;
+ effect_class->paint = animation_clutter_affine_effect_paint;
+
+ object_properties[PROP_TRANSFORM_ANIMATION] =
+ g_param_spec_object ("transform-animation",
+ "Transform Animation",
+ "The underlying transform animation",
+ ANIMATION_TYPE_TRANSFORM_ANIMATION,
+ G_PARAM_WRITABLE);
+
+ g_object_class_install_properties (object_class, PROP_LAST, object_properties);
+}
+
+ClutterEffect *
+animation_clutter_affine_effect_new (AnimationTransformAnimation *transform_animation)
+{
+ return g_object_new (ANIMATION_CLUTTER_TYPE_AFFINE_EFFECT,
+ "transform-animation", transform_animation,
+ NULL);
+}
diff --git a/animation-clutter/animation-clutter-affine-effect.h b/animation-clutter/animation-clutter-affine-effect.h
new file mode 100644
index 0000000..e41da71
--- /dev/null
+++ b/animation-clutter/animation-clutter-affine-effect.h
@@ -0,0 +1,44 @@
+/*
+ * animation-clutter/clutter-animation-affine-effect.h
+ *
+ * Copyright © 2013-2016 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_CLUTTER_TYPE_AFFINE_EFFECT (animation_clutter_affine_effect_get_type ())
+G_DECLARE_FINAL_TYPE (AnimationClutterAffineEffect, animation_clutter_affine_effect, ANIMATION_CLUTTER, AFFINE_EFFECT, ClutterEffect)
+
+/**
+ * animation_clutter_affine_effect_new:
+ * @transform_animation: An #AnimationTransformAnimation to wrap.
+ *
+ * Creates a new #ClutterEffect which uses the underlying
+ * AnimationZoomAnimation to apply a linear transformation to the actor.
+ *
+ * Returns: (transfer full): A new #ClutterEffect
+ */
+ClutterEffect * animation_clutter_affine_effect_new (AnimationTransformAnimation *transform_animation);
+
+G_END_DECLS
diff --git a/animation-clutter/animation-clutter-common-private.h b/animation-clutter/animation-clutter-common-private.h
new file mode 100644
index 0000000..72fe04f
--- /dev/null
+++ b/animation-clutter/animation-clutter-common-private.h
@@ -0,0 +1,31 @@
+/*
+ * animation-clutter/animation-clutter-common-private.h
+ *
+ * Copyright © 2013-2016 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+void animation_clutter_actor_box_enlarge_for_effects (ClutterActorBox *box);
+
+G_END_DECLS
+
diff --git a/animation-clutter/animation-clutter-common.c b/animation-clutter/animation-clutter-common.c
new file mode 100644
index 0000000..a687b6c
--- /dev/null
+++ b/animation-clutter/animation-clutter-common.c
@@ -0,0 +1,253 @@
+/*
+ * animation-clutter/animation-clutter-common.c
+ *
+ * Copyright © 2013-2018 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#include
+
+#include
+
+#include "animation-clutter-common.h"
+
+/* This code was borrowed from clutter-actor-box.c
+ *
+ * Copyright (c) 2006, 2007, 2008, OpenedHand Ltd.
+ * Copyright (c) 2009, 2010, 2011, 2012, Intel Corporation.
+ *
+ * The reason why we need this code is that for the wobbly effect,
+ * both the model and the renderer must agree on the geometry of the
+ * surface to be animated. In the case of clutter, ClutterDeformEffect
+ * is a subclass of ClutterOffscreenEffect, such that the actor is first
+ * painted into an FBO, then the FBO is rendered with the specified mesh.
+ *
+ * However, "behind our back", clutter will make the FBO a little bit
+ * bigger than the actual actor geometry, meaning that if we were to
+ * deform vertices as though the surface size was the same as the actor
+ * size, we would actually be "pinching" the FBO every so slightly, leading
+ * to an irritating visual glitch where the window gets slightly smaller
+ * as soon as it starts moving.
+ *
+ * Therefore, we tell clutter that the actor paint box is the normal actor
+ * paint box extents without any effects applied as usual, but we tell
+ * libanimation that the model is the same size that clutter would have
+ * computed the FBO to be, such that the FBO size and the model size
+ * agree and there is no "pinching" effect.
+ */
+static inline int
+nearby_int (float x)
+{
+ return (int) (x < 0.0f ? x - 0.5f : x + 0.5f);
+}
+
+void
+animation_clutter_actor_box_enlarge_for_effects (ClutterActorBox *box)
+{
+ float width, height;
+
+ /* The aim here is that for a given rectangle defined with floating point
+ * coordinates we want to determine a stable quantized size in pixels
+ * that doesn't vary due to the original box's sub-pixel position.
+ *
+ * The reason this is important is because effects will use this
+ * API to determine the size of offscreen framebuffers and so for
+ * a fixed-size object that may be animated accross the screen we
+ * want to make sure that the stage paint-box has an equally stable
+ * size so that effects aren't made to continuously re-allocate
+ * a corresponding fbo.
+ *
+ * The other thing we consider is that the calculation of this box is
+ * subject to floating point precision issues that might be slightly
+ * different to the precision issues involved with actually painting the
+ * actor, which might result in painting slightly leaking outside the
+ * user's calculated paint-volume. For this we simply aim to pad out the
+ * paint-volume by at least half a pixel all the way around.
+ */
+ width = box->x2 - box->x1;
+ height = box->y2 - box->y1;
+ width = nearby_int (width);
+ height = nearby_int (height);
+ /* XXX: NB the width/height may now be up to 0.5px too small so we
+ * must also pad by 0.25px all around to account for this. In total we
+ * must padd by at least 0.75px around all sides. */
+
+ /* XXX: The furthest that we can overshoot the bottom right corner by
+ * here is 1.75px in total if you consider that the 0.75 padding could
+ * just cross an integer boundary and so ceil will effectively add 1.
+ */
+ box->x2 = ceilf (box->x2 + 0.75);
+ box->y2 = ceilf (box->y2 + 0.75);
+
+ /* Now we redefine the top-left relative to the bottom right based on the
+ * rounded width/height determined above + a constant so that the overall
+ * size of the box will be stable and not dependant on the box's
+ * position.
+ *
+ * Adding 3px to the width/height will ensure we cover the maximum of
+ * 1.75px padding on the bottom/right and still ensure we have > 0.75px
+ * padding on the top/left.
+ */
+ box->x1 = box->x2 - width - 3;
+ box->y1 = box->y2 - height - 3;
+}
+
+/* This constant is used to deal with rounding error in computing
+ * paint boxes. See also https://gitlab.gnome.org/GNOME/mutter/blob/master/clutter/clutter/clutter-paint-volume.c#L1212 */
+#define PAINT_BOX_OFFSET 1
+
+/**
+ * animation_clutter_get_untransformed_paint_box_from_existing_volume:
+ * @actor: A #ClutterActor
+ * @volume: A #ClutterPaintVolume
+ * @box: (out caller-allocates): A #ClutterActorBox to write extents to
+ *
+ * Assuming that the paint volume is orthogonal, get the stage-relative 2D
+ * extents of the paint volume and write them to the @box
+ * out parameter.
+ */
+void
+animation_clutter_get_untransformed_paint_box_from_existing_volume (ClutterActor *actor,
+ const ClutterPaintVolume *volume,
+ ClutterActorBox *box)
+{
+ graphene_point3d_t origin;
+
+ /* We don't have access to the stage projection matrix
+ * so the best we can do is hope here that the volume is
+ * two dimensional and orthogonal. */
+ clutter_paint_volume_get_origin (volume, &origin);
+
+ box->x1 = floor (origin.x + clutter_actor_get_x (actor)) - PAINT_BOX_OFFSET;
+ box->y1 = floor (origin.y + clutter_actor_get_y (actor)) - PAINT_BOX_OFFSET;
+ box->x2 = box->x1 + ceil (clutter_paint_volume_get_width (volume)) + PAINT_BOX_OFFSET * 2;
+ box->y2 = box->y1 + ceil (clutter_paint_volume_get_height (volume)) + PAINT_BOX_OFFSET * 2;
+}
+
+/**
+ * animation_clutter_get_best_known_paint_extents_box:
+ * @actor: A #ClutterActor
+ * @box: (out caller-allocates): A #ClutterActorBox
+ *
+ * Get the paint box if possible, otherwise fall back to
+ * using the actor geometry.
+ */
+void
+animation_clutter_get_best_known_paint_extents_box (ClutterActor *actor,
+ ClutterActorBox *box)
+{
+ float x, y, width, height;
+
+ g_return_if_fail (box != NULL);
+
+ if (clutter_actor_get_paint_box (actor, box))
+ return;
+
+ clutter_actor_get_position (actor, &x, &y);
+ clutter_actor_get_size (actor, &width, &height);
+
+ box->x1 = x;
+ box->y1 = y;
+ box->x2 = x + width;
+ box->y2 = y + height;
+}
+
+/**
+ * animation_clutter_compute_corners_from_paint_volume:
+ * @actor: A #ClutterActor that we're computing corners for.
+ * @volume: An existing #ClutterPaintVolume.
+ * @out_corners: (out caller-allocates) (array fixed-size=4): An array
+ * of corners representing a 3D bounding plane for this
+ * paint area.
+ * @offset: (out caller-allocates): A 2D vector representing the offset
+ * from the actor paint box corners to the real actor's real
+ * position.
+ */
+void
+animation_clutter_compute_corners_from_untransformed_paint_volume (ClutterActor *actor,
+ ClutterPaintVolume *volume,
+ AnimationVector *out_corners,
+ AnimationVector *out_offset)
+{
+ ClutterActorBox box;
+ float actor_x, actor_y;
+ float actor_paint_box_x, actor_paint_box_y;
+ float actor_paint_box_width, actor_paint_box_height;
+
+ g_return_if_fail (out_corners != NULL);
+ g_return_if_fail (out_offset != NULL);
+
+ animation_clutter_get_untransformed_paint_box_from_existing_volume (actor, volume, &box);
+ clutter_actor_get_position (actor, &actor_x, &actor_y);
+
+ actor_paint_box_x = box.x1;
+ actor_paint_box_y = box.y1;
+ actor_paint_box_width = box.x2 - box.x1;
+ actor_paint_box_height = box.y2 - box.y1;
+
+ out_corners[0].x = actor_paint_box_x;
+ out_corners[0].y = actor_paint_box_y;
+ out_corners[1].x = actor_paint_box_x + actor_paint_box_width;
+ out_corners[1].y = actor_paint_box_y;
+ out_corners[2].x = actor_paint_box_x;
+ out_corners[2].y = actor_paint_box_y + actor_paint_box_height;
+ out_corners[3].x = actor_paint_box_x + actor_paint_box_width;
+ out_corners[3].y = actor_paint_box_y + actor_paint_box_height;
+
+ out_offset->x = actor_paint_box_x - actor_x;
+ out_offset->y = actor_paint_box_y - actor_y;
+}
+
+/**
+ * animation_clutter_expand_paint_volume_with_extremes:
+ * @volume: A #ClutterPaintVolume
+ * @extremes: (array fixed-size=4): An array
+ * of corners representing a 3D bounding plane for this
+ * paint area.
+ * @offset: A 2D vector representing the offset from the actor paint
+ * box corners to the real actor's real position.
+ */
+void
+animation_clutter_expand_paint_volume_with_extremes (ClutterPaintVolume *volume,
+ AnimationVector4D *extremes,
+ AnimationVector *offset)
+{
+ float x1, y1, x2, y2, z1, z2;
+
+ g_return_if_fail (extremes != NULL);
+ g_return_if_fail (offset != NULL);
+
+ x1 = MIN (extremes[0].x, extremes[2].x) - offset->x;
+ y1 = MIN (extremes[0].y, extremes[1].y) - offset->y;
+ x2 = MAX (extremes[1].x, extremes[3].x) + offset->x;
+ y2 = MAX (extremes[2].y, extremes[3].y) + offset->y;
+ z1 = MIN (MIN (extremes[0].z, extremes[1].z),
+ MIN (extremes[2].z, extremes[3].z));
+ z2 = MAX (MAX (extremes[0].z, extremes[1].z),
+ MAX (extremes[2].z, extremes[3].z));
+
+ g_autoptr(ClutterPaintVolume) extremes_volume =
+ clutter_paint_volume_copy (volume);
+
+ graphene_point3d_t const origin = { x1, y1, z1 };
+ clutter_paint_volume_set_origin (extremes_volume, &origin);
+ clutter_paint_volume_set_width (extremes_volume, x2 - x1);
+ clutter_paint_volume_set_height (extremes_volume, y2 - y1);
+ clutter_paint_volume_set_depth (extremes_volume, z2 - z1);
+
+ clutter_paint_volume_union (volume, extremes_volume);
+}
diff --git a/animation-clutter/animation-clutter-common.h b/animation-clutter/animation-clutter-common.h
new file mode 100644
index 0000000..2310f4b
--- /dev/null
+++ b/animation-clutter/animation-clutter-common.h
@@ -0,0 +1,47 @@
+/*
+ * animation-clutter/animation-clutter-common.h
+ *
+ * Copyright © 2013-2016 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+void animation_clutter_get_untransformed_paint_box_from_existing_volume (ClutterActor *actor,
+ const ClutterPaintVolume *volume,
+ ClutterActorBox *box);
+
+void animation_clutter_get_best_known_paint_extents_box (ClutterActor *actor,
+ ClutterActorBox *box);
+
+void animation_clutter_compute_corners_from_untransformed_paint_volume (ClutterActor *actor,
+ ClutterPaintVolume *volume,
+ AnimationVector *out_corners,
+ AnimationVector *out_offset);
+
+void animation_clutter_expand_paint_volume_with_extremes (ClutterPaintVolume *volume,
+ AnimationVector4D *extremes,
+ AnimationVector *offset);
+
+G_END_DECLS
diff --git a/animation-clutter/animation-clutter-grid-effect.c b/animation-clutter/animation-clutter-grid-effect.c
new file mode 100644
index 0000000..7914fb8
--- /dev/null
+++ b/animation-clutter/animation-clutter-grid-effect.c
@@ -0,0 +1,333 @@
+/*
+ * animation-clutter/animation-clutter-grid-effect.c
+ *
+ * Copyright © 2013-2018 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "animation-clutter-grid-effect.h"
+#include "animation-clutter-common.h"
+
+struct _AnimationClutterGridEffect {
+ ClutterDeformEffect parent_instance;
+};
+
+typedef struct
+{
+ AnimationGridAnimation *grid_animation;
+ gint64 last_usecs;
+ guint timeout_id;
+} AnimationClutterGridEffectPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_GRID_ANIMATION,
+ PROP_LAST
+};
+
+static GParamSpec *object_properties[PROP_LAST];
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationClutterGridEffect,
+ animation_clutter_grid_effect,
+ CLUTTER_TYPE_DEFORM_EFFECT)
+
+static gboolean
+animation_clutter_grid_effect_modify_paint_volume (ClutterEffect *effect,
+ ClutterPaintVolume *volume)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (effect);
+ ClutterActor *actor = clutter_actor_meta_get_actor (meta);
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (effect);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ /* We assume that the parent's modify_paint_volume method always returns
+ * TRUE here. */
+ CLUTTER_EFFECT_CLASS (animation_clutter_grid_effect_parent_class)->modify_paint_volume (effect, volume);
+
+ if (priv->grid_animation && clutter_actor_meta_get_enabled (meta))
+ {
+ ClutterActorBox box;
+ float actor_x, actor_y;
+
+ animation_clutter_get_untransformed_paint_box_from_existing_volume (actor, volume, &box);
+ clutter_actor_get_position (actor, &actor_x, &actor_y);
+
+ AnimationVector corners[4] = {
+ { box.x1, box.y1 },
+ { box.x2, box.y1 },
+ { box.x1, box.y2 },
+ { box.x2, box.y2 }
+ };
+ AnimationVector4D extremes[4];
+
+ animation_grid_animation_extremes (priv->grid_animation,
+ corners,
+ extremes);
+
+ float x1 = MIN (extremes[0].x, extremes[2].x);
+ float y1 = MIN (extremes[0].y, extremes[1].y);
+ float z1 = MIN (MIN (extremes[0].z, extremes[1].z),
+ MIN (extremes[2].z, extremes[3].z));
+ float x2 = MAX (extremes[1].x, extremes[3].x);
+ float y2 = MAX (extremes[2].y, extremes[3].y);
+ float z2 = MAX (MAX (extremes[0].z, extremes[1].z),
+ MAX (extremes[2].z, extremes[3].z));
+
+ g_autoptr(ClutterPaintVolume) extremes_volume =
+ clutter_paint_volume_copy (volume);
+
+ graphene_point3d_t const origin = { x1 - actor_x, y1 - actor_y, z1 };
+ clutter_paint_volume_set_origin (extremes_volume, &origin);
+ clutter_paint_volume_set_width (extremes_volume, MAX (x2 - x1, 1.0));
+ clutter_paint_volume_set_height (extremes_volume, MAX (y2 - y1, 1.0));
+ clutter_paint_volume_set_depth (extremes_volume, z2 - z1);
+
+ clutter_paint_volume_union (volume, extremes_volume);
+ }
+
+ return TRUE;
+}
+
+static void
+animation_clutter_grid_effect_deform_vertex (ClutterDeformEffect *effect,
+ gfloat width G_GNUC_UNUSED,
+ gfloat height G_GNUC_UNUSED,
+ CoglTextureVertex *vertex)
+{
+ ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (effect);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+ AnimationVector uv = { vertex->tx, vertex->ty };
+ AnimationVector deformed;
+ float x, y;
+
+ animation_grid_animation_deform_uv_to_model_space (priv->grid_animation,
+ &uv,
+ &deformed);
+
+ clutter_actor_get_position (actor, &x, &y);
+
+ vertex->x = deformed.x - x;
+ vertex->y = deformed.y - y;
+}
+
+
+static gboolean
+animation_clutter_grid_effect_new_frame (gpointer user_data)
+{
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (user_data);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (grid_effect);
+ gint64 msecs = g_get_monotonic_time ();
+
+ static const unsigned int ms_to_us = 1000;
+
+ g_assert (priv->grid_animation);
+
+ /* Wraparound, priv->last_usecs -= G_MAXINT64.
+ * We make priv->last_usecs negative so that subtracting it
+ * from msecs results in the correct delta */
+ if (G_UNLIKELY (priv->last_usecs > msecs))
+ priv->last_usecs -= G_MAXINT64;
+
+ gint64 msecs_delta = (msecs - priv->last_usecs) / ms_to_us;
+ priv->last_usecs = msecs;
+
+ /* If there was no time movement, then we can't really step or remove
+ * models in a way that makes sense, so don't do it */
+ if (msecs_delta == 0)
+ return G_SOURCE_CONTINUE;
+
+ if (!animation_grid_animation_step (priv->grid_animation, msecs_delta))
+ {
+ /* Disable the effect */
+ clutter_actor_meta_set_enabled (meta, FALSE);
+
+ /* Finally, return false so that we don't keep animating */
+ priv->timeout_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+ else
+ {
+ clutter_actor_meta_set_enabled (meta, TRUE);
+ clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (grid_effect));
+ }
+
+ /* We always want to return true even if there was no time delta */
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+animation_clutter_grid_effect_ensure_timeline (AnimationClutterGridEffect *grid_effect)
+{
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ if (priv->timeout_id == 0)
+ {
+ static const unsigned int frame_length_ms = 16; /* 1000 / 60 */;
+
+ priv->last_usecs = g_get_monotonic_time ();
+ priv->timeout_id = g_timeout_add (frame_length_ms, animation_clutter_grid_effect_new_frame, grid_effect);
+
+ ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (grid_effect));
+
+ /* Make sure to show the actor so that we can see the animation
+ * if the animation was on open or unminimize */
+ clutter_actor_show (actor);
+ }
+}
+
+static void
+animation_clutter_grid_effect_notify (GObject *object,
+ GParamSpec *pspec)
+{
+ ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (object);
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (object);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ if (g_strcmp0 (pspec->name, "enabled") == 0)
+ {
+ if (clutter_actor_meta_get_enabled (actor_meta))
+ animation_clutter_grid_effect_ensure_timeline (grid_effect);
+ else
+ g_clear_handle_id (&priv->timeout_id, g_source_remove);
+ }
+
+ G_OBJECT_CLASS (animation_clutter_grid_effect_parent_class)->notify (object, pspec);
+}
+
+static void
+animation_clutter_grid_effect_set_actor (ClutterActorMeta *actor_meta,
+ ClutterActor *actor)
+{
+ CLUTTER_ACTOR_META_CLASS (animation_clutter_grid_effect_parent_class)->set_actor (actor_meta, actor);
+
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (actor_meta);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ /* Disable the effect before we do anything else - this ensures that
+ * for instance, we get the right paint box because we don't have applied
+ * effects that haven't had their paint boxes computed. */
+ clutter_actor_meta_set_enabled (actor_meta, FALSE);
+
+ g_clear_handle_id (&priv->timeout_id, g_source_remove);
+}
+
+static void
+animation_clutter_grid_effect_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (object);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ switch (prop_id)
+ {
+ case PROP_GRID_ANIMATION:
+ g_set_object (&priv->grid_animation, g_value_dup_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+animation_clutter_grid_effect_dispose (GObject *object)
+{
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (object);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ g_clear_object (&priv->grid_animation);
+
+ G_OBJECT_CLASS (animation_clutter_grid_effect_parent_class)->dispose (object);
+}
+
+static void
+animation_clutter_grid_effect_finalize (GObject *object)
+{
+ AnimationClutterGridEffect *grid_effect = ANIMATION_CLUTTER_GRID_EFFECT (object);
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (grid_effect);
+
+ g_clear_handle_id (&priv->timeout_id, g_source_remove);
+
+ G_OBJECT_CLASS (animation_clutter_grid_effect_parent_class)->finalize (object);
+}
+
+static void
+animation_clutter_grid_effect_init (AnimationClutterGridEffect *effect)
+{
+ AnimationClutterGridEffectPrivate *priv =
+ animation_clutter_grid_effect_get_instance_private (effect);
+
+ priv->timeout_id = 0;
+}
+
+static void
+animation_clutter_grid_effect_class_init (AnimationClutterGridEffectClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+ ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
+ ClutterDeformEffectClass *deform_class = CLUTTER_DEFORM_EFFECT_CLASS (klass);
+
+ object_class->notify = animation_clutter_grid_effect_notify;
+ object_class->set_property = animation_clutter_grid_effect_set_property;
+ object_class->dispose = animation_clutter_grid_effect_dispose;
+ object_class->finalize = animation_clutter_grid_effect_finalize;
+ meta_class->set_actor = animation_clutter_grid_effect_set_actor;
+ effect_class->modify_paint_volume = animation_clutter_grid_effect_modify_paint_volume;
+ deform_class->deform_vertex = animation_clutter_grid_effect_deform_vertex;
+
+ object_properties[PROP_GRID_ANIMATION] =
+ g_param_spec_object ("grid-animation",
+ "Grid Animation",
+ "The underlying grid animation",
+ ANIMATION_TYPE_GRID_ANIMATION,
+ G_PARAM_WRITABLE);
+
+ g_object_class_install_properties (object_class, PROP_LAST, object_properties);
+}
+
+ClutterEffect *
+animation_clutter_grid_effect_new (AnimationGridAnimation *grid_animation)
+{
+ return g_object_new (ANIMATION_CLUTTER_TYPE_GRID_EFFECT,
+ "grid-animation", grid_animation,
+ NULL);
+}
diff --git a/animation-clutter/animation-clutter-grid-effect.h b/animation-clutter/animation-clutter-grid-effect.h
new file mode 100644
index 0000000..9af2b5c
--- /dev/null
+++ b/animation-clutter/animation-clutter-grid-effect.h
@@ -0,0 +1,45 @@
+/*
+ * animation-clutter/animation-clutter-grid-effect.h
+ *
+ * Copyright © 2013-2016 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_CLUTTER_TYPE_GRID_EFFECT (animation_clutter_grid_effect_get_type ())
+G_DECLARE_FINAL_TYPE (AnimationClutterGridEffect, animation_clutter_grid_effect, ANIMATION_CLUTTER, GRID_EFFECT, ClutterDeformEffect)
+
+
+/**
+ * animation_clutter_grid_effect_new:
+ * @grid_animation: An #AnimationGridAnimation to wrap.
+ *
+ * Creates a new #ClutterEffect which uses the underlying
+ * AnimationGridAnimation to apply grid based effects to the actor.
+ *
+ * Returns: (transfer full): A new #ClutterEffect
+ */
+ClutterEffect * animation_clutter_grid_effect_new (AnimationGridAnimation *grid_animation);
+
+G_END_DECLS
diff --git a/animation-clutter/animation-clutter-wobbly-effect.c b/animation-clutter/animation-clutter-wobbly-effect.c
new file mode 100644
index 0000000..46d465a
--- /dev/null
+++ b/animation-clutter/animation-clutter-wobbly-effect.c
@@ -0,0 +1,523 @@
+/*
+ * animation-clutter/animation-clutter-wobbly-effect.c
+ *
+ * Copyright © 2013-2018 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "animation-clutter-common.h"
+#include "animation-clutter-common-private.h"
+#include "animation-clutter-wobbly-effect.h"
+
+struct _AnimationClutterWobblyEffect {
+ ClutterDeformEffect parent_instance;
+};
+
+typedef struct _AnimationClutterWobblyEffectPrivate
+{
+ float slowdown_factor;
+ double spring_constant;
+ double friction;
+ double movement_range;
+ AnimationWobblyModel *model;
+ AnimationWobblyAnchor *anchor;
+ gint64 last_msecs;
+ guint timeout_id;
+ guint width_changed_signal;
+ guint height_changed_signal;
+ gboolean ungrab_pending;
+} AnimationClutterWobblyEffectPrivate;
+
+enum
+{
+ PROP_0,
+
+ PROP_SPRING_K,
+ PROP_FRICTION,
+ PROP_SLOWDOWN_FACTOR,
+ PROP_OBJECT_MOVEMENT_RANGE,
+
+ PROP_LAST
+};
+
+static GParamSpec *object_properties[PROP_LAST];
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationClutterWobblyEffect,
+ animation_clutter_wobbly_effect,
+ CLUTTER_TYPE_DEFORM_EFFECT)
+
+static gboolean
+animation_clutter_wobbly_effect_modify_paint_volume (ClutterEffect *effect,
+ ClutterPaintVolume *volume)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (effect);
+ ClutterActor *actor = clutter_actor_meta_get_actor (meta);
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (effect);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ /* We assume that the parent's modify_paint_volume method always returns
+ * TRUE here. */
+ CLUTTER_EFFECT_CLASS (animation_clutter_wobbly_effect_parent_class)->modify_paint_volume (effect, volume);
+
+ if (priv->model && clutter_actor_meta_get_enabled (meta))
+ {
+ AnimationVector extremes[4];
+
+ animation_wobbly_model_query_extremes (priv->model,
+ &extremes[0],
+ &extremes[1],
+ &extremes[2],
+ &extremes[3]);
+
+ float x1 = MIN (extremes[0].x, extremes[2].x);
+ float y1 = MIN (extremes[0].y, extremes[1].y);
+ float x2 = MAX (extremes[1].x, extremes[3].x);
+ float y2 = MAX (extremes[2].y, extremes[3].y);
+
+ ClutterActorBox const extremesBox =
+ {
+ floor (x1),
+ floor (y1),
+ ceil (x2),
+ ceil (y2)
+ };
+
+ clutter_paint_volume_union_box (volume, &extremesBox);
+ }
+
+ return TRUE;
+}
+
+static void
+animation_clutter_wobbly_effect_deform_vertex (ClutterDeformEffect *effect,
+ gfloat x G_GNUC_UNUSED,
+ gfloat y G_GNUC_UNUSED,
+ CoglTextureVertex *vertex)
+{
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (effect);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ /* The reversal of ty and tx here is intentional */
+ AnimationVector uv = { vertex->ty, vertex->tx };
+ AnimationVector deformed;
+ animation_wobbly_model_deform_texcoords (priv->model,
+ uv,
+ &deformed);
+
+ vertex->x = deformed.x;
+ vertex->y = deformed.y;
+}
+
+static void
+remove_anchor_if_pending (AnimationClutterWobblyEffectPrivate *priv)
+{
+ if (priv->ungrab_pending)
+ {
+ g_clear_object (&priv->anchor);
+ priv->ungrab_pending = FALSE;
+ }
+}
+
+/* It turns out that clutter doesn't contain any mechanism whatsoever
+ * to do timeline-less animations. We're just using a timeout here
+ * to keep performing animations on the actor */
+static gboolean
+animation_clutter_wobbly_effect_new_frame (gpointer user_data)
+{
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (user_data);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+ gint64 msecs = g_get_monotonic_time ();
+
+ static const unsigned int ms_to_us = 1000;
+
+ g_assert (priv->model);
+
+ /* Wraparound, priv->last_msecs -= G_MAXINT64.
+ * We make priv->last_msecs negative so that subtracting it
+ * from msecs results in the correct delta */
+ if (G_UNLIKELY (priv->last_msecs > msecs))
+ priv->last_msecs -= G_MAXINT64;
+
+ gint64 msecs_delta = (msecs - priv->last_msecs ) / ms_to_us;
+ priv->last_msecs = msecs;
+
+ /* If there was no time movement, then we can't really step or remove
+ * models in a way that makes sense, so don't do it */
+ if (msecs_delta)
+ {
+ if (animation_wobbly_model_step (priv->model, msecs_delta / priv->slowdown_factor))
+ {
+ clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (wobbly_effect), TRUE);
+ clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (wobbly_effect));
+ }
+ else
+ {
+ remove_anchor_if_pending (priv);
+
+ /* Also disable the effect */
+ clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (wobbly_effect), FALSE);
+
+ /* Finally, return false so that we don't keep animating */
+ priv->timeout_id = -1;
+ return FALSE;
+ }
+ }
+
+ /* We always want to return true even if there was no time delta */
+ return TRUE;
+}
+
+static void
+animation_clutter_wobbly_effect_ensure_timeline (AnimationClutterWobblyEffect *wobbly_effect)
+{
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ if (priv->timeout_id == -1)
+ {
+ static const unsigned int frame_length_ms = 16; // 60 / 1000;
+
+ priv->last_msecs = g_get_monotonic_time ();
+ priv->timeout_id = g_timeout_add (frame_length_ms, animation_clutter_wobbly_effect_new_frame, wobbly_effect);
+ }
+}
+
+void
+animation_clutter_wobbly_effect_grab (AnimationClutterWobblyEffect *effect,
+ double x,
+ double y)
+{
+ ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (effect);
+
+ g_assert (!priv->anchor || priv->ungrab_pending);
+
+ /* Either ungrab here or at the end of the animation */
+ remove_anchor_if_pending (priv);
+
+ if (priv->model)
+ {
+ /* Make sure to update the model geometry and move
+ * to the right position, it may have changed
+ * in the meantime */
+ ClutterActorBox box;
+ float actor_paint_box_width, actor_paint_box_height;
+ animation_clutter_get_best_known_paint_extents_box (actor, &box);
+
+ /* See animation-clutter-common.c for why we need to do this */
+ animation_clutter_actor_box_enlarge_for_effects (&box);
+
+ actor_paint_box_width = box.x2 - box.x1;
+ actor_paint_box_height = box.y2 - box.y1;
+
+ AnimationVector position = { 0, 0 };
+ AnimationVector size = { actor_paint_box_width, actor_paint_box_height };
+
+ animation_wobbly_model_resize (priv->model, size);
+ animation_wobbly_model_move_to (priv->model, position);
+
+ animation_clutter_wobbly_effect_ensure_timeline (effect);
+
+ float actor_x, actor_y;
+ clutter_actor_get_position (actor, &actor_x, &actor_y);
+
+ AnimationVector anchor_position = { x - actor_x, y - actor_y };
+
+ priv->anchor = animation_wobbly_model_grab_anchor (priv->model, anchor_position);
+ }
+}
+
+void
+animation_clutter_wobbly_effect_ungrab (AnimationClutterWobblyEffect *effect)
+{
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (effect);
+
+ g_assert (priv->anchor && !priv->ungrab_pending);
+
+ /* Don't immediately ungrab. We can be a little bit more
+ * clever here and make the ungrab pending on the completion
+ * of the animation */
+ if (priv->timeout_id != -1)
+ priv->ungrab_pending = TRUE;
+ else
+ g_clear_object (&priv->anchor);
+}
+
+void
+animation_clutter_wobbly_effect_move_by (AnimationClutterWobblyEffect *effect,
+ double dx,
+ double dy)
+{
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (effect);
+
+ if (priv->anchor)
+ {
+ AnimationVector delta = { dx, dy };
+
+ animation_clutter_wobbly_effect_ensure_timeline (effect);
+ animation_wobbly_anchor_move_by (priv->anchor, delta);
+
+ AnimationVector reverse_delta = delta;
+ reverse_delta.x *= -1;
+ reverse_delta.y *= -1;
+
+ /* Now move the entire model back - this ensures that
+ * we stay in sync with the actor's relative position */
+ animation_wobbly_model_move_by (priv->model, reverse_delta);
+ }
+}
+
+static void
+animation_clutter_wobbly_effect_size_changed (GObject *object,
+ GParamSpec *spec G_GNUC_UNUSED,
+ gpointer user_data)
+{
+ ClutterActor *actor = CLUTTER_ACTOR (object);
+ AnimationClutterWobblyEffect *effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (user_data);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (effect);
+
+ /* We don't ensure a timeline here because we only want to redistribute
+ * non-anchor points if we're already grabbed, which the wobbly effect will
+ * do internally anyways */
+ if (priv->model)
+ {
+ ClutterActorBox box;
+ float actor_paint_box_width, actor_paint_box_height;
+ animation_clutter_get_best_known_paint_extents_box (actor, &box);
+
+ /* See animation-clutter-common.c for why we need to do this */
+ animation_clutter_actor_box_enlarge_for_effects (&box);
+
+ actor_paint_box_width = box.x2 - box.x1;
+ actor_paint_box_height = box.y2 - box.y1;
+
+ /* If we have any pending anchors, we should release them now -
+ * the model move and resize code explicitly does not move
+ * anchors around (because that'd put them out of sync with
+ * the cursor) */
+ remove_anchor_if_pending (priv);
+
+ AnimationVector actor_size = { actor_paint_box_width, actor_paint_box_height };
+ AnimationVector actor_position = { 0.0, 0.0 };
+
+ g_message ("Actor paint box size %f %f %f %f\n", box.x1, box.y1, actor_paint_box_width, actor_paint_box_height);
+ animation_wobbly_model_resize (priv->model, actor_size);
+ animation_wobbly_model_move_to (priv->model, actor_position);
+ }
+}
+
+static void
+animation_clutter_wobbly_effect_set_actor (ClutterActorMeta *actor_meta,
+ ClutterActor *actor)
+{
+ ClutterActor *prev_actor = clutter_actor_meta_get_actor (actor_meta);
+
+ CLUTTER_ACTOR_META_CLASS (animation_clutter_wobbly_effect_parent_class)->set_actor (actor_meta, actor);
+
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (actor_meta);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ g_clear_object (&priv->anchor);
+ g_clear_object (&priv->model);
+
+ priv->ungrab_pending = FALSE;
+
+ if (priv->timeout_id != -1)
+ {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = -1;
+ }
+
+ if (prev_actor)
+ {
+ g_signal_handler_disconnect (prev_actor, priv->width_changed_signal);
+ priv->width_changed_signal = 0;
+
+ g_signal_handler_disconnect (prev_actor, priv->height_changed_signal);
+ priv->height_changed_signal = 0;
+ }
+
+ if (actor)
+ {
+ ClutterActorBox box;
+ float actor_paint_box_width, actor_paint_box_height;
+ animation_clutter_get_best_known_paint_extents_box (actor, &box);
+
+ actor_paint_box_width = box.x2 - box.x1;
+ actor_paint_box_height = box.y2 - box.y1;
+
+ AnimationVector actor_position = { 0, 0 };
+ AnimationVector actor_size = { actor_paint_box_width, actor_paint_box_height };
+
+ priv->model = animation_wobbly_model_new (actor_position,
+ actor_size,
+ priv->spring_constant,
+ priv->friction,
+ priv->movement_range);
+
+ priv->width_changed_signal =
+ g_signal_connect_object (actor,
+ "notify::width",
+ G_CALLBACK (animation_clutter_wobbly_effect_size_changed),
+ wobbly_effect,
+ G_CONNECT_AFTER);
+ priv->height_changed_signal =
+ g_signal_connect_object (actor,
+ "notify::height",
+ G_CALLBACK (animation_clutter_wobbly_effect_size_changed),
+ wobbly_effect,
+ G_CONNECT_AFTER);
+ }
+
+ /* Whatever the actor, ensure that the effect is disabled at this point */
+ clutter_actor_meta_set_enabled (actor_meta, FALSE);
+}
+
+static void
+animation_clutter_wobbly_effect_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (object);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ switch (prop_id)
+ {
+ case PROP_SPRING_K:
+ priv->spring_constant = g_value_get_double (value);
+
+ if (priv->model != NULL)
+ animation_wobbly_model_set_spring_k (priv->model, priv->spring_constant);
+ break;
+ case PROP_FRICTION:
+ priv->friction = g_value_get_double (value);
+
+ if (priv->model != NULL)
+ animation_wobbly_model_set_friction (priv->model, priv->friction);
+ break;
+ case PROP_SLOWDOWN_FACTOR:
+ priv->slowdown_factor = g_value_get_double (value);
+ break;
+ case PROP_OBJECT_MOVEMENT_RANGE:
+ priv->movement_range = g_value_get_double (value);
+
+ if (priv->model != NULL)
+ animation_wobbly_model_set_maximum_range (priv->model, priv->movement_range);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+animation_clutter_wobbly_effect_finalize (GObject *object)
+{
+ AnimationClutterWobblyEffect *wobbly_effect = ANIMATION_CLUTTER_WOBBLY_EFFECT (object);
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (wobbly_effect);
+
+ g_clear_object (&priv->model);
+
+ if (priv->timeout_id != -1)
+ {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = -1;
+ }
+
+ G_OBJECT_CLASS (animation_clutter_wobbly_effect_parent_class)->finalize (object);
+}
+
+static void
+animation_clutter_wobbly_effect_init (AnimationClutterWobblyEffect *effect)
+{
+ AnimationClutterWobblyEffectPrivate *priv =
+ animation_clutter_wobbly_effect_get_instance_private (effect);
+
+ priv->timeout_id = -1;
+}
+
+static void
+animation_clutter_wobbly_effect_class_init (AnimationClutterWobblyEffectClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+ ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
+ ClutterDeformEffectClass *deform_class = CLUTTER_DEFORM_EFFECT_CLASS (klass);
+
+ object_class->set_property = animation_clutter_wobbly_effect_set_property;
+ object_class->finalize = animation_clutter_wobbly_effect_finalize;
+ meta_class->set_actor = animation_clutter_wobbly_effect_set_actor;
+ effect_class->modify_paint_volume = animation_clutter_wobbly_effect_modify_paint_volume;
+ deform_class->deform_vertex = animation_clutter_wobbly_effect_deform_vertex;
+
+ object_properties[PROP_SPRING_K] =
+ g_param_spec_double ("spring-k",
+ "Spring Constant",
+ "How springy the model is",
+ 2.0, 10.0, 8.0,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
+
+ object_properties[PROP_FRICTION] =
+ g_param_spec_double ("friction",
+ "Friction Constant",
+ "How much friction force should be applied to moving objects",
+ 2.0, 10.0, 3.0,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
+
+ object_properties[PROP_SLOWDOWN_FACTOR] =
+ g_param_spec_double ("slowdown-factor",
+ "Slowdown Factor",
+ "How much to slow the model's timesteps down",
+ 1.0, 5.0, 1.0,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
+
+ object_properties[PROP_OBJECT_MOVEMENT_RANGE] =
+ g_param_spec_double ("object-movement-range",
+ "Object Movement Range",
+ "How much objects are allowed to move around",
+ 10.0, 500.0, 100.0,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
+
+ g_object_class_install_properties (object_class, PROP_LAST, object_properties);
+}
+
+ClutterEffect *
+animation_clutter_wobbly_effect_new (void)
+{
+ return g_object_new (ANIMATION_CLUTTER_TYPE_WOBBLY, NULL);
+}
diff --git a/animation-clutter/animation-clutter-wobbly-effect.h b/animation-clutter/animation-clutter-wobbly-effect.h
new file mode 100644
index 0000000..e68eb8a
--- /dev/null
+++ b/animation-clutter/animation-clutter-wobbly-effect.h
@@ -0,0 +1,90 @@
+/*
+ * animation-clutter/animation-clutter-wobbly-effect.h
+ *
+ * Copyright © 2013-2016 Endless Mobile, Inc.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Sam Spilsbury
+ */
+
+#pragma once
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_CLUTTER_TYPE_WOBBLY animation_clutter_wobbly_effect_get_type ()
+G_DECLARE_FINAL_TYPE (AnimationClutterWobblyEffect, animation_clutter_wobbly_effect, ANIMATION_CLUTTER, WOBBLY_EFFECT, ClutterDeformEffect)
+
+/**
+ * animation_clutter_wobbly_effect_grab:
+ * @effect: An #AnimationClutterWobblyEffect
+ * @x: The x-coordinate on the mesh to grab, specified relative to the
+ * upper-left corner of the mesh
+ * @y: The y-coordinate on the mesh to grab, specified relative to the
+ * upper-left corner of the mesh.
+ *
+ * Grabs the anchor specified by @x and @y on the mesh. While
+ * the mesh is in this state, this point will move immediately,
+ * causing spring forces to be applied to other points on the mesh
+ *
+ * It is a precondition violation to call this function when the mesh is
+ * already grabbed.
+ *
+ */
+void animation_clutter_wobbly_effect_grab (AnimationClutterWobblyEffect *effect,
+ double x,
+ double y);
+
+/**
+ * animation_clutter_wobbly_effect_ungrab:
+ * @effect: An #AnimationClutterWobblyEffect
+ * Removes the current grab. When the actor is moved, the mesh will
+ * move uniformly.
+ *
+ * It is a precondition violation to call this function when the mesh is
+ * not grabbed.
+ */
+void animation_clutter_wobbly_effect_ungrab (AnimationClutterWobblyEffect *effect);
+
+/**
+ * animation_clutter_wobbly_effect_move_by:
+ * @effect: An #AnimationClutterWobblyEffect
+ * @dx: A delta-x coordinate to move the mesh by
+ * @dy: A delta-y coordinate to move the mesh by
+ *
+ * Moves the mesh by @dx and @dy
+ *
+ * If the mesh is grabbed, then spring forces will be applied causing
+ * some points on the mesh to move more slowly than others. The nature
+ * of the moment will depend on the window's maximization state.
+ *
+ */
+void animation_clutter_wobbly_effect_move_by (AnimationClutterWobblyEffect *effect,
+ double dx,
+ double dy);
+
+/**
+ * animation_clutter_wobbly_effect_new:
+ *
+ * Creates a new #ClutterEffect which makes the window "wobble"
+ * on a spring mesh for the actor
+ *
+ * Returns: (transfer full): A new #ClutterEffect
+ */
+ClutterEffect * animation_clutter_wobbly_effect_new (void);
+
+G_END_DECLS
diff --git a/animation-clutter/meson.build b/animation-clutter/meson.build
new file mode 100644
index 0000000..074cb52
--- /dev/null
+++ b/animation-clutter/meson.build
@@ -0,0 +1,108 @@
+# animation-clutter/meson.build
+#
+# Copyright (C) 2017, 2018 Endless Mobile, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Meson build definitions for clutter backend to libanimation.
+
+api_version = '0'
+
+animation_clutter_introspectable_sources = files([])
+animation_clutter_private_headers = files([])
+animation_clutter_private_sources = files([])
+animation_clutter_headers = files([])
+animation_clutter_headers_subdir = 'animation-clutter'
+animation_clutter_sources = files([])
+
+animation_clutter_toplevel_private_headers = files([
+ 'animation-clutter-common-private.h'
+])
+animation_clutter_toplevel_headers = files([
+ 'animation-clutter-affine-effect.h',
+ 'animation-clutter-actor-box-query.h',
+ 'animation-clutter-common.h',
+ 'animation-clutter-grid-effect.h',
+ 'animation-clutter-wobbly-effect.h'
+])
+
+animation_clutter_toplevel_private_sources = files([])
+animation_clutter_toplevel_introspectable_sources = files([
+ 'animation-clutter-affine-effect.c',
+ 'animation-clutter-actor-box-query.c',
+ 'animation-clutter-common.c',
+ 'animation-clutter-grid-effect.c',
+ 'animation-clutter-wobbly-effect.c'
+])
+
+animation_clutter_introspectable_sources += animation_clutter_toplevel_introspectable_sources
+animation_clutter_private_sources += animation_clutter_toplevel_private_sources
+animation_clutter_headers += animation_clutter_toplevel_headers
+animation_clutter_private_headers += animation_clutter_toplevel_private_headers
+
+install_headers(animation_clutter_toplevel_headers, subdir: animation_clutter_headers_subdir)
+
+animation_clutter_sources = animation_clutter_introspectable_sources + animation_clutter_private_sources
+
+glib = dependency('glib-2.0')
+gobject = dependency('gobject-2.0')
+clutter = dependency('mutter-clutter-8')
+mutter = dependency('libmutter-8')
+
+mutter_typelibdir = mutter.get_pkgconfig_variable('typelibdir')
+install_rpath = mutter_typelibdir
+
+animation_clutter_lib = shared_library(
+ 'animation-clutter',
+ animation_clutter_sources,
+ soversion: api_version,
+ install: true,
+ include_directories: [ animation_inc ],
+ dependencies: [ clutter, glib, gobject, mutter, animation_dep, animation_glib_dep ],
+ build_rpath: mutter_typelibdir,
+ install_rpath: mutter_typelibdir
+)
+
+animation_clutter_dep = declare_dependency(
+ link_with: animation_clutter_lib,
+ include_directories: [ animation_inc ],
+)
+
+introspection_sources = [ animation_clutter_introspectable_sources, animation_clutter_headers ]
+
+gnome = import('gnome')
+animation_clutter_gir = gnome.generate_gir(
+ animation_clutter_lib,
+ extra_args: ['--warn-all', '--warn-error'],
+ identifier_prefix: 'AnimationClutter',
+ include_directories: animation_inc,
+ includes: [animation_glib_gir, 'Clutter-8', 'GLib-2.0', 'GObject-2.0'],
+ install: true,
+ namespace: 'AnimationClutter',
+ nsversion: api_version,
+ sources: introspection_sources,
+ symbol_prefix: 'animation_clutter'
+)[0]
+
+pkg = import('pkgconfig')
+pkg.generate(
+ description: 'Library to provide 2D surface animations (Clutter Implementation)',
+ name: 'libanimation-clutter',
+ filebase: 'libanimation-clutter-' + api_version,
+ version: meson.project_version(),
+ libraries: animation_clutter_lib,
+ install_dir: join_paths(get_option('libdir'), 'pkgconfig')
+)
+
diff --git a/animation-glib/bounce/bounce.cpp b/animation-glib/bounce/bounce.cpp
new file mode 100644
index 0000000..f262e7e
--- /dev/null
+++ b/animation-glib/bounce/bounce.cpp
@@ -0,0 +1,336 @@
+/*
+ * animation-glib/bounce/bounce.cpp
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject implementation for a "bounce" animation.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace agd = animation::geometry::dimension;
+namespace agl = animation::glib;
+namespace ab = animation::bounce;
+namespace ag = animation::glib;
+namespace as = animation::stepper;
+namespace asg = animation::stepper::glib;
+namespace at = animation::transform;
+
+struct _AnimationBounceAnimation
+{
+ AnimationTransformAnimation parent_instance;
+};
+
+typedef struct _AnimationBounceAnimationPrivate
+{
+} AnimationBounceAnimationPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationBounceAnimation,
+ animation_bounce_animation,
+ ANIMATION_TYPE_TRANSFORM_ANIMATION)
+
+enum {
+ PROP_0,
+ PROP_INITIAL_SCALE,
+ PROP_MAXIMUM_SCALE,
+ PROP_N_BOUNCE,
+ PROP_TARGET,
+ PROP_STEPPER,
+ NPROPS
+};
+
+static GParamSpec *animation_bounce_animation_props [NPROPS] = { NULL, };
+
+double
+animation_bounce_animation_get_initial_scale (AnimationBounceAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->InitialScale ();
+}
+
+void
+animation_bounce_animation_set_initial_scale (AnimationBounceAnimation *animation,
+ double initial_scale)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->InitialScale (initial_scale);
+}
+
+double
+animation_bounce_animation_get_maximum_scale (AnimationBounceAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->MaximumScale ();
+}
+
+void
+animation_bounce_animation_set_maximum_scale (AnimationBounceAnimation *animation,
+ double maximum_scale)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->MaximumScale (maximum_scale);
+}
+
+unsigned int
+animation_bounce_animation_get_n_bounce (AnimationBounceAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->NBounce ();
+}
+
+void
+animation_bounce_animation_set_n_bounce (AnimationBounceAnimation *animation,
+ unsigned int n_bounce)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->NBounce (n_bounce);
+}
+
+void
+animation_bounce_animation_set_target (AnimationBounceAnimation *animation,
+ AnimationBoxQuery *target)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Target (std::make_shared (target));
+}
+
+/**
+ * animation_bounce_animation_get_target:
+ * @animation: An #AnimationBoxQuery
+ *
+ * Returns: (transfer none): Get the #AnimationBoxQuery target for this #AnimationBounceAnimation
+ */
+AnimationBoxQuery *
+animation_bounce_animation_get_target (AnimationBounceAnimation *animation)
+{
+ return std::static_pointer_cast (LookupTypedInterfaceProp (G_OBJECT (animation))->Target ())->BoxQuery ();
+}
+
+void
+animation_bounce_animation_set_stepper (AnimationBounceAnimation *animation,
+ AnimationStepper *stepper)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (std::make_shared (stepper));
+}
+
+/**
+ * animation_bounce_animation_get_stepper:
+ * @animation: An #AnimationBounceAnimation
+ *
+ * Returns: (transfer none): Get the #AnimationStepper for this #AnimationBounceAnimation
+ */
+AnimationStepper *
+animation_bounce_animation_get_stepper (AnimationBounceAnimation *animation)
+{
+ auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ());
+
+ return std::static_pointer_cast (stepper)->BaseStepper ();
+}
+
+static void
+animation_bounce_animation_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_INITIAL_SCALE:
+ animation_bounce_animation_set_initial_scale (ANIMATION_BOUNCE_ANIMATION (object),
+ g_value_get_double (value));
+ break;
+ case PROP_MAXIMUM_SCALE:
+ animation_bounce_animation_set_maximum_scale (ANIMATION_BOUNCE_ANIMATION (object),
+ g_value_get_double (value));
+ break;
+ case PROP_N_BOUNCE:
+ animation_bounce_animation_set_n_bounce (ANIMATION_BOUNCE_ANIMATION (object),
+ g_value_get_uint (value));
+ break;
+ case PROP_TARGET:
+ animation_bounce_animation_set_target (ANIMATION_BOUNCE_ANIMATION (object),
+ ANIMATION_BOX_QUERY (g_value_get_object (value)));
+ break;
+ case PROP_STEPPER:
+ animation_bounce_animation_set_stepper (ANIMATION_BOUNCE_ANIMATION (object),
+ ANIMATION_STEPPER (g_value_get_object (value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_bounce_animation_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationBounceAnimation *bounce_animation = ANIMATION_BOUNCE_ANIMATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_INITIAL_SCALE:
+ g_value_set_double (value, animation_bounce_animation_get_initial_scale (bounce_animation));
+ break;
+ case PROP_MAXIMUM_SCALE:
+ g_value_set_double (value, animation_bounce_animation_get_maximum_scale (bounce_animation));
+ break;
+ case PROP_N_BOUNCE:
+ g_value_set_uint (value, animation_bounce_animation_get_n_bounce (bounce_animation));
+ break;
+ case PROP_TARGET:
+ g_value_set_object (value, animation_bounce_animation_get_target (bounce_animation));
+ break;
+ case PROP_STEPPER:
+ g_value_set_object (value, animation_bounce_animation_get_stepper (bounce_animation));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static GObject *
+animation_bounce_animation_constructor (GType type,
+ unsigned int n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ auto *interface = InterfaceConstructor ::construct ();
+ auto *transform_interface = static_cast (interface);
+
+ /* We need to also set defaults for certain properties in order
+ * to ensure that they are bindable later on, in case they are
+ * not set by the caller. */
+ replace_named_pointer_props_in_construct_params_if_null (
+ construct_params,
+ n_construct_params,
+ {
+ ReplacePropSpec ("stepper", g_value_get_object, g_value_set_object, []() -> gpointer {
+ return animation_linear_stepper_new (1);
+ }),
+ ReplacePropSpec ("target", g_value_get_object, g_value_set_object, []() -> gpointer {
+ return animation_box_query_new ();
+ })
+ }
+ );
+
+ replace_interface_prop_in_construct_params (construct_params,
+ n_construct_params,
+ transform_interface);
+
+ return G_OBJECT_CLASS (animation_bounce_animation_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+}
+
+static void
+animation_bounce_animation_constructed (GObject *object)
+{
+ /* Take a size-zero step, which ensures that we update the
+ * internal state of the animation with all the properties we
+ * just set */
+ animation_transform_animation_step (ANIMATION_TRANSFORM_ANIMATION (object), 0);
+}
+
+static void
+animation_bounce_animation_init (AnimationBounceAnimation *model)
+{
+}
+
+
+static void
+animation_bounce_animation_class_init (AnimationBounceAnimationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = animation_bounce_animation_constructor;
+ object_class->constructed = animation_bounce_animation_constructed;
+ object_class->get_property = animation_bounce_animation_get_property;
+ object_class->set_property = animation_bounce_animation_set_property;
+
+ animation_bounce_animation_props[PROP_INITIAL_SCALE] =
+ g_param_spec_double ("initial-scale",
+ "Initial Scale",
+ "The initial scale of the animation",
+ 0.1,
+ 1.0,
+ 0.7,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_bounce_animation_props[PROP_MAXIMUM_SCALE] =
+ g_param_spec_double ("maximum-scale",
+ "Maximum Scale",
+ "The maximum scale of the animation",
+ 1.0,
+ 3.0,
+ 1.2,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_bounce_animation_props[PROP_N_BOUNCE] =
+ g_param_spec_uint ("n-bounce",
+ "Number of Bounces",
+ "The number of bounces in the animation",
+ 1,
+ 10,
+ 1,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_bounce_animation_props[PROP_TARGET] =
+ g_param_spec_object ("target",
+ "Target Box",
+ "Box that we are animating to",
+ ANIMATION_TYPE_BOX_QUERY,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_bounce_animation_props[PROP_STEPPER] =
+ g_param_spec_object ("stepper",
+ "Stepper",
+ "Stepper to use to progress the animation",
+ ANIMATION_TYPE_STEPPER,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_properties (object_class,
+ NPROPS,
+ animation_bounce_animation_props);
+}
+
+/**
+ * animation_bounce_new:
+ * @initial_scale: Scale factor that the surface will initially have.
+ * @maximum_scale: Scale factor that the surface will have at maximum.
+ * @n_bounce: Number of bounces.
+ * @target: The #AnimationBoxQuery that we are animating to.
+ * @stepper: The #AnimationStepper of the animation.
+ *
+ * Returns: (transfer full): A new #AnimationBounceAnimation.
+ */
+AnimationBounceAnimation *
+animation_bounce_new (double initial_scale,
+ double maximum_scale,
+ unsigned int n_bounce,
+ const AnimationBoxQuery *target,
+ AnimationStepper *stepper)
+{
+ return ANIMATION_BOUNCE_ANIMATION (g_object_new (ANIMATION_TYPE_BOUNCE_ANIMATION,
+ "initial-scale", initial_scale,
+ "maximum-scale", maximum_scale,
+ "n-bounce", n_bounce,
+ "target", target,
+ "stepper", stepper,
+ NULL));
+}
diff --git a/animation-glib/bounce/bounce.h b/animation-glib/bounce/bounce.h
new file mode 100644
index 0000000..4315fb3
--- /dev/null
+++ b/animation-glib/bounce/bounce.h
@@ -0,0 +1,63 @@
+/*
+ * animation-glib/bounce/bounce.h
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject Interface for "bounce" animation.
+ */
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_TYPE_BOUNCE_ANIMATION animation_bounce_animation_get_type ()
+G_DECLARE_FINAL_TYPE (AnimationBounceAnimation, animation_bounce_animation, ANIMATION, BOUNCE_ANIMATION, AnimationTransformAnimation)
+
+double animation_bounce_animation_get_initial_scale (AnimationBounceAnimation *animation);
+void animation_bounce_animation_set_initial_scale (AnimationBounceAnimation *animation,
+ double initial_scale);
+
+double animation_bounce_animation_get_maximum_scale (AnimationBounceAnimation *animation);
+void animation_bounce_animation_set_maximum_scale (AnimationBounceAnimation *animation,
+ double maximum_scale);
+
+unsigned int animation_bounce_animation_get_n_bounce (AnimationBounceAnimation *animation);
+void animation_bounce_animation_set_n_bounce (AnimationBounceAnimation *animation,
+ unsigned int n_bounce);
+
+void animation_bounce_animation_set_stepper (AnimationBounceAnimation *animation,
+ AnimationStepper *stepper);
+AnimationStepper * animation_bounce_animation_get_stepper (AnimationBounceAnimation *animation);
+
+void animation_bounce_animation_set_target (AnimationBounceAnimation *animation,
+ AnimationBoxQuery *target);
+AnimationBoxQuery * animation_bounce_animation_get_target (AnimationBounceAnimation *animation);
+
+AnimationBounceAnimation * animation_bounce_new (double initial_scale,
+ double maximum_scale,
+ unsigned int n_bounce,
+ const AnimationBoxQuery *target,
+ AnimationStepper *stepper);
+
+G_END_DECLS
+
+#pragma once
diff --git a/animation-glib/bounce/meson.build b/animation-glib/bounce/meson.build
new file mode 100644
index 0000000..44c2279
--- /dev/null
+++ b/animation-glib/bounce/meson.build
@@ -0,0 +1,32 @@
+# animation-glib/bounce/meson.build
+#
+# Copyright (C) 2017, 2018 Endless Mobile, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Build the libanimation library (bounce animation component), GObject bindings.
+
+bounce_introspectable_sources = files([
+ 'bounce.cpp'
+])
+
+bounce_headers = files([
+ 'bounce.h'
+])
+
+animation_glib_introspectable_sources += bounce_introspectable_sources
+animation_glib_headers += bounce_headers
+
+install_headers(bounce_headers, subdir: join_paths(animation_headers_subdir, 'bounce'))
diff --git a/animation-glib/box.cpp b/animation-glib/box.cpp
new file mode 100644
index 0000000..00af7b3
--- /dev/null
+++ b/animation-glib/box.cpp
@@ -0,0 +1,40 @@
+/*
+ * animation-glib/box.cpp
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject Interface for "wobbly" textures, box
+ * type implementation.
+ */
+
+#include
+
+static gpointer
+animation_box_copy (gpointer ptr)
+{
+ AnimationBox *src = reinterpret_cast (ptr);
+ AnimationBox *dst = g_new0 (AnimationBox, 1);
+
+ *dst = *src;
+
+ return reinterpret_cast (dst);
+}
+
+G_DEFINE_BOXED_TYPE (AnimationBox,
+ animation_box,
+ animation_box_copy,
+ g_free);
diff --git a/animation-glib/box.h b/animation-glib/box.h
new file mode 100644
index 0000000..b583475
--- /dev/null
+++ b/animation-glib/box.h
@@ -0,0 +1,39 @@
+/*
+ * animation-glib/box.h
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject Interface for "wobbly" textures, 2D box type.
+ */
+#pragma once
+
+#include
+
+#include
+
+G_BEGIN_DECLS
+
+typedef struct {
+ AnimationVector top_left;
+ AnimationVector bottom_right;
+} AnimationBox;
+
+#define ANIMATION_TYPE_BOX animation_box_get_type ()
+
+GType animation_box_get_type ();
+
+G_END_DECLS
diff --git a/animation-glib/constructor-helpers.cpp b/animation-glib/constructor-helpers.cpp
new file mode 100644
index 0000000..522a7a2
--- /dev/null
+++ b/animation-glib/constructor-helpers.cpp
@@ -0,0 +1,139 @@
+/*
+ * animation-glib/constructor-helpers.cpp
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * Helpers for constructing C++ objects directly from GObject properties
+ * in a GObject constructor.
+ */
+
+#include
+
+#include "constructor-helpers.h"
+
+/**
+ * replace_construct_param:
+ * @construct_params: (array length=n_construct_params) An array of #GObjectConstructParam
+ * @n_construct_params: Number of elements in @construct_params.
+ * @prop_name: The name of the construct prop to replace the value of.
+ * @initialize_func: A function which sets the GValue to something sensible.
+ *
+ * Replace a construction parameter @prop_name in the
+ * passed @construct_params by using the passed @initialize_func.
+ *
+ * This function must always replace one construct parameter, it is
+ * an error to pass a @prop_name that is not in the @construct_params.
+ */
+void
+replace_construct_param (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ AnimationConstructorHelpersInitializeValueFunc initialize_func,
+ gpointer initialize_func_data)
+{
+ /* The prop should always be found in the array so that we can replace
+ * it, this function doesn't support appending the prop. That means
+ * that the relevant prop must always G_PARAM_CONSTRUCT or
+ * G_PARAM_CONSTRUCT_ONLY. */
+ for (unsigned int i = 0; i < n_construct_params; ++i)
+ {
+ if (g_strcmp0 (construct_params[i].pspec->name, prop_name) == 0)
+ {
+ g_value_unset (construct_params[i].value);
+ initialize_func (construct_params[i].value, initialize_func_data);
+ return;
+ }
+ }
+
+ g_assert_not_reached ();
+}
+
+template
+static typename std::result_of ::type
+invoke_function_thunk (Args... args, gpointer lambda)
+{
+ FunctionType *f = reinterpret_cast (lambda);
+
+ return (*f)(args...);
+}
+
+
+void
+replace_named_pointer_prop_in_construct_params (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ gpointer ptr)
+{
+ auto set_value = [ptr](GValue *value) {
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, ptr);
+ };
+ replace_construct_param (construct_params,
+ n_construct_params,
+ prop_name,
+ (AnimationConstructorHelpersInitializeValueFunc) invoke_function_thunk ,
+ &set_value);
+}
+
+void
+replace_interface_prop_in_construct_params (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ gpointer interface)
+{
+ replace_named_pointer_prop_in_construct_params (construct_params,
+ n_construct_params,
+ "interface",
+ interface);
+}
+
+void
+replace_named_pointer_prop_in_construct_params_if_null (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ AnimationConstructorHelpersGValueGetPointerFunc get_func,
+ AnimationConstructorHelpersGValueSetPointerFunc set_func,
+ AnimationConstructorHelpersConstructDefaultValueFunc construct_func)
+{
+ /* The prop should always be found in the array so that we can replace
+ * it, this function doesn't support appending the prop. That means
+ * that the relevant prop must always G_PARAM_CONSTRUCT or
+ * G_PARAM_CONSTRUCT_ONLY. */
+ for (unsigned int i = 0; i < n_construct_params; ++i)
+ {
+ if (g_strcmp0 (construct_params[i].pspec->name, prop_name) == 0)
+ {
+ if (get_func (construct_params[i].value) == nullptr)
+ set_func (construct_params[i].value, construct_func ());
+
+ return;
+ }
+ }
+
+ g_assert_not_reached ();
+}
+
+void replace_named_pointer_props_in_construct_params_if_null (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ std::initializer_list replace_specs)
+{
+ for (auto const &spec : replace_specs) {
+ replace_named_pointer_prop_in_construct_params_if_null (construct_params,
+ n_construct_params,
+ spec.prop_name,
+ spec.get_func,
+ spec.set_func,
+ spec.construct_func);
+ }
+}
diff --git a/animation-glib/constructor-helpers.h b/animation-glib/constructor-helpers.h
new file mode 100644
index 0000000..c6f9218
--- /dev/null
+++ b/animation-glib/constructor-helpers.h
@@ -0,0 +1,130 @@
+/*
+ * animation-glib/constructor-helpers.cpp
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * Helpers for constructing C++ objects directly from GObject properties
+ * in a GObject constructor.
+ */
+
+#pragma once
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+inline GValue *
+lookup_gvalue (GHashTable *ht, const char *key)
+{
+ return reinterpret_cast (g_hash_table_lookup (ht, key));
+}
+
+typedef void (*AnimationConstructorHelpersInitializeValueFunc) (GValue *value,
+ gpointer user_data);
+
+void replace_construct_param (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ AnimationConstructorHelpersInitializeValueFunc initialize_func,
+ gpointer initialize_func_data);
+
+void replace_named_pointer_prop_in_construct_params (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ gpointer ptr);
+
+void replace_interface_prop_in_construct_params (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ gpointer interface);
+
+typedef gpointer (*AnimationConstructorHelpersGValueGetPointerFunc) (const GValue *value);
+typedef void (*AnimationConstructorHelpersGValueSetPointerFunc) (GValue *value, gpointer);
+typedef gpointer (*AnimationConstructorHelpersConstructDefaultValueFunc) (void);
+
+void replace_named_pointer_prop_in_construct_params_if_null (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ const char *prop_name,
+ AnimationConstructorHelpersGValueGetPointerFunc get_func,
+ AnimationConstructorHelpersGValueSetPointerFunc set_func,
+ AnimationConstructorHelpersConstructDefaultValueFunc construct_func);
+
+G_END_DECLS
+
+#ifdef __cplusplus
+struct ReplacePropSpec
+{
+ ReplacePropSpec (const char *prop_name,
+ AnimationConstructorHelpersGValueGetPointerFunc get_func,
+ AnimationConstructorHelpersGValueSetPointerFunc set_func,
+ AnimationConstructorHelpersConstructDefaultValueFunc construct_func) :
+ prop_name (prop_name),
+ get_func (get_func),
+ set_func (set_func),
+ construct_func (construct_func)
+ {
+ }
+
+ const char *prop_name;
+ AnimationConstructorHelpersGValueGetPointerFunc get_func;
+ AnimationConstructorHelpersGValueSetPointerFunc set_func;
+ AnimationConstructorHelpersConstructDefaultValueFunc construct_func;
+};
+
+void replace_named_pointer_props_in_construct_params_if_null (GObjectConstructParam *construct_params,
+ unsigned int n_construct_params,
+ std::initializer_list replace_specs);
+
+template
+typename std::result_of ::type ForwardFromValueHT (GHashTable *ht,
+ Marshaller &&m,
+ const char *name)
+{
+ return m (lookup_gvalue (ht, name));
+}
+
+template
+struct InterfaceConstructor
+{
+ template
+ static Interface * construct (ArgTypes&&... args)
+ {
+ return new Interface (args...);
+ }
+};
+
+template
+DerivedType * LookupTypedInterfaceProp (GObject *object)
+{
+ InterfaceType *iface = nullptr;
+ g_object_get (object, "interface", (gpointer) &iface, NULL);
+
+ return static_cast (iface);
+}
+#endif
diff --git a/animation-glib/glide/glide.cpp b/animation-glib/glide/glide.cpp
new file mode 100644
index 0000000..d176286
--- /dev/null
+++ b/animation-glib/glide/glide.cpp
@@ -0,0 +1,440 @@
+/*
+ * animation-glib/glide/glide.cpp
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject implementation for a "glide" animation.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace agd = animation::geometry::dimension;
+namespace ag = animation::glide;
+namespace agl = animation::glib;
+namespace at = animation::transform;
+namespace asg = animation::stepper::glib;
+
+struct _AnimationGlideAnimation
+{
+ AnimationTransformAnimation parent_instance;
+};
+
+typedef struct _AnimationGlideAnimationPrivate
+{
+} AnimationGlideAnimationPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationGlideAnimation,
+ animation_glide_animation,
+ ANIMATION_TYPE_TRANSFORM_ANIMATION)
+
+enum {
+ PROP_0,
+ PROP_INITIAL_DISTANCE,
+ PROP_X_ROTATION_ANGLE_DEGREES,
+ PROP_Y_ROTATION_ANGLE_DEGREES,
+ PROP_X_AXIS_LOCATION_UNIT,
+ PROP_Y_AXIS_LOCATION_UNIT,
+ PROP_VIEWPORT,
+ PROP_TARGET,
+ PROP_STEPPER,
+ NPROPS
+};
+
+static GParamSpec *animation_glide_animation_props [NPROPS] = { NULL, };
+
+void
+animation_glide_animation_set_initial_distance (AnimationGlideAnimation *animation,
+ double initial_distance)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->InitialDistance (initial_distance);
+}
+
+double
+animation_glide_animation_get_initial_distance (AnimationGlideAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->InitialDistance ();
+}
+
+void
+animation_glide_animation_set_x_rotation_angle_degrees (AnimationGlideAnimation *animation,
+ double x_rotation_angle_degrees)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->XRotationAngleDegrees (x_rotation_angle_degrees);
+}
+
+double
+animation_glide_animation_get_x_rotation_angle_degrees (AnimationGlideAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->XRotationAngleDegrees ();
+}
+
+void
+animation_glide_animation_set_y_rotation_angle_degrees (AnimationGlideAnimation *animation,
+ double y_rotation_angle_degrees)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->YRotationAngleDegrees (y_rotation_angle_degrees);
+}
+
+double
+animation_glide_animation_get_y_rotation_angle_degrees (AnimationGlideAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->YRotationAngleDegrees ();
+}
+
+void
+animation_glide_animation_set_x_axis_location_unit (AnimationGlideAnimation *animation,
+ double x_axis_location_unit)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->XAxisLocationUnit (x_axis_location_unit);
+}
+
+double
+animation_glide_animation_get_x_axis_location_unit (AnimationGlideAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->XAxisLocationUnit ();
+}
+
+void
+animation_glide_animation_set_y_axis_location_unit (AnimationGlideAnimation *animation,
+ double y_axis_location_unit)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->YAxisLocationUnit (y_axis_location_unit);
+}
+
+double
+animation_glide_animation_get_y_axis_location_unit (AnimationGlideAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->YAxisLocationUnit ();
+}
+
+void
+animation_glide_animation_set_target (AnimationGlideAnimation *animation,
+ AnimationBoxQuery *target)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Target (std::make_shared (target));
+}
+
+/**
+ * animation_glide_animation_get_target:
+ * @animation: An #AnimationBoxQuery
+ *
+ * Returns: (transfer none): Get the #AnimationBoxQuery target for this #AnimationGlideAnimation
+ */
+AnimationBoxQuery *
+animation_glide_animation_get_target (AnimationGlideAnimation *animation)
+{
+ return std::static_pointer_cast (LookupTypedInterfaceProp (G_OBJECT (animation))->Target ())->BoxQuery ();
+}
+
+void
+animation_glide_animation_set_viewport (AnimationGlideAnimation *animation,
+ AnimationBoxQuery *viewport)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Viewport (std::make_shared (viewport));
+}
+
+/**
+ * animation_glide_animation_get_viewport:
+ * @animation: An #AnimationBoxQuery
+ *
+ * Returns: (transfer none): Get the #AnimationBoxQuery for the viewport for this #AnimationGlideAnimation
+ */
+AnimationBoxQuery *
+animation_glide_animation_get_viewport (AnimationGlideAnimation *animation)
+{
+ return std::static_pointer_cast (LookupTypedInterfaceProp (G_OBJECT (animation))->Viewport ())->BoxQuery ();
+}
+
+void
+animation_glide_animation_set_stepper (AnimationGlideAnimation *animation,
+ AnimationStepper *stepper)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (std::make_shared (stepper));
+}
+
+/**
+ * animation_glide_animation_get_stepper:
+ * @animation: An #AnimationGlideAnimation
+ *
+ * Returns: (transfer full): Get the stepper for this #AnimationGlideAnimation
+ */
+AnimationStepper *
+animation_glide_animation_get_stepper (AnimationGlideAnimation *animation)
+{
+ auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ());
+
+ return std::static_pointer_cast (stepper)->BaseStepper ();
+}
+
+static void
+animation_glide_animation_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationGlideAnimation *glide_animation = ANIMATION_GLIDE_ANIMATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_INITIAL_DISTANCE:
+ animation_glide_animation_set_initial_distance (glide_animation, g_value_get_double (value));
+ break;
+ case PROP_X_ROTATION_ANGLE_DEGREES:
+ animation_glide_animation_set_x_rotation_angle_degrees (glide_animation, g_value_get_double (value));
+ break;
+ case PROP_Y_ROTATION_ANGLE_DEGREES:
+ animation_glide_animation_set_y_rotation_angle_degrees (glide_animation, g_value_get_double (value));
+ break;
+ case PROP_X_AXIS_LOCATION_UNIT:
+ animation_glide_animation_set_x_axis_location_unit (glide_animation, g_value_get_double (value));
+ break;
+ case PROP_Y_AXIS_LOCATION_UNIT:
+ animation_glide_animation_set_y_axis_location_unit (glide_animation, g_value_get_double (value));
+ break;
+ case PROP_VIEWPORT:
+ animation_glide_animation_set_viewport (glide_animation,
+ ANIMATION_BOX_QUERY (g_value_get_object (value)));
+ break;
+ case PROP_TARGET:
+ animation_glide_animation_set_target (glide_animation,
+ ANIMATION_BOX_QUERY (g_value_get_object (value)));
+ break;
+ case PROP_STEPPER:
+ animation_glide_animation_set_stepper (glide_animation,
+ ANIMATION_STEPPER (g_value_get_object (value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_glide_animation_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationGlideAnimation *glide_animation = ANIMATION_GLIDE_ANIMATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_INITIAL_DISTANCE:
+ g_value_set_double (value, animation_glide_animation_get_initial_distance (glide_animation));
+ break;
+ case PROP_X_ROTATION_ANGLE_DEGREES:
+ g_value_set_double (value, animation_glide_animation_get_x_rotation_angle_degrees (glide_animation));
+ break;
+ case PROP_Y_ROTATION_ANGLE_DEGREES:
+ g_value_set_double (value, animation_glide_animation_get_y_rotation_angle_degrees (glide_animation));
+ break;
+ case PROP_X_AXIS_LOCATION_UNIT:
+ g_value_set_double (value, animation_glide_animation_get_x_axis_location_unit (glide_animation));
+ break;
+ case PROP_Y_AXIS_LOCATION_UNIT:
+ g_value_set_double (value, animation_glide_animation_get_y_axis_location_unit (glide_animation));
+ break;
+ case PROP_VIEWPORT:
+ g_value_set_object (value, animation_glide_animation_get_viewport (glide_animation));
+ break;
+ case PROP_TARGET:
+ g_value_set_object (value, animation_glide_animation_get_target (glide_animation));
+ break;
+ case PROP_STEPPER:
+ g_value_set_object (value, animation_glide_animation_get_stepper (glide_animation));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static GObject *
+animation_glide_animation_constructor (GType type,
+ unsigned int n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ auto *interface = InterfaceConstructor ::construct ();
+ auto *transform_interface = static_cast (interface);
+
+ /* We need to also set defaults for certain properties in order
+ * to ensure that they are bindable later on, in case they are
+ * not set by the caller. */
+ replace_named_pointer_props_in_construct_params_if_null (
+ construct_params,
+ n_construct_params,
+ {
+ ReplacePropSpec ("stepper", g_value_get_object, g_value_set_object, []() -> gpointer {
+ return animation_linear_stepper_new (1);
+ }),
+ ReplacePropSpec ("target", g_value_get_object, g_value_set_object, []() -> gpointer {
+ return animation_box_query_new ();
+ }),
+ ReplacePropSpec ("viewport", g_value_get_object, g_value_set_object, []() -> gpointer {
+ return animation_box_query_new ();
+ })
+ }
+ );
+
+ replace_interface_prop_in_construct_params (construct_params,
+ n_construct_params,
+ transform_interface);
+
+ return G_OBJECT_CLASS (animation_glide_animation_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+}
+
+static void
+animation_glide_animation_constructed (GObject *object)
+{
+ /* Take a size-zero step, which ensures that we update the
+ * internal state of the animation with all the properties we
+ * just set */
+ animation_transform_animation_step (ANIMATION_TRANSFORM_ANIMATION (object), 0);
+}
+
+static void
+animation_glide_animation_init (AnimationGlideAnimation *model)
+{
+}
+
+
+static void
+animation_glide_animation_class_init (AnimationGlideAnimationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = animation_glide_animation_constructor;
+ object_class->constructed = animation_glide_animation_constructed;
+ object_class->get_property = animation_glide_animation_get_property;
+ object_class->set_property = animation_glide_animation_set_property;
+
+ animation_glide_animation_props[PROP_INITIAL_DISTANCE] =
+ g_param_spec_double ("initial-distance",
+ "Initial Distance",
+ "The initial distance away from the camera",
+ -1.0,
+ 1.0,
+ -0.3,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_X_ROTATION_ANGLE_DEGREES] =
+ g_param_spec_double ("x-rotation-angle-degrees",
+ "X Rotation Angle Degrees",
+ "Number of degrees on the X axis to rotate",
+ -360.0,
+ 360.0,
+ 0.0,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_Y_ROTATION_ANGLE_DEGREES] =
+ g_param_spec_double ("y-rotation-angle-degrees",
+ "Y Rotation Angle Degrees",
+ "Number of degrees on the Y axis to rotate",
+ -360.0,
+ 360.0,
+ 0.0,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_X_AXIS_LOCATION_UNIT] =
+ g_param_spec_double ("x-axis-location-unit",
+ "X Axis Location Unit",
+ "Unit-coordinates of where the X axis is on the surface",
+ 0.0,
+ 1.0,
+ 0.2,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_Y_AXIS_LOCATION_UNIT] =
+ g_param_spec_double ("y-axis-location-unit",
+ "Y Axis Location Unit",
+ "Unit-coordinates of where the Y axis is on the surface",
+ 0.0,
+ 1.0,
+ 0.5,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_VIEWPORT] =
+ g_param_spec_object ("viewport",
+ "Viewport BoxQuery",
+ "BoxQuery for the viewport dimensions that the surface is in",
+ ANIMATION_TYPE_BOX_QUERY,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_TARGET] =
+ g_param_spec_object ("target",
+ "Target BoxQuery",
+ "BoxQuery for box that we are animating to",
+ ANIMATION_TYPE_BOX_QUERY,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_glide_animation_props[PROP_STEPPER] =
+ g_param_spec_object ("stepper",
+ "Stepper",
+ "Stepper to use to progress the animation",
+ ANIMATION_TYPE_STEPPER,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_properties (object_class,
+ NPROPS,
+ animation_glide_animation_props);
+}
+
+/**
+ * animation_glide_new:
+ * @initial_distance: Initial distance frm the camera.
+ * @x_rotation_angle_degrees: Degrees of rotation towards the X axis.
+ * @y_rotation_angle_degrees: Degrees of rotation towards the Y axis.
+ * @y_axis_location_unit: Unit-coordinates of where the X axis is on the surface.
+ * @x_axis_location_unit: Unit-coordinates of where the Y axis is on the surface.
+ * @screen_width: Width of the screen, in pixels.
+ * @target_box: The #AnimationBoxQuery that we are animating to.
+ * @length: The length of the animation.
+ *
+ * Returns: (transfer full): A new #AnimationGlideAnimation.
+ */
+AnimationGlideAnimation *
+animation_glide_new (double initial_distance,
+ double x_rotation_angle_degrees,
+ double y_rotation_angle_degrees,
+ double x_axis_location_unit,
+ double y_axis_location_unit,
+ unsigned int screen_width,
+ const AnimationBoxQuery *target_box,
+ unsigned int length)
+{
+ return ANIMATION_GLIDE_ANIMATION (g_object_new (ANIMATION_TYPE_GLIDE_ANIMATION,
+ "initial-distance", initial_distance,
+ "x-rotation-angle-degrees", x_rotation_angle_degrees,
+ "y-rotation-angle-degrees", y_rotation_angle_degrees,
+ "x-axis-location-unit", x_axis_location_unit,
+ "y-axis-location-unit", y_axis_location_unit,
+ "screen-width", screen_width,
+ "target", target_box,
+ "length", length,
+ NULL));
+}
diff --git a/animation-glib/glide/glide.h b/animation-glib/glide/glide.h
new file mode 100644
index 0000000..1bec121
--- /dev/null
+++ b/animation-glib/glide/glide.h
@@ -0,0 +1,78 @@
+/*
+ * animation-glib/glide/glide.h
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject Interface for "glide" animation.
+ */
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_TYPE_GLIDE_ANIMATION animation_glide_animation_get_type ()
+G_DECLARE_FINAL_TYPE (AnimationGlideAnimation, animation_glide_animation, ANIMATION, GLIDE_ANIMATION, AnimationTransformAnimation)
+
+void animation_glide_animation_set_initial_distance (AnimationGlideAnimation *animation,
+ double initial_distance);
+double animation_glide_animation_get_initial_distance (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_x_rotation_angle_degrees (AnimationGlideAnimation *animation,
+ double x_rotation_angle_degrees);
+double animation_glide_animation_get_x_rotation_angle_degrees (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_y_rotation_angle_degrees (AnimationGlideAnimation *animation,
+ double y_rotation_angle_degrees);
+double animation_glide_animation_get_y_rotation_angle_degrees (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_x_axis_location_unit (AnimationGlideAnimation *animation,
+ double x_axis_location_unit);
+
+double animation_glide_animation_get_x_axis_location_unit (AnimationGlideAnimation *animation);
+void animation_glide_animation_set_y_axis_location_unit (AnimationGlideAnimation *animation,
+ double y_axis_location_unit);
+
+double animation_glide_animation_get_y_axis_location_unit (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_target (AnimationGlideAnimation *animation,
+ AnimationBoxQuery *target);
+AnimationBoxQuery * animation_glide_animation_get_target (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_viewport (AnimationGlideAnimation *animation,
+ AnimationBoxQuery *target);
+AnimationBoxQuery * animation_glide_animation_get_viewport (AnimationGlideAnimation *animation);
+
+void animation_glide_animation_set_stepper (AnimationGlideAnimation *animation,
+ AnimationStepper *stepper);
+AnimationStepper * animation_glide_animation_get_stepper (AnimationGlideAnimation *animation);
+
+AnimationGlideAnimation * animation_glide_new (double initial_distance,
+ double x_rotation_angle_degrees,
+ double y_rotation_angle_degrees,
+ double x_axis_location_unit,
+ double y_axis_location_unit,
+ unsigned int screen_width,
+ const AnimationBoxQuery *target_box,
+ unsigned int length);
+
+G_END_DECLS
diff --git a/animation-glib/glide/meson.build b/animation-glib/glide/meson.build
new file mode 100644
index 0000000..a7e1112
--- /dev/null
+++ b/animation-glib/glide/meson.build
@@ -0,0 +1,32 @@
+# animation/glide/meson.build
+#
+# Copyright (C) 2017, 2018 Endless Mobile, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Build the libanimation library (glide animation component), GObject bindings.
+
+glide_introspectable_sources = files([
+ 'glide.cpp'
+])
+
+glide_headers = files([
+ 'glide.h'
+])
+
+animation_glib_introspectable_sources += glide_introspectable_sources
+animation_glib_headers += glide_headers
+
+install_headers(glide_headers, subdir: join_paths(animation_glib_headers_subdir, 'glide'))
diff --git a/animation-glib/grid/grid.cpp b/animation-glib/grid/grid.cpp
new file mode 100644
index 0000000..df064ac
--- /dev/null
+++ b/animation-glib/grid/grid.cpp
@@ -0,0 +1,259 @@
+/*
+ * animation-glib/grid/grid.cpp
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject base class for grid animations.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace agd = animation::geometry::dimension;
+namespace agr = animation::grid;
+
+typedef struct _AnimationGridAnimationPrivate
+{
+ agr::GridAnimation *interface;
+} AnimationGridAnimationPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationGridAnimation,
+ animation_grid_animation,
+ G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_INTERFACE,
+ NPROPS
+};
+
+static GParamSpec *animation_grid_animation_props [NPROPS] = { NULL, };
+
+gboolean
+animation_grid_animation_step (AnimationGridAnimation *grid_animation,
+ unsigned int ms)
+{
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ return priv->interface->Step (ms);
+}
+
+/**
+ * animation_grid_animation_deform_uv_to_model_space:
+ * @grid_animation: An #AnimationGridAnimation
+ * @uv: An #AnimationVector representing a point in unit coordinate
+ * space to be deformed.
+ * @model_space_point: (out caller-allocates): An #AnimationVector to write
+ * the deformed co-ordinate to.
+ *
+ * Determine where a unit coordinate lies in model space.
+ */
+void
+animation_grid_animation_deform_uv_to_model_space (AnimationGridAnimation *grid_animation,
+ AnimationVector *uv,
+ AnimationVector *model_space_point)
+{
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ g_return_if_fail (model_space_point != NULL);
+
+ animation::Point point (uv->x, uv->y);
+ animation::Point deformed (priv->interface->DeformUVToModelSpace (point));
+
+ model_space_point->x = agd::get <0> (deformed);
+ model_space_point->y = agd::get <1> (deformed);
+}
+
+/**
+ * animation_grid_animation_resolution:
+ * @grid_animation: An #AnimationGridAnimation
+ * @out_resolution: (out caller-allocates): An #AnimationVector specifying the
+ * ideal resolution of the animated surface grid.
+ *
+ * Return the expected grid resolution that would be required to
+ * make this animation look smooth. The renderer should subdivide
+ * the animated surface into this many equal sized chunks.
+ */
+void
+animation_grid_animation_resolution (AnimationGridAnimation *grid_animation,
+ AnimationVector *out_resolution)
+{
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ g_return_if_fail (out_resolution != NULL);
+
+ auto resolution_cpp (priv->interface->Resolution ());
+
+ out_resolution->x = agd::get <0> (resolution_cpp);
+ out_resolution->y = agd::get <1> (resolution_cpp);
+}
+
+/**
+ * animation_grid_animation_extremes: (skip)
+ * @grid_animation: A #AnimationGridAnimation
+ * @corners: (array fixed-size=4): The four #AnimationVector4D values
+ * describing the location of the surface corners.
+ * @out_extremes: (array fixed-size=4) (out): The grided four #AnimationVector
+ * values describing the location of the grided surface
+ * surface corners.
+ *
+ * Get the four co-ordinates of a 3D plane which bound the animated surface.
+ */
+void
+animation_grid_animation_extremes (AnimationGridAnimation *grid_animation,
+ AnimationVector const *corners,
+ AnimationVector4D *out_extremes)
+{
+ g_return_if_fail (corners != NULL);
+ g_return_if_fail (out_extremes != NULL);
+
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ std::array points = {
+ animation::Point (corners[0].x, corners[0].y),
+ animation::Point (corners[1].x, corners[1].y),
+ animation::Point (corners[2].x, corners[2].y),
+ animation::Point (corners[3].x, corners[3].y)
+ };
+
+ std::array extremes = priv->interface->Extremes (points);
+
+ agd::assign (out_extremes[0], extremes[0]);
+ agd::assign (out_extremes[1], extremes[1]);
+ agd::assign (out_extremes[2], extremes[2]);
+ agd::assign (out_extremes[3], extremes[3]);
+}
+
+/**
+ * animation_grid_animation_alloc_extremes: (rename-to animation_grid_animation_extremes)
+ * @grid_animation: A #AnimationGridAnimation
+ * @corners: (array fixed-size=4): The four #AnimationVector4D values
+ * describing the location of the surface corners.
+ *
+ * Get the four co-ordinates of a 3D plane which bound the animated surface. This
+ * function exists as a workaround for the fact that some language bindings do not support
+ * caller allocation for out-array types.
+ *
+ * Returns: (array fixed-size=4) (transfer full): The transformed four #AnimationVector
+ * values describing the location of the transformed surface
+ * surface corners.
+ */
+AnimationVector4D *
+animation_grid_animation_alloc_extremes (AnimationGridAnimation *grid_animation,
+ AnimationVector const *corners)
+{
+ AnimationVector4D *out_array = g_new0 (AnimationVector4D, 4);
+
+ animation_grid_animation_extremes (grid_animation, corners, out_array);
+ return out_array;
+}
+
+float
+animation_grid_animation_progress (AnimationGridAnimation *grid_animation)
+{
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ return priv->interface->Progress ();
+}
+
+static void
+animation_grid_animation_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationGridAnimation *grid_animation = ANIMATION_GRID_ANIMATION (object);
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ switch (prop_id)
+ {
+ case PROP_INTERFACE:
+ priv->interface = reinterpret_cast (g_value_get_pointer (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_grid_animation_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationGridAnimation *grid_animation = ANIMATION_GRID_ANIMATION (object);
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ switch (prop_id)
+ {
+ case PROP_INTERFACE:
+ g_value_set_pointer (value, reinterpret_cast (priv->interface));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_grid_animation_finalize (GObject *object)
+{
+ AnimationGridAnimation *grid_animation = ANIMATION_GRID_ANIMATION (object);
+ AnimationGridAnimationPrivate *priv =
+ reinterpret_cast (animation_grid_animation_get_instance_private (grid_animation));
+
+ delete priv->interface;
+ priv->interface = nullptr;
+
+ G_OBJECT_CLASS (animation_grid_animation_parent_class)->finalize (object);
+}
+
+static void
+animation_grid_animation_init (AnimationGridAnimation *model)
+{
+}
+
+
+static void
+animation_grid_animation_class_init (AnimationGridAnimationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = animation_grid_animation_get_property;
+ object_class->set_property = animation_grid_animation_set_property;
+ object_class->finalize = animation_grid_animation_finalize;
+
+ animation_grid_animation_props[PROP_INTERFACE] =
+ g_param_spec_pointer ("interface",
+ "Internal Interface",
+ "Internal C++ interface that this class wraps",
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_properties (object_class,
+ NPROPS,
+ animation_grid_animation_props);
+}
diff --git a/animation-glib/grid/grid.h b/animation-glib/grid/grid.h
new file mode 100644
index 0000000..1666ac4
--- /dev/null
+++ b/animation-glib/grid/grid.h
@@ -0,0 +1,57 @@
+/*
+ * animation-glib/grid/grid.h
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject base class for grid animations.
+ */
+#pragma once
+
+#include
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_TYPE_GRID_ANIMATION animation_grid_animation_get_type ()
+G_DECLARE_DERIVABLE_TYPE (AnimationGridAnimation, animation_grid_animation, ANIMATION, GRID_ANIMATION, GObject)
+
+struct _AnimationGridAnimationClass {
+ GObjectClass parent_class;
+};
+
+gboolean animation_grid_animation_step (AnimationGridAnimation *grid_animation,
+ unsigned int ms);
+
+float animation_grid_animation_progress (AnimationGridAnimation *grid_animation);
+
+void animation_grid_animation_deform_uv_to_model_space (AnimationGridAnimation *grid_animation,
+ AnimationVector *uv,
+ AnimationVector *model_space_point);
+
+void animation_grid_animation_resolution (AnimationGridAnimation *grid_animation,
+ AnimationVector *out_resolution);
+
+void animation_grid_animation_extremes (AnimationGridAnimation *grid_animation,
+ AnimationVector const *corners,
+ AnimationVector4D *out_extremes);
+
+AnimationVector4D * animation_grid_animation_alloc_extremes (AnimationGridAnimation *grid_animation,
+ AnimationVector const *corners);
+
+G_END_DECLS
diff --git a/animation-glib/grid/meson.build b/animation-glib/grid/meson.build
new file mode 100644
index 0000000..eeaf92a
--- /dev/null
+++ b/animation-glib/grid/meson.build
@@ -0,0 +1,32 @@
+# animation/grid/meson.build
+#
+# Copyright (C) 2017, 2018 Endless Mobile, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Build the libanimation library (grid animation base component GObject interface)
+
+grid_introspectable_sources = files([
+ 'grid.cpp'
+])
+
+grid_headers = files([
+ 'grid.h'
+])
+
+animation_glib_introspectable_sources += grid_introspectable_sources
+animation_glib_headers += grid_headers
+
+install_headers(grid_headers, subdir: join_paths(animation_glib_headers_subdir, 'grid'))
diff --git a/animation-glib/magiclamp/magiclamp.cpp b/animation-glib/magiclamp/magiclamp.cpp
new file mode 100644
index 0000000..689a3af
--- /dev/null
+++ b/animation-glib/magiclamp/magiclamp.cpp
@@ -0,0 +1,455 @@
+/*
+ * animation-glib/magiclamp/magiclamp.cpp
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject implementation for a "magiclamp" animation.
+ */
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ag = animation::grid;
+namespace agd = animation::geometry::dimension;
+namespace age = animation::geometry;
+namespace agl = animation::glib;
+namespace aml = animation::magiclamp;
+namespace asg = animation::stepper::glib;
+
+struct _AnimationMagicLampAnimation
+{
+ AnimationGridAnimation parent_instance;
+};
+
+typedef struct _AnimationMagicLampAnimationPrivate
+{
+} AnimationMagicLampAnimationPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AnimationMagicLampAnimation,
+ animation_magiclamp_animation,
+ ANIMATION_TYPE_GRID_ANIMATION)
+
+enum {
+ PROP_0,
+ PROP_SOURCE,
+ PROP_TARGET,
+ PROP_RESOLUTION,
+ PROP_BEND_FACTOR,
+ PROP_OFFSET_FACTOR,
+ PROP_STRETCH_FACTOR,
+ PROP_DEFORM_SPEED_FACTOR,
+ PROP_STEPPER,
+ NPROPS
+};
+
+static GParamSpec *animation_magiclamp_animation_props [NPROPS] = { NULL, };
+
+void
+animation_magiclamp_animation_set_bend_factor (AnimationMagicLampAnimation *animation,
+ double bend_factor)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->BendFactor (bend_factor);
+}
+
+double
+animation_magiclamp_animation_get_bend_factor (AnimationMagicLampAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->BendFactor ();
+}
+
+void
+animation_magiclamp_animation_set_offset_factor (AnimationMagicLampAnimation *animation,
+ double offset_factor)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->OffsetFactor (offset_factor);
+}
+
+double
+animation_magiclamp_animation_get_offset_factor (AnimationMagicLampAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->OffsetFactor ();
+}
+
+void
+animation_magiclamp_animation_set_stretch_factor (AnimationMagicLampAnimation *animation,
+ double stretch_factor)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->StretchFactor (stretch_factor);
+}
+
+double
+animation_magiclamp_animation_get_stretch_factor (AnimationMagicLampAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->StretchFactor ();
+}
+
+void
+animation_magiclamp_animation_set_deform_speed_factor (AnimationMagicLampAnimation *animation,
+ double deform_speed_factor)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->DeformSpeedFactor (deform_speed_factor);
+}
+
+double
+animation_magiclamp_animation_get_deform_speed_factor (AnimationMagicLampAnimation *animation)
+{
+ return LookupTypedInterfaceProp (G_OBJECT (animation))->DeformSpeedFactor ();
+}
+
+void
+animation_magiclamp_animation_set_resolution (AnimationMagicLampAnimation *animation,
+ AnimationVector *vector)
+{
+ auto resolution = age::PointModel (vector->x, vector->y);
+ LookupTypedInterfaceProp (G_OBJECT (animation))->GridResolution (resolution);
+}
+
+/**
+ * animation_magiclamp_animation_get_resolution:
+ * @animation: An #AnimationMagicLampAnimation
+ * @vector: (out): The #AnimationVector to write the resolution into.
+ */
+void
+animation_magiclamp_animation_get_resolution (AnimationMagicLampAnimation *animation,
+ AnimationVector *vector)
+{
+ auto resolution = LookupTypedInterfaceProp (G_OBJECT (animation))->GridResolution ();
+
+ vector->x = static_cast (resolution.x);
+ vector->y = static_cast (resolution.y);
+}
+
+void
+animation_magiclamp_animation_set_source (AnimationMagicLampAnimation *animation,
+ AnimationBoxQuery *source)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Source (std::make_shared (source));
+}
+
+/**
+ * animation_magiclamp_animation_get_source:
+ * @animation: A #AnimationMagicLampAnimation
+ *
+ * Returns: (transfer none): Get the #AnimationBoxQuery source for this #AnimationMagicLampAnimation
+ */
+AnimationBoxQuery *
+animation_magiclamp_animation_get_source (AnimationMagicLampAnimation *animation)
+{
+ return std::static_pointer_cast (LookupTypedInterfaceProp (G_OBJECT (animation))->Source ())->BoxQuery ();
+}
+
+void
+animation_magiclamp_animation_set_target (AnimationMagicLampAnimation *animation,
+ AnimationBoxQuery *target)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Target (std::make_shared (target));
+}
+
+/**
+ * animation_magiclamp_animation_get_target:
+ * @animation: A #AnimationMagicLampAnimation
+ *
+ * Returns: (transfer none): Get the #AnimationBoxQuery target for this #AnimationMagicLampAnimation
+ */
+AnimationBoxQuery *
+animation_magiclamp_animation_get_target (AnimationMagicLampAnimation *animation)
+{
+ return std::static_pointer_cast (LookupTypedInterfaceProp (G_OBJECT (animation))->Target ())->BoxQuery ();
+}
+
+void
+animation_magiclamp_animation_set_stepper (AnimationMagicLampAnimation *animation,
+ AnimationStepper *stepper)
+{
+ LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (std::make_shared (stepper));
+}
+
+/**
+ * animation_magiclamp_animation_get_stepper:
+ * @animation: An #AnimationMagicLampAnimation
+ *
+ * Returns: (transfer full): Get the stepper for this #AnimationMagicLampAnimation
+ */
+AnimationStepper *
+animation_magiclamp_animation_get_stepper (AnimationMagicLampAnimation *animation)
+{
+ auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ());
+
+ return std::static_pointer_cast (stepper)->BaseStepper ();
+}
+
+static void
+animation_magiclamp_animation_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationMagicLampAnimation *magiclamp_animation = ANIMATION_MAGIC_LAMP_ANIMATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ animation_magiclamp_animation_set_source (magiclamp_animation,
+ ANIMATION_BOX_QUERY (g_value_get_object (value)));
+ break;
+ case PROP_TARGET:
+ animation_magiclamp_animation_set_target (magiclamp_animation,
+ ANIMATION_BOX_QUERY (g_value_get_object (value)));
+ break;
+ case PROP_RESOLUTION:
+ animation_magiclamp_animation_set_resolution (magiclamp_animation,
+ reinterpret_cast (g_value_get_boxed (value)));
+ break;
+ case PROP_BEND_FACTOR:
+ animation_magiclamp_animation_set_bend_factor (magiclamp_animation, g_value_get_double (value));
+ break;
+ case PROP_OFFSET_FACTOR:
+ animation_magiclamp_animation_set_offset_factor (magiclamp_animation, g_value_get_double (value));
+ break;
+ case PROP_STRETCH_FACTOR:
+ animation_magiclamp_animation_set_stretch_factor (magiclamp_animation, g_value_get_double (value));
+ break;
+ case PROP_DEFORM_SPEED_FACTOR:
+ animation_magiclamp_animation_set_deform_speed_factor (magiclamp_animation, g_value_get_double (value));
+ break;
+ case PROP_STEPPER:
+ animation_magiclamp_animation_set_stepper (magiclamp_animation,
+ ANIMATION_STEPPER (g_value_get_object (value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+animation_magiclamp_animation_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AnimationMagicLampAnimation *magiclamp_animation = ANIMATION_MAGIC_LAMP_ANIMATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ g_value_set_object (value, animation_magiclamp_animation_get_source (magiclamp_animation));
+ break;
+ case PROP_TARGET:
+ g_value_set_object (value, animation_magiclamp_animation_get_target (magiclamp_animation));
+ break;
+ case PROP_RESOLUTION:
+ {
+ AnimationVector vector;
+ animation_magiclamp_animation_get_resolution (magiclamp_animation, &vector);
+ g_value_set_boxed (value, reinterpret_cast (&vector));
+ }
+ break;
+ case PROP_BEND_FACTOR:
+ g_value_set_double (value, animation_magiclamp_animation_get_bend_factor (magiclamp_animation));
+ break;
+ case PROP_STRETCH_FACTOR:
+ g_value_set_double (value, animation_magiclamp_animation_get_stretch_factor (magiclamp_animation));
+ break;
+ case PROP_OFFSET_FACTOR:
+ g_value_set_double (value, animation_magiclamp_animation_get_offset_factor (magiclamp_animation));
+ break;
+ case PROP_DEFORM_SPEED_FACTOR:
+ g_value_set_double (value, animation_magiclamp_animation_get_deform_speed_factor (magiclamp_animation));
+ break;
+ case PROP_STEPPER:
+ g_value_set_object (value, animation_magiclamp_animation_get_stepper (magiclamp_animation));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static GObject *
+animation_magiclamp_animation_constructor (GType type,
+ unsigned int n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ auto *interface = InterfaceConstructor ::construct ();
+ auto *grid_interface = static_cast (interface);
+
+ /* We need to also set defaults for certain properties in order
+ * to ensure that they are bindable later on, in case they are
+ * not set by the caller. */
+ replace_named_pointer_props_in_construct_params_if_null (
+ construct_params,
+ n_construct_params,
+ {
+ ReplacePropSpec ("stepper", g_value_get_object, g_value_take_object, []() -> gpointer {
+ return animation_linear_stepper_new (1);
+ }),
+ ReplacePropSpec ("source", g_value_get_object, g_value_take_object, []() -> gpointer {
+ return animation_box_query_new ();
+ }),
+ ReplacePropSpec ("target", g_value_get_object, g_value_take_object, []() -> gpointer {
+ return animation_box_query_new ();
+ })
+ }
+ );
+
+ replace_interface_prop_in_construct_params (construct_params,
+ n_construct_params,
+ grid_interface);
+
+ return G_OBJECT_CLASS (animation_magiclamp_animation_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+}
+
+static void
+animation_magiclamp_animation_constructed (GObject *object)
+{
+ /* Take a size-zero step, which ensures that we update the
+ * internal state of the animation with all the properties we
+ * just set */
+ animation_grid_animation_step (ANIMATION_GRID_ANIMATION (object), 0);
+}
+
+static void
+animation_magiclamp_animation_init (AnimationMagicLampAnimation *model)
+{
+}
+
+
+static void
+animation_magiclamp_animation_class_init (AnimationMagicLampAnimationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = animation_magiclamp_animation_constructor;
+ object_class->constructed = animation_magiclamp_animation_constructed;
+ object_class->get_property = animation_magiclamp_animation_get_property;
+ object_class->set_property = animation_magiclamp_animation_set_property;
+
+ animation_magiclamp_animation_props[PROP_SOURCE] =
+ g_param_spec_object ("source",
+ "Source Box",
+ "BoxQuery for box that we are animating from",
+ ANIMATION_TYPE_BOX_QUERY,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_TARGET] =
+ g_param_spec_object ("target",
+ "Target Box",
+ "BoxQuery for box that we are animating to",
+ ANIMATION_TYPE_BOX_QUERY,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_RESOLUTION] =
+ g_param_spec_boxed ("resolution",
+ "Resolution",
+ "Grid Resolution",
+ ANIMATION_TYPE_VECTOR,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_BEND_FACTOR] =
+ g_param_spec_double ("bend-factor",
+ "Bend Factor",
+ "How much the window should bend",
+ 1.0,
+ 20.0,
+ 10.0,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_OFFSET_FACTOR] =
+ g_param_spec_double ("offset-factor",
+ "Offset Factor",
+ "How big the curves of the animation should be",
+ 0.1,
+ 1.0,
+ 0.5,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_STRETCH_FACTOR] =
+ g_param_spec_double ("stretch-factor",
+ "Stretch Factor",
+ "How much the window should stretch when animating",
+ 0.2,
+ 1.0,
+ 0.45,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_DEFORM_SPEED_FACTOR] =
+ g_param_spec_double ("deform-speed-factor",
+ "Deform Speed Factor",
+ "How quickly the deformation phase should happen",
+ 1.0,
+ 4.0,
+ 2.3,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ animation_magiclamp_animation_props[PROP_STEPPER] =
+ g_param_spec_object ("stepper",
+ "Stepper",
+ "Stepper to use to progress the animation",
+ ANIMATION_TYPE_STEPPER,
+ static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_properties (object_class,
+ NPROPS,
+ animation_magiclamp_animation_props);
+}
+
+/**
+ * animation_magiclamp_new:
+ * @source_box: The #AnimationBoxQuery that we are animating from.
+ * @target_box: The #AnimationBoxQuery that we are animating to.
+ * @resolution: The #AnimationVector representing the grid resolution
+ * @bend_factor: How much the window should bend
+ * @offset_factor: How big the curves of the animation should be
+ * @deform_speed_factor: How quickly the deformation should complete.
+ * @stepper: An #AnimationStepper used for progressing the animation.
+ *
+ * Returns: (transfer full): A new #AnimationMagicLampAnimation.
+ */
+AnimationMagicLampAnimation *
+animation_magiclamp_new (const AnimationBoxQuery *source_box,
+ const AnimationBoxQuery *target_box,
+ const AnimationVector *resolution,
+ double bend_factor,
+ double offset_factor,
+ double stretch_factor,
+ double deform_speed_factor,
+ AnimationStepper *stepper)
+{
+ return ANIMATION_MAGIC_LAMP_ANIMATION (g_object_new (ANIMATION_TYPE_MAGIC_LAMP_ANIMATION,
+ "source", source_box,
+ "target", target_box,
+ "resolution", resolution,
+ "bend-factor", bend_factor,
+ "offset-factor", offset_factor,
+ "stretch-factor", stretch_factor,
+ "deform-speed-factor", deform_speed_factor,
+ "stepper", stepper,
+ NULL));
+}
diff --git a/animation-glib/magiclamp/magiclamp.h b/animation-glib/magiclamp/magiclamp.h
new file mode 100644
index 0000000..674289a
--- /dev/null
+++ b/animation-glib/magiclamp/magiclamp.h
@@ -0,0 +1,73 @@
+/*
+ * animation-glib/magiclamp/magiclamp.h
+ *
+ * Copyright 2018 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * GObject Interface for "magiclamp" animation.
+ */
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define ANIMATION_TYPE_MAGIC_LAMP_ANIMATION animation_magiclamp_animation_get_type ()
+G_DECLARE_FINAL_TYPE (AnimationMagicLampAnimation, animation_magiclamp_animation, ANIMATION, MAGIC_LAMP_ANIMATION, AnimationGridAnimation)
+
+void animation_magiclamp_animation_set_bend_factor (AnimationMagicLampAnimation *animation,
+ double bend_factor);
+double animation_magiclamp_animation_get_bend_factor (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_offset_factor (AnimationMagicLampAnimation *animation,
+ double offset_factor);
+double animation_magiclamp_animation_get_offset_factor (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_stretch_factor (AnimationMagicLampAnimation *animation,
+ double stretch_factor);
+double animation_magiclamp_animation_get_stretch_factor (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_deform_speed_factor (AnimationMagicLampAnimation *animation,
+ double deform_speed_factor);
+double animation_magiclamp_animation_get_deform_speed_factor (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_source (AnimationMagicLampAnimation *animation,
+ AnimationBoxQuery *source);
+AnimationBoxQuery * animation_magiclamp_animation_get_source (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_target (AnimationMagicLampAnimation *animation,
+ AnimationBoxQuery *target);
+AnimationBoxQuery * animation_magiclamp_animation_get_target (AnimationMagicLampAnimation *animation);
+
+void animation_magiclamp_animation_set_stepper (AnimationMagicLampAnimation *animation,
+ AnimationStepper *stepper);
+AnimationStepper * animation_magiclamp_animation_get_stepper (AnimationMagicLampAnimation *animation);
+
+AnimationMagicLampAnimation * animation_magiclamp_new (const AnimationBox *source_box,
+ const AnimationBox *target_box,
+ const AnimationVector *resolution,
+ double bend_factor,
+ double offset_factor,
+ double stretch_factor,
+ double deform_speed_factor,
+ AnimationStepper *stepper);
+
+G_END_DECLS
diff --git a/animation-glib/magiclamp/meson.build b/animation-glib/magiclamp/meson.build
new file mode 100644
index 0000000..0e9e139
--- /dev/null
+++ b/animation-glib/magiclamp/meson.build
@@ -0,0 +1,32 @@
+# /animation-glib/magiclamp/meson.build
+#
+# Copyright (C) 2017, 2018 Endless Mobile, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Build the libanimation library (magiclamp animation component), GObject binding.
+
+magiclamp_introspectable_sources = files([
+ 'magiclamp.cpp'
+])
+
+magiclamp_headers = files([
+ 'magiclamp.h'
+])
+
+animation_glib_introspectable_sources += magiclamp_introspectable_sources
+animation_glib_headers += magiclamp_headers
+
+install_headers(magiclamp_headers, subdir: join_paths(animation_glib_headers_subdir, 'magiclamp'))
diff --git a/animation-glib/meson.build b/animation-glib/meson.build
index fb997bb..2238e3c 100644
--- a/animation-glib/meson.build
+++ b/animation-glib/meson.build
@@ -20,18 +20,44 @@
api_version = '0'
-animation_glib_toplevel_headers = ['vector.h']
-animation_glib_toplevel_introspectable_sources = ['vector.cpp']
+animation_glib_toplevel_headers = files([
+ 'box.h',
+ 'vector.h',
+ 'vector4d.h'
+])
+animation_glib_toplevel_introspectable_sources = files([
+ 'box.cpp',
+ 'vector.cpp',
+ 'vector4d.cpp'
+])
+animation_glib_toplevel_private_headers = files([
+ 'constructor-helpers.h',
+ 'vector4d-internal.h'
+])
+animation_glib_toplevel_private_sources = files([
+ 'constructor-helpers.cpp'
+])
-animation_glib_introspectable_sources = []
-animation_glib_private_sources = []
-animation_glib_headers = []
+animation_glib_introspectable_sources = files([])
+animation_glib_private_headers = files([])
+animation_glib_private_sources = files([])
+animation_glib_headers = files([])
animation_glib_headers_subdir = 'animation-glib'
+subdir('bounce')
+subdir('glide')
+subdir('grid')
+subdir('magiclamp')
+subdir('query')
+subdir('stepper')
+subdir('transform')
subdir('wobbly')
+subdir('zoom')
-animation_glib_introspectable_sources += files(animation_glib_toplevel_introspectable_sources)
-animation_glib_headers += files(animation_glib_toplevel_headers)
+animation_glib_introspectable_sources += animation_glib_toplevel_introspectable_sources
+animation_glib_private_sources += animation_glib_toplevel_private_sources
+animation_glib_headers += animation_glib_toplevel_headers
+animation_glib_private_headers += animation_glib_toplevel_private_headers
install_headers(animation_glib_toplevel_headers, subdir: animation_glib_headers_subdir)
@@ -57,7 +83,7 @@ animation_glib_dep = declare_dependency(
introspection_sources = [ animation_glib_introspectable_sources, animation_glib_headers ]
gnome = import('gnome')
-gnome.generate_gir(
+animation_glib_gir = gnome.generate_gir(
animation_glib_lib,
extra_args: ['--warn-all', '--warn-error'],
identifier_prefix: 'Animation',
@@ -68,7 +94,7 @@ gnome.generate_gir(
nsversion: api_version,
sources: introspection_sources,
symbol_prefix: 'animation'
-)
+)[0]
pkg = import('pkgconfig')
pkg.generate(
diff --git a/animation-glib/query/geometry-query-internal.cpp b/animation-glib/query/geometry-query-internal.cpp
new file mode 100644
index 0000000..fad0557
--- /dev/null
+++ b/animation-glib/query/geometry-query-internal.cpp
@@ -0,0 +1,74 @@
+/*
+ * animation-glib/query/geometry-query-internal.cpp
+ *
+ * Copyright 2019 Endless Mobile, Inc.
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * Wrapper for the AnimationBoxQuery object into a C++ object satisfying
+ * the animation::BoxQuery interface, implementation.
+ */
+
+#include
+#include
+#include
+
+namespace ag = animation::glib;
+
+namespace animation
+{
+ namespace glib
+ {
+ struct BoxQueryWrapper::Private
+ {
+ Private (AnimationBoxQuery *);
+ ~Private ();
+
+ AnimationBoxQuery *query;
+ };
+ }
+}
+
+ag::BoxQueryWrapper::Private::Private (AnimationBoxQuery *query) :
+ query (ANIMATION_BOX_QUERY (g_object_ref (query)))
+{
+}
+
+ag::BoxQueryWrapper::Private::~Private ()
+{
+ g_clear_object (&query);
+}
+
+animation::Box const &
+ag::BoxQueryWrapper::Geometry () const
+{
+ return animation_box_query_get_storage (priv->query).Geometry ();
+}
+
+AnimationBoxQuery *
+ag::BoxQueryWrapper::BoxQuery () const
+{
+ return priv->query;
+}
+
+ag::BoxQueryWrapper::BoxQueryWrapper (AnimationBoxQuery *query) :
+ priv (std::make_unique (query))
+{
+}
+
+ag::BoxQueryWrapper::~BoxQueryWrapper ()
+{
+}
+
diff --git a/animation-glib/query/geometry-query-private.h b/animation-glib/query/geometry-query-private.h
new file mode 100644
index 0000000..bad90e0
--- /dev/null
+++ b/animation-glib/query/geometry-query-private.h
@@ -0,0 +1,62 @@
+/*
+ * animation-glib/query/geometry-query-private.h
+ *
+ * libanimation is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * libanimation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with eos-companion-app-service. If not, see
+ * .
+ *
+ * Wrapper for the AnimationBoxQuery object into a C++ object satisfying
+ * the animation::BoxQuery interface.
+ */
+#pragma once
+
+#include
+
+#include
+
+#include
+#include
+#include