progresstracker: simple struct to track animation progress
This commit is contained in:
parent
f1cbd9ca13
commit
e71d09e9cb
@ -520,6 +520,7 @@ gtk_private_h_sources = \
|
|||||||
gtkprintutils.h \
|
gtkprintutils.h \
|
||||||
gtkprivate.h \
|
gtkprivate.h \
|
||||||
gtkpixelcacheprivate.h \
|
gtkpixelcacheprivate.h \
|
||||||
|
gtkprogresstrackerprivate.h \
|
||||||
gtkquery.h \
|
gtkquery.h \
|
||||||
gtkrangeprivate.h \
|
gtkrangeprivate.h \
|
||||||
gtkrbtree.h \
|
gtkrbtree.h \
|
||||||
@ -832,6 +833,7 @@ gtk_base_c_sources = \
|
|||||||
gtkprivate.c \
|
gtkprivate.c \
|
||||||
gtkprivatetypebuiltins.c \
|
gtkprivatetypebuiltins.c \
|
||||||
gtkprogressbar.c \
|
gtkprogressbar.c \
|
||||||
|
gtkprogresstracker.c \
|
||||||
gtkpixelcache.c \
|
gtkpixelcache.c \
|
||||||
gtkpopover.c \
|
gtkpopover.c \
|
||||||
gtkpopovermenu.c \
|
gtkpopovermenu.c \
|
||||||
|
250
gtk/gtkprogresstracker.c
Normal file
250
gtk/gtkprogresstracker.c
Normal file
@ -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);
|
||||||
|
}
|
75
gtk/gtkprogresstrackerprivate.h
Normal file
75
gtk/gtkprogresstrackerprivate.h
Normal file
@ -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__ */
|
Loading…
Reference in New Issue
Block a user