diff options
Diffstat (limited to '')
-rw-r--r-- | subprojects/libhandy/src/gtkprogresstracker.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/subprojects/libhandy/src/gtkprogresstracker.c b/subprojects/libhandy/src/gtkprogresstracker.c new file mode 100644 index 0000000..72d2013 --- /dev/null +++ b/subprojects/libhandy/src/gtkprogresstracker.c @@ -0,0 +1,248 @@ +/* + * 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 "gtkprivate.h" */ +/* #include "gtkcsseasevalueprivate.h" */ + +#include <math.h> +#include <string.h> + +#include "hdy-animation-private.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. + * + * Progress tracker will use the GTK_SLOWDOWN environment variable to control + * the speed of animations. This can be useful for debugging. + */ + +static gdouble gtk_slowdown = 1.0; + +/** + * 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) / gtk_slowdown / 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; +} + +/** + * 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 hdy_ease_out_cubic (progress); +} |