[gtk+] progresstracker: simple struct to track animation progress



commit e71d09e9cb37a60a026bc39048d0e6ea14394f90
Author: Matt Watson <mattdangerw gmail com>
Date:   Mon Feb 29 21:39:33 2016 -0800

    progresstracker: simple struct to track animation progress

 gtk/Makefile.am                 |    2 +
 gtk/gtkprogresstracker.c        |  250 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkprogresstrackerprivate.h |   75 ++++++++++++
 3 files changed, 327 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 0e92feb..90b3235 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -520,6 +520,7 @@ gtk_private_h_sources =             \
        gtkprintutils.h         \
        gtkprivate.h            \
        gtkpixelcacheprivate.h  \
+       gtkprogresstrackerprivate.h     \
        gtkquery.h              \
        gtkrangeprivate.h       \
        gtkrbtree.h             \
@@ -832,6 +833,7 @@ gtk_base_c_sources =                \
        gtkprivate.c            \
        gtkprivatetypebuiltins.c \
        gtkprogressbar.c        \
+       gtkprogresstracker.c    \
        gtkpixelcache.c         \
        gtkpopover.c            \
        gtkpopovermenu.c        \
diff --git a/gtk/gtkprogresstracker.c b/gtk/gtkprogresstracker.c
new file mode 100644
index 0000000..277fd9a
--- /dev/null
+++ b/gtk/gtkprogresstracker.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright © 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.1 of the License, 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthew Watson <mattdangerw gmail com>
+ */
+
+#include "gtkprogresstrackerprivate.h"
+#include "gtkcsseasevalueprivate.h"
+
+#include <math.h>
+#include <string.h>
+
+/*
+ * Progress tracker is small helper for tracking progress through gtk
+ * animations. It's a simple zero-initable struct, meant to be thrown in a
+ * widget's private data without the need for setup or teardown.
+ *
+ * Progress tracker will handle translating frame clock timestamps to a
+ * fractional progress value for interpolating between animation targets.
+ */
+
+/**
+ * gtk_progress_tracker_init_copy:
+ * @source: The source progress tracker
+ * @dest: The destination progress tracker
+ *
+ * Copy all progress tracker state from the source tracker to dest tracker.
+ **/
+void
+gtk_progress_tracker_init_copy (GtkProgressTracker *source,
+                                GtkProgressTracker *dest)
+{
+  memcpy (dest, source, sizeof (GtkProgressTracker));
+}
+
+/**
+ * gtk_progress_tracker_start:
+ * @tracker: The progress tracker
+ * @duration: Animation duration in us
+ * @delay: Animation delay in us
+ * @iteration_count: Number of iterations to run the animation, must be >= 0
+ *
+ * Begins tracking progress for a new animation. Clears all previous state.
+ **/
+void
+gtk_progress_tracker_start (GtkProgressTracker *tracker,
+                            guint64 duration,
+                            gint64 delay,
+                            gdouble iteration_count)
+{
+  tracker->is_running = TRUE;
+  tracker->last_frame_time = 0;
+  tracker->duration = duration;
+  tracker->iteration = - delay / (gdouble) duration;
+  tracker->iteration_count = iteration_count;
+}
+
+/**
+ * gtk_progress_tracker_finish:
+ * @tracker: The progress tracker
+ *
+ * Stops running the current animation.
+ **/
+void
+gtk_progress_tracker_finish (GtkProgressTracker *tracker)
+{
+  tracker->is_running = FALSE;
+}
+
+/**
+ * gtk_progress_tracker_advance_frame:
+ * @tracker: The progress tracker
+ * @frame_time: The current frame time, usually from the frame clock.
+ *
+ * Increments the progress of the animation forward a frame. If no animation has
+ * been started, does nothing.
+ **/
+void
+gtk_progress_tracker_advance_frame (GtkProgressTracker *tracker,
+                                 guint64 frame_time)
+{
+  gdouble delta;
+
+  if (!tracker->is_running)
+    return;
+
+  if (tracker->last_frame_time == 0)
+    {
+      tracker->last_frame_time = frame_time;
+      return;
+    }
+
+  if (frame_time < tracker->last_frame_time)
+    {
+      g_warning ("Progress tracker frame set backwards, ignoring.");
+      return;
+    }
+
+  delta = (frame_time - tracker->last_frame_time) / (gdouble) tracker->duration;
+  tracker->last_frame_time = frame_time;
+  tracker->iteration += delta;
+}
+
+/**
+ * gtk_progress_tracker_skip_frame:
+ * @tracker: The progress tracker
+ * @frame_time: The current frame time, usually from the frame clock.
+ *
+ * Does not update the progress of the animation forward, but records the frame
+ * to calculate future deltas. Calling this each frame will effectively pause
+ * the animation.
+ **/
+void
+gtk_progress_tracker_skip_frame (GtkProgressTracker *tracker,
+                                 guint64 frame_time)
+{
+  if (!tracker->is_running)
+    return;
+
+  tracker->last_frame_time = frame_time;
+}
+
+/**
+ * gtk_progress_tracker_get_state:
+ * @tracker: The progress tracker
+ *
+ * Returns whether the tracker is before, during or after the currently started
+ * animation. The tracker will only ever be in the before state if the animation
+ * was started with a delay. If no animation has been started, returns
+ * %GTK_PROGRESS_STATE_AFTER.
+ *
+ * Returns: A GtkProgressState
+ **/
+GtkProgressState
+gtk_progress_tracker_get_state (GtkProgressTracker *tracker)
+{
+  if (!tracker->is_running || tracker->iteration > tracker->iteration_count)
+    return GTK_PROGRESS_STATE_AFTER;
+  if (tracker->iteration < 0)
+    return GTK_PROGRESS_STATE_BEFORE;
+  return GTK_PROGRESS_STATE_DURING;
+}
+
+/**
+ * gtk_progress_tracker_get_iteration:
+ * @tracker: The progress tracker
+ *
+ * Returns the fractional number of cycles the animation has completed. For
+ * example, it you started an animation with iteration-count of 2 and are half
+ * way through the second animation, this returns 1.5.
+ *
+ * Returns: The current iteration.
+ **/
+gdouble
+gtk_progress_tracker_get_iteration (GtkProgressTracker *tracker)
+{
+  return tracker->is_running ? CLAMP (tracker->iteration, 0.0, tracker->iteration_count) : 1.0;
+}
+
+/**
+ * gtk_progress_tracker_get_iteration_cycle:
+ * @tracker: The progress tracker
+ *
+ * Returns an integer index of the current iteration cycle tracker is
+ * progressing through. Handles edge cases, such as an iteration value of 2.0
+ * which could be considered the end of the second iteration of the beginning of
+ * the third, in the same way as gtk_progress_tracker_get_progress().
+ *
+ * Returns: The integer count of the current animation cycle.
+ **/
+guint64
+gtk_progress_tracker_get_iteration_cycle (GtkProgressTracker *tracker)
+{
+  gdouble iteration = gtk_progress_tracker_get_iteration (tracker);
+
+  /* Some complexity here. We want an iteration of 0.0 to always map to 0 (start
+   * of the first iteration), but an iteration of 1.0 to also map to 0 (end of
+   * first iteration) and 2.0 to 1 (end of the second iteration).
+   */
+  if (iteration == 0.0)
+    return 0;
+
+  return (guint64) ceil (iteration) - 1;
+}
+
+/**
+ * gtk_progress_tracker_get_progress:
+ * @tracker: The progress tracker
+ * @reversed: If progress should be reversed.
+ *
+ * Gets the progress through the current animation iteration, from [0, 1]. Use
+ * to interpolate between animation targets. If reverse is true each iteration
+ * will begin at 1 and end at 0.
+ *
+ * Returns: The progress value.
+ **/
+gdouble
+gtk_progress_tracker_get_progress (GtkProgressTracker *tracker,
+                                   gboolean reversed)
+{
+  gdouble progress, iteration;
+  guint64 iteration_cycle;
+
+  iteration = gtk_progress_tracker_get_iteration (tracker);
+  iteration_cycle = gtk_progress_tracker_get_iteration_cycle (tracker);
+
+  progress = iteration - iteration_cycle;
+  return reversed ? 1.0 - progress : progress;
+}
+
+/* From clutter-easing.c, based on Robert Penner's
+ * infamous easing equations, MIT license.
+ */
+static gdouble
+ease_out_cubic (gdouble t)
+{
+  gdouble p = t - 1;
+  return p * p * p + 1;
+}
+
+/**
+ * gtk_progress_tracker_get_ease_out_cubic:
+ * @tracker: The progress tracker
+ * @reversed: If progress should be reversed before applying the ease function.
+ *
+ * Applies a simple ease out cubic function to the result of
+ * gtk_progress_tracker_get_progress().
+ *
+ * Returns: The eased progress value.
+ **/
+gdouble
+gtk_progress_tracker_get_ease_out_cubic (GtkProgressTracker *tracker,
+                                         gboolean reversed)
+{
+  gdouble progress = gtk_progress_tracker_get_progress (tracker, reversed);
+  return ease_out_cubic (progress);
+}
diff --git a/gtk/gtkprogresstrackerprivate.h b/gtk/gtkprogresstrackerprivate.h
new file mode 100644
index 0000000..1355dae
--- /dev/null
+++ b/gtk/gtkprogresstrackerprivate.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 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.1 of the License, 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthew Watson <mattdangerw gmail com>
+ */
+
+#ifndef __GTK_PROGRESS_TRACKER_PRIVATE_H__
+#define __GTK_PROGRESS_TRACKER_PRIVATE_H__
+
+#include <glib-object.h>
+#include "gtkcsseasevalueprivate.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GTK_PROGRESS_STATE_BEFORE,
+  GTK_PROGRESS_STATE_DURING,
+  GTK_PROGRESS_STATE_AFTER,
+} GtkProgressState;
+
+typedef struct _GtkProgressTracker GtkProgressTracker;
+
+struct _GtkProgressTracker
+{
+  gboolean is_running;
+  guint64 last_frame_time;
+  guint64 duration;
+  gdouble iteration;
+  gdouble iteration_count;
+};
+
+void                 gtk_progress_tracker_init_copy           (GtkProgressTracker *source,
+                                                               GtkProgressTracker *dest);
+
+void                 gtk_progress_tracker_start               (GtkProgressTracker *tracker,
+                                                               guint64 duration,
+                                                               gint64 delay,
+                                                               gdouble iteration_count);
+
+void                 gtk_progress_tracker_finish              (GtkProgressTracker *tracker);
+
+void                 gtk_progress_tracker_advance_frame       (GtkProgressTracker *tracker,
+                                                               guint64 frame_time);
+
+void                 gtk_progress_tracker_skip_frame          (GtkProgressTracker *tracker,
+                                                               guint64 frame_time);
+
+GtkProgressState     gtk_progress_tracker_get_state           (GtkProgressTracker *tracker);
+
+gdouble              gtk_progress_tracker_get_iteration       (GtkProgressTracker *tracker);
+
+guint64              gtk_progress_tracker_get_iteration_cycle (GtkProgressTracker *tracker);
+
+gdouble              gtk_progress_tracker_get_progress        (GtkProgressTracker *tracker,
+                                                               gboolean reverse);
+
+gdouble              gtk_progress_tracker_get_ease_out_cubic  (GtkProgressTracker *tracker,
+                                                               gboolean reverse);
+
+G_END_DECLS
+
+#endif /* __GTK_PROGRESS_TRACKER_PRIVATE_H__ */


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