/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*- * * Copyright (C) 2011,2012 Canonical Ltd * Copyright (C) 2015 Mike Gabriel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * 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, see . * * Authors: Robert Ancell * Michael Terry * Mike Gabriel */ private class AnimateTimer : Object { /* x and y are 0.0 to 1.0 */ public delegate double EasingFunc (double x); /* The following are the same intervals that Unity uses */ public const int INSTANT = 150; /* Good for animations that don't convey any information */ public const int FAST = 250; /* Good for animations that convey duplicated information */ public const int NORMAL = 500; public const int SLOW = 1000; /* Good for animations that convey information that is only presented in the animation */ /* speed is in milliseconds */ public unowned EasingFunc easing_func { get; private set; } public int speed { get; set; } public bool is_running { get { return timeout != 0; } } public double progress { get; private set; } /* progress is from 0.0 to 1.0 */ public signal void animate (double progress); /* AnimateTimer requires two things: an easing function and a speed. The speed is just the duration of the animation in milliseconds. The easing function describes how fast the animation occurs at different parts of the duration. See http://hosted.zeh.com.br/tweener/docs/en-us/misc/transitions.html for examples of various easing functions. A few are provided with this class, notably ease_in_out and ease_out_quint. */ /* speed is in milliseconds */ public AnimateTimer (EasingFunc func, int speed) { Object (speed: speed); this.easing_func = func; } ~AnimateTimer () { stop (); } /* temp_speed is in milliseconds */ public void reset (int temp_speed = -1) { stop (); timeout = Timeout.add (16, animate_cb); progress = 0; start_time = 0; extra_time = 0; extra_progress = 0; if (temp_speed == -1) temp_speed = speed; length = temp_speed * TimeSpan.MILLISECOND; } public void stop () { if (timeout != 0) Source.remove (timeout); timeout = 0; } private uint timeout = 0; private TimeSpan start_time = 0; private TimeSpan length = 0; private TimeSpan extra_time = 0; private double extra_progress = 0.0; private bool animate_cb () { if (start_time == 0) start_time = GLib.get_monotonic_time (); var time_progress = normalize_time (GLib.get_monotonic_time ()); progress = calculate_progress (time_progress); animate (progress); if (time_progress >= 1.0) { timeout = 0; return false; } else return true; } /* Returns 0.0 to 1.0 where 1.0 is at or past end_time */ private double normalize_time (TimeSpan now) { if (length == 0) return 1.0f; return (((double)(now - start_time)) / length).clamp (0.0, 1.0); } /* Returns 0.0 to 1.0 where 1.0 is done. time is not normalized yet! */ private double calculate_progress (double time_progress) { var y = easing_func (time_progress); return y.clamp (0.0, 1.0); } public static double ease_in_out (double x) { return (1 - Math.cos (Math.PI * x)) / 2; } /*public static double ease_in_quad (double x) { return Math.pow (x, 2); }*/ /*public static double ease_out_quad (double x) { return -1 * Math.pow (x - 1, 2) + 1; }*/ /*public static double ease_in_quint (double x) { return Math.pow (x, 5); }*/ public static double ease_out_quint (double x) { return Math.pow (x - 1, 5) + 1; } }