2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / animation.cpp
blob376395930da02965bfc8a9245756a68161a30b41
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * animation.cpp: Animation engine
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <glib.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <math.h>
22 #include "application.h"
23 #include "timemanager.h"
24 #include "animation.h"
26 #include "color.h"
27 #include "runtime.h"
28 #include "utils.h"
30 #define LERP(f,t,p) ((f) + ((t) - (f)) * (p))
32 #define KEYSPLINE_PRECISION_LEVEL 4
34 // This is 2 to power of KEYSPLINE_PRECISION_LEVEL
35 #define KEYSPLINE_TOTAL_COUNT 16
37 KeyTime KeyTime::Paced (KeyTime::PACED);
38 KeyTime KeyTime::Uniform (KeyTime::UNIFORM);
41 AnimationStorage sits between an DependencyObject and a DependencyProperty.
42 The AnimationClock creates a storage for DO, and the storage attaches itself to
43 a DP. The DP keeps a list (hashtable) keyed by the DO pointer.
45 The storage can be deleted when
46 - The DP when it's clearing its list of storage objects. This happens when the DP
47 is destroyed.
48 - The AnimationClock is destroyed.
49 - A new storage is created for the same dependencyobject. In this case, the previous
50 storage that was on the list for the DO is replaced.
52 This means the storage can disappear but both the DependencyProperty and the
53 DependencyObject (and AnimationClock) that it referenced might still be
54 alive. It is very important that when the storage is removed, the
55 corresponding references to it be cleared, too - this means removing it
56 from the DP list when it is deleted by the clock, or removing it from the clock
57 when it's deleted by the DP, as well as clearing any event handlers that could
58 still fire up after it's dead.
62 AnimationStorage::AnimationStorage (AnimationClock *clock, Animation *timeline,
63 DependencyObject *targetobj, DependencyProperty *targetprop)
64 : baseValue(NULL), stopValue(NULL), disabled(false)
66 this->clock = clock;
67 this->timeline = timeline;
68 this->targetobj = targetobj;
69 this->targetprop = targetprop;
71 AttachUpdateHandler ();
72 AttachTargetHandler ();
74 AnimationStorage *prev_storage = targetobj->AttachAnimationStorage (targetprop, this);
76 baseValue = targetobj->GetValue (targetprop);
77 if (baseValue)
78 baseValue = new Value(*baseValue);
79 else
80 baseValue = new Value (targetprop->GetPropertyType ());
82 if (prev_storage) {
83 Value *v = prev_storage->GetResetValue ();
84 stopValue = new Value (*v);
88 bool
89 AnimationStorage::IsCurrentStorage ()
91 if (targetobj == NULL || targetprop == NULL)
92 return false;
94 if (targetobj->GetAnimationStorageFor (targetprop) == this)
95 return true;
97 return false;
101 void
102 AnimationStorage::SwitchTarget (DependencyObject *target)
104 bool wasDisabled = disabled;
105 if (!disabled)
106 Disable ();
107 targetobj = target;
108 if (!wasDisabled) {
109 AttachTargetHandler ();
110 AttachUpdateHandler ();
112 disabled = wasDisabled;
115 void
116 AnimationStorage::Enable ()
118 if (!disabled)
119 return;
121 AttachTargetHandler ();
122 AttachUpdateHandler ();
123 disabled = false;
124 UpdatePropertyValue ();
127 void
128 AnimationStorage::Disable ()
130 DetachUpdateHandler ();
131 DetachTargetHandler ();
132 disabled = true;
135 void
136 AnimationStorage::Stop ()
138 ResetPropertyValue ();
141 Value*
142 AnimationStorage::GetResetValue ()
144 if (stopValue)
145 return stopValue;
146 else
147 return baseValue;
150 void
151 AnimationStorage::SetStopValue (Value *value)
153 if (stopValue)
154 delete stopValue;
156 if (value)
157 stopValue = new Value (*value);
158 else
159 stopValue = NULL;
161 // End of public methods
163 // Private methods
164 void
165 AnimationStorage::target_object_destroyed (EventObject *, EventArgs *, gpointer closure)
167 ((AnimationStorage*)closure)->TargetObjectDestroyed ();
170 void
171 AnimationStorage::TargetObjectDestroyed ()
173 DetachUpdateHandler ();
174 targetobj = NULL;
178 void
179 AnimationStorage::update_property_value (EventObject *, EventArgs *, gpointer closure)
181 ((AnimationStorage*)closure)->UpdatePropertyValue ();
184 void
185 AnimationStorage::UpdatePropertyValue ()
187 if (!targetobj) return;
189 Value *current_value = clock->GetCurrentValue (baseValue, stopValue ? stopValue : baseValue);
190 if (current_value != NULL && timeline->GetTimelineStatus () == Timeline::TIMELINE_STATUS_OK) {
191 Applier *applier = clock->GetTimeManager ()->GetApplier ();
192 applier->AddPropertyChange (targetobj, targetprop, new Value (*current_value), APPLIER_PRECEDENCE_ANIMATION);
195 delete current_value;
198 void
199 AnimationStorage::ResetPropertyValue ()
201 if (disabled) return;
203 if (targetobj == NULL || targetprop == NULL)
204 return;
206 if (timeline->GetTimelineStatus () != Timeline::TIMELINE_STATUS_OK)
207 return;
209 Applier *applier = clock->GetTimeManager ()->GetApplier ();
211 if (applier)
212 applier->AddPropertyChange (targetobj, targetprop,
213 new Value (*GetResetValue ()),
214 APPLIER_PRECEDENCE_ANIMATION_RESET);
217 void
218 AnimationStorage::DetachFromProperty ()
220 if (targetobj == NULL || targetprop == NULL)
221 return;
222 targetobj->DetachAnimationStorage (targetprop, this);
225 void
226 AnimationStorage::AttachUpdateHandler ()
228 if (!clock) return;
229 clock->AddHandler (Clock::CurrentTimeInvalidatedEvent, update_property_value, this);
233 void
234 AnimationStorage::DetachUpdateHandler ()
236 if (disabled) return;
237 if (!clock) return;
238 clock->RemoveHandler (Clock::CurrentTimeInvalidatedEvent, update_property_value, this);
241 void
242 AnimationStorage::AttachTargetHandler ()
244 if (!targetobj) return;
245 targetobj->AddHandler (EventObject::DestroyedEvent, target_object_destroyed, this);
248 void
249 AnimationStorage::DetachTargetHandler ()
251 if (disabled) return;
252 if (!targetobj) return;
253 targetobj->RemoveHandler (EventObject::DestroyedEvent, target_object_destroyed, this);
256 AnimationStorage::~AnimationStorage ()
258 DetachTargetHandler ();
259 DetachUpdateHandler ();
260 DetachFromProperty ();
262 if (clock != NULL)
263 clock->DetachStorage ();
265 if (baseValue) {
266 delete baseValue;
267 baseValue = NULL;
270 if (stopValue) {
271 delete stopValue;
272 stopValue = NULL;
276 AnimationClock::AnimationClock (Animation *timeline)
277 : Clock (timeline)
279 SetObjectType (Type::ANIMATIONCLOCK);
281 this->timeline = timeline;
282 storage = NULL;
285 AnimationStorage *
286 AnimationClock::HookupStorage (DependencyObject *targetobj, DependencyProperty *targetprop)
288 /* Before hooking up make sure that the values our animation generates
289 (doubles, colors, points...) match the values that the property is
290 ready to receive. If not, print an informative message. */
291 Type *property_type = Type::Find (targetprop->GetPropertyType());
292 if (timeline->GetValueKind () != Type::INVALID && !property_type->IsAssignableFrom (timeline->GetValueKind ())) {
293 Type *timeline_type = Type::Find (timeline->GetValueKind ());
295 const char *timeline_type_name = (timeline_type != NULL) ? timeline_type->GetName () : "Invalid";
296 const char *property_type_name = (property_type != NULL) ? property_type->GetName () : "Invalid";
297 g_warning ("%s.%s property value type is '%s' but animation type is '%s'.",
298 targetobj->GetTypeName (), targetprop->GetName(),
299 property_type_name, timeline_type_name);
301 return false;
304 char *name = g_strdup_printf ("AnimationClock for %s, targetobj = %p/%s, targetprop = %s", GetTypeName(),
305 targetobj,
306 targetobj->GetName(),
307 targetprop->GetName());
308 SetName (name);
310 g_free (name);
312 if (storage)
313 delete storage;
314 storage = new AnimationStorage (this, timeline, targetobj, targetprop);
315 return storage;
318 Value*
319 AnimationClock::GetCurrentValue (Value* defaultOriginValue, Value* defaultDestinationValue)
321 return timeline->GetCurrentValue (defaultOriginValue, defaultDestinationValue, this);
324 void
325 AnimationClock::Stop ()
327 if (storage) {
328 storage->Stop ();
329 delete storage;
330 storage = NULL;
333 Clock::Stop ();
336 void
337 AnimationClock::Begin (TimeSpan parentTime)
339 Clock::Begin (parentTime);
342 AnimationClock::~AnimationClock ()
344 if (storage) {
345 delete storage;
346 storage = NULL;
350 void
351 AnimationClock::DetachStorage ()
353 storage = NULL;
356 Clock*
357 Animation::AllocateClock()
359 clock = new AnimationClock (this);
361 AttachCompletedHandler ();
363 return clock;
366 Value*
367 Animation::GetTargetValue (Value* defaultOriginValue)
369 return NULL;
372 Value*
373 Animation::GetCurrentValue (Value* defaultOriginValue, Value* defaultDestinationValue,
374 AnimationClock* animationClock)
376 return NULL;
380 Duration
381 Animation::GetNaturalDurationCore (Clock* clock)
383 return Duration::FromSeconds (1);
389 /* storyboard */
391 Storyboard::Storyboard ()
393 SetObjectType (Type::STORYBOARD);
396 Storyboard::~Storyboard ()
398 if (clock) {
399 StopWithError (/* ignore any error */ NULL);
403 TimeSpan
404 Storyboard::GetCurrentTime ()
406 return GetClock() ? GetClock()->GetCurrentTime () : 0;
410 Storyboard::GetCurrentState ()
412 return GetClock() ? GetClock()->GetClockState () : Clock::Stopped;
415 DependencyProperty *
416 Storyboard::GetTargetDependencyProperty ()
418 PropertyPath *path = GetTargetProperty (this);
419 return path ? path->property : NULL;
422 bool
423 Storyboard::HookupAnimationsRecurse (Clock *clock, DependencyObject *targetObject, PropertyPath *targetPropertyPath, GHashTable *promoted_values, MoonError *error)
425 DependencyObject *localTargetObject = NULL;
426 PropertyPath *localTargetPropertyPath = NULL;
428 Timeline *timeline = clock->GetTimeline ();
430 /* get the target object at this level */
431 if (timeline->HasManualTarget ())
432 localTargetObject = timeline->GetManualTarget ();
433 else {
434 const char *targetName = Storyboard::GetTargetName (timeline);
435 if (targetName)
436 localTargetObject = FindName (targetName);
439 /* get the target property path at this level */
440 localTargetPropertyPath = Storyboard::GetTargetProperty (timeline);
443 /* override the object and property passed from our parent here */
444 if (localTargetObject != NULL)
445 targetObject = localTargetObject;
447 if (localTargetPropertyPath != NULL)
448 targetPropertyPath = localTargetPropertyPath;
451 if (clock->Is (Type::CLOCKGROUP)) {
452 for (GList *l = ((ClockGroup*)clock)->child_clocks; l; l = l->next) {
453 if (!HookupAnimationsRecurse ((Clock*)l->data,
454 targetObject,
455 targetPropertyPath,
456 promoted_values,
457 error))
458 return false;
461 else {
462 DependencyProperty *prop = NULL;
463 DependencyObject *realTargetObject;
465 if (!targetPropertyPath) {
466 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Target Property has not been specified.");
467 g_warning ("No target property!");
468 return false;
471 if (!targetObject) {
472 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "No Target or TargetName has been specified");
473 return false;
476 realTargetObject = targetObject;
478 prop = resolve_property_path (&realTargetObject, targetPropertyPath, promoted_values);
480 if (!prop || !realTargetObject) {
481 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "TargetProperty could not be resolved");
482 g_warning ("No property path %s on object of type type %s!",
483 targetPropertyPath->path, targetObject->GetTypeName());
484 return false;
487 if (clock->Is(Type::ANIMATIONCLOCK)) {
488 Animation *animation = (Animation*)timeline;
490 if (!animation->Resolve (realTargetObject, prop)) {
491 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Storyboard value could not be converted to the correct type");
492 return false;
495 if (!((AnimationClock*)clock)->HookupStorage (realTargetObject, prop))
496 return false;
500 return true;
503 bool
504 Storyboard::BeginWithError (MoonError *error)
506 if (GetHadParent ()) {
507 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Begin a Storyboard which is not the root Storyboard.");
508 return false;
511 /* destroy the clock hierarchy and recreate it to restart.
512 easier than making Begin work again with the existing clock
513 hierarchy */
514 if (clock) {
515 DetachCompletedHandler ();
516 clock->Dispose ();
519 if (Validate () == false)
520 return false;
522 // This creates the clock tree for the hierarchy. if a
523 // Timeline A is a child of TimelineGroup B, then Clock cA
524 // will be a child of ClockGroup cB.
525 AllocateClock ();
526 char *name = g_strdup_printf ("Storyboard, named '%s'", GetName());
527 clock->SetValue (DependencyObject::NameProperty, name);
528 g_free (name);
531 // walk the clock tree hooking up the correct properties and
532 // creating AnimationStorage's for AnimationClocks.
533 GHashTable *promoted_values = g_hash_table_new (g_direct_hash, g_direct_equal);
534 if (!HookupAnimationsRecurse (clock, NULL, NULL, promoted_values, error)) {
535 g_hash_table_destroy (promoted_values);
536 return false;
538 g_hash_table_destroy (promoted_values);
540 Deployment::GetCurrent()->GetSurface()->GetTimeManager()->AddClock (clock);
542 if (GetBeginTime() == 0)
543 clock->BeginOnTick ();
545 return true;
548 void
549 Storyboard::PauseWithError (MoonError *error)
551 if (GetHadParent ()) {
552 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Pause a Storyboard which is not the root Storyboard.");
553 return;
555 if (clock)
556 clock->Pause ();
559 void
560 Storyboard::ResumeWithError (MoonError *error)
562 if (GetHadParent ()) {
563 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Resume a Storyboard which is not the root Storyboard.");
564 return;
566 if (clock)
567 clock->Resume ();
570 void
571 Storyboard::SeekWithError (TimeSpan timespan, MoonError *error)
573 if (GetHadParent ()) {
574 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Seek a Storyboard which is not the root Storyboard.");
575 return;
577 if (clock)
578 clock->Seek (timespan);
581 void
582 Storyboard::SeekAlignedToLastTickWithError (TimeSpan timespan, MoonError *error)
584 if (GetHadParent ()) {
585 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Seek a Storyboard which is not the root Storyboard.");
586 return;
588 if (clock)
589 clock->SeekAlignedToLastTick (timespan);
592 void
593 Storyboard::SkipToFillWithError (MoonError *error)
595 if (GetHadParent ()) {
596 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot SkipToFill a Storyboard which is not the root Storyboard.");
597 return;
599 if (clock) {
600 clock->SkipToFill ();
604 void
605 Storyboard::StopWithError (MoonError *error)
607 if (GetHadParent ()) {
608 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Stop a Storyboard which is not the root Storyboard.");
609 return;
611 if (clock) {
612 DetachCompletedHandler ();
613 clock->Stop ();
614 clock->Dispose ();
618 BeginStoryboard::BeginStoryboard ()
620 SetObjectType (Type::BEGINSTORYBOARD);
623 BeginStoryboard::~BeginStoryboard ()
627 void
628 BeginStoryboard::Fire ()
630 Storyboard *sb = GetStoryboard ();
631 if (sb) {
632 // FIXME I'd imagine we should be bubbling this error/exception upward, no?
633 sb->BeginWithError (NULL);
638 DoubleAnimation::DoubleAnimation ()
640 SetObjectType (Type::DOUBLEANIMATION);
642 doubleToCached = NULL;
643 doubleFromCached = NULL;
644 doubleByCached = NULL;
645 hasCached = FALSE;
648 void DoubleAnimation::EnsureCache (void)
650 doubleFromCached = GetFrom ();
651 doubleToCached = GetTo ();
652 doubleByCached = GetBy ();
653 hasCached = TRUE;
656 Value*
657 DoubleAnimation::GetTargetValue (Value *defaultOriginValue)
659 if (! hasCached)
660 this->EnsureCache ();
662 double start;
664 if (doubleFromCached)
665 start = *doubleFromCached;
666 else if (defaultOriginValue->Is(Type::DOUBLE))
667 start = defaultOriginValue->AsDouble();
668 else
669 start = 0.0;
671 if (doubleToCached)
672 return new Value (*doubleToCached);
673 else if (doubleByCached)
674 return new Value (start + *doubleByCached);
675 else
676 return new Value (start);
679 Value*
680 DoubleAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
681 AnimationClock* animationClock)
683 if (! hasCached)
684 this->EnsureCache ();
686 double start;
688 if (doubleFromCached)
689 start = *doubleFromCached;
690 else if (defaultOriginValue->Is(Type::DOUBLE))
691 start = defaultOriginValue->AsDouble();
692 else
693 start = 0.0;
695 double end;
697 if (doubleToCached) {
698 end = *doubleToCached;
700 else if (doubleByCached) {
701 end = start + *doubleByCached;
703 else if (defaultDestinationValue->Is(Type::DOUBLE)) {
704 end = defaultDestinationValue->AsDouble();
706 else
707 end = start;
709 double progress = animationClock->GetCurrentProgress ();
711 if (GetEasingFunction ())
712 progress = GetEasingFunction()->Ease (progress);
714 return new Value (LERP (start, end, progress));
717 void
718 DoubleAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
720 if (args->GetProperty ()->GetOwnerType() != Type::DOUBLEANIMATION) {
721 DependencyObject::OnPropertyChanged (args, error);
722 return;
725 // Get rid of the cache
726 hasCached = FALSE;
727 doubleToCached = NULL;
728 doubleFromCached = NULL;
729 doubleByCached = NULL;
731 NotifyListenersOfPropertyChange (args, error);
734 ColorAnimation::ColorAnimation ()
736 SetObjectType (Type::COLORANIMATION);
738 colorToCached = NULL;
739 colorFromCached = NULL;
740 colorByCached = NULL;
741 hasCached = FALSE;
744 void ColorAnimation::EnsureCache (void)
746 colorFromCached = GetFrom ();
747 colorToCached = GetTo ();
748 colorByCached = GetBy ();
749 hasCached = TRUE;
752 Value*
753 ColorAnimation::GetTargetValue (Value *defaultOriginValue)
755 if (! hasCached)
756 this->EnsureCache ();
758 Color start;
760 if (colorFromCached)
761 start = *colorFromCached;
762 else if (defaultOriginValue->Is(Type::COLOR))
763 start = *defaultOriginValue->AsColor();
765 if (colorToCached)
766 return new Value (*colorToCached);
767 else if (colorByCached)
768 return new Value (start + *colorByCached);
769 else
770 return new Value (start);
773 Value*
774 ColorAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
775 AnimationClock* animationClock)
777 if (! hasCached)
778 this->EnsureCache ();
780 Color start;
782 if (colorFromCached)
783 start = *colorFromCached;
784 else if (defaultOriginValue->Is(Type::COLOR))
785 start = *defaultOriginValue->AsColor();
787 Color end;
789 if (colorToCached) {
790 end = *colorToCached;
792 else if (colorByCached) {
793 end = start + *colorByCached;
795 else if (defaultDestinationValue->Is(Type::COLOR)) {
796 end = *defaultDestinationValue->AsColor();
798 else {
799 end = start;
802 double progress = animationClock->GetCurrentProgress ();
804 if (GetEasingFunction ())
805 progress = GetEasingFunction()->Ease (progress);
807 return new Value (LERP (start, end, progress));
810 void
811 ColorAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
813 if (args->GetProperty ()->GetOwnerType() != Type::COLORANIMATION) {
814 DependencyObject::OnPropertyChanged (args, error);
815 return;
818 // Get rid of the cache
819 colorToCached = NULL;
820 colorFromCached = NULL;
821 colorByCached = NULL;
822 hasCached = FALSE;
824 NotifyListenersOfPropertyChange (args, error);
827 PointAnimation::PointAnimation ()
829 SetObjectType (Type::POINTANIMATION);
831 pointToCached = NULL;
832 pointFromCached = NULL;
833 pointByCached = NULL;
834 hasCached = FALSE;
837 PointAnimation::~PointAnimation ()
841 void PointAnimation::EnsureCache (void)
843 pointFromCached = GetFrom ();
844 pointToCached = GetTo ();
845 pointByCached = GetBy ();
846 hasCached = TRUE;
849 Value*
850 PointAnimation::GetTargetValue (Value *defaultOriginValue)
852 if (! hasCached)
853 this->EnsureCache ();
855 Point start;
857 if (pointFromCached)
858 start = *pointFromCached;
859 else if (defaultOriginValue->Is(Type::POINT))
860 start = *defaultOriginValue->AsPoint();
862 if (pointToCached)
863 return new Value (*pointToCached);
864 else if (pointByCached)
865 return new Value (start + *pointByCached);
866 else
867 return new Value (start);
870 Value*
871 PointAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
872 AnimationClock* animationClock)
874 if (! hasCached)
875 this->EnsureCache ();
877 Point start;
879 if (pointFromCached)
880 start = *pointFromCached;
881 else if (defaultOriginValue->Is(Type::POINT))
882 start = *defaultOriginValue->AsPoint();
884 Point end;
886 if (pointToCached) {
887 end = *pointToCached;
889 else if (pointByCached) {
890 end = start + *pointByCached;
892 else if (defaultDestinationValue->Is(Type::POINT)) {
893 end = *defaultDestinationValue->AsPoint();
895 else {
896 end = start;
899 double progress = animationClock->GetCurrentProgress ();
901 if (GetEasingFunction ())
902 progress = GetEasingFunction()->Ease (progress);
904 return new Value (LERP (start, end, progress));
907 void
908 PointAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
910 if (args->GetProperty ()->GetOwnerType() != Type::POINTANIMATION) {
911 DependencyObject::OnPropertyChanged (args, error);
912 return;
915 // Get rid of the cache
916 pointToCached = NULL;
917 pointFromCached = NULL;
918 pointByCached = NULL;
919 hasCached = FALSE;
921 NotifyListenersOfPropertyChange (args, error);
924 KeySpline::KeySpline ()
926 SetObjectType (Type::KEYSPLINE);
928 quadraticsArray = NULL;
931 KeySpline::KeySpline (Point controlPoint1, Point controlPoint2)
933 SetObjectType (Type::KEYSPLINE);
935 quadraticsArray = NULL;
936 SetControlPoint1 (&controlPoint1);
937 SetControlPoint2 (&controlPoint2);
940 KeySpline::KeySpline (double x1, double y1,
941 double x2, double y2)
943 SetObjectType (Type::KEYSPLINE);
945 quadraticsArray = NULL;
947 Point p1 = Point (x1, y1);
948 Point p2 = Point (x2, y2);
950 SetControlPoint1 (&p1);
951 SetControlPoint2 (&p2);
954 KeySpline::~KeySpline ()
956 g_free (quadraticsArray);
957 quadraticsArray = NULL;
961 void
962 KeySpline::RegenerateQuadratics ()
964 quadraticsArray = (moon_quadratic *) g_malloc (sizeof (moon_quadratic) * KEYSPLINE_TOTAL_COUNT);
966 Point c1 = *GetControlPoint1 ();
967 Point c2 = *GetControlPoint2 ();
969 moon_cubic src;
970 src.c0.x = 0; src.c0.y = 0;
971 src.c1.x = c1.x; src.c1.y = c1.y;
972 src.c2.x = c2.x; src.c2.y = c2.y;
973 src.c3.x = 1.0; src.c3.y = 1.0;
975 moon_cubic carr [KEYSPLINE_TOTAL_COUNT];
977 moon_subdivide_cubic_at_level (carr, KEYSPLINE_PRECISION_LEVEL, &src);
978 moon_convert_cubics_to_quadratics (quadraticsArray, carr, KEYSPLINE_TOTAL_COUNT);
981 void
982 KeySpline::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
984 if (args->GetProperty ()->GetOwnerType() != Type::KEYSPLINE) {
985 DependencyObject::OnPropertyChanged (args, error);
986 return;
989 g_free (quadraticsArray);
990 quadraticsArray = NULL;
992 NotifyListenersOfPropertyChange (args, error);
995 double
996 KeySpline::GetSplineProgress (double linearProgress)
998 if (linearProgress >= 1.0)
999 return 1.0;
1001 if (linearProgress <= 0.0)
1002 return 0.0;
1004 if (quadraticsArray == NULL)
1005 RegenerateQuadratics ();
1007 return moon_quadratic_array_y_for_x (quadraticsArray, linearProgress, KEYSPLINE_TOTAL_COUNT);
1010 KeyFrame::KeyFrame ()
1012 SetObjectType (Type::KEYFRAME);
1015 KeyFrame::~KeyFrame ()
1019 Value *
1020 KeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1022 g_warning ("KeyFrame::InterpolateValue has been called. The derived class %s should have overridden it.",
1023 GetName ());
1024 return NULL;
1027 static int
1028 KeyFrameComparer (gconstpointer kf1, gconstpointer kf2)
1030 // Assumes timespan keytimes only
1031 TimeSpan ts1 = (*(KeyFrame **) kf1)->resolved_keytime;
1032 TimeSpan ts2 = (*(KeyFrame **) kf2)->resolved_keytime;
1033 TimeSpan tsdiff = ts1 - ts2;
1035 if (tsdiff == 0)
1036 return 0;
1037 else if (tsdiff < 0)
1038 return -1;
1039 else
1040 return 1;
1043 KeyFrameCollection::KeyFrameCollection ()
1045 SetObjectType (Type::KEYFRAME_COLLECTION);
1047 sorted_list = g_ptr_array_new ();
1048 resolved = false;
1051 KeyFrameCollection::~KeyFrameCollection ()
1053 g_ptr_array_free (sorted_list, true);
1056 bool
1057 KeyFrameCollection::AddedToCollection (Value *value, MoonError *error)
1059 if (!DependencyObjectCollection::AddedToCollection (value, error))
1060 return false;
1062 resolved = false;
1064 return true;
1067 void
1068 KeyFrameCollection::RemovedFromCollection (Value *value)
1070 DependencyObjectCollection::RemovedFromCollection (value);
1072 resolved = false;
1075 bool
1076 KeyFrameCollection::Clear ()
1078 resolved = false;
1079 g_ptr_array_set_size (sorted_list, 0);
1080 return DependencyObjectCollection::Clear ();
1083 KeyFrame *
1084 KeyFrameCollection::GetKeyFrameForTime (TimeSpan t, KeyFrame **prev_frame)
1086 KeyFrame *current_keyframe = NULL;
1087 KeyFrame *previous_keyframe = NULL;
1088 int i;
1090 if (sorted_list->len == 0) {
1091 if (prev_frame)
1092 *prev_frame = NULL;
1094 return NULL;
1097 /* Crawl forward to figure out what segment to use (this assumes the list is sorted) */
1098 for (i = 0; i < (int) sorted_list->len; i++) {
1099 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1100 TimeSpan key_end_time = keyframe->resolved_keytime;
1102 if (key_end_time >= t || (i + 1) >= (int) sorted_list->len)
1103 break;
1106 /* Crawl backward to find first non-null frame */
1107 for (; i >= 0; i--) {
1108 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1109 DependencyProperty *value_prop = keyframe->GetDependencyProperty ("Value");
1110 if (keyframe->GetValue (value_prop) != NULL) {
1111 current_keyframe = keyframe;
1112 break;
1116 /* Crawl backward some more to find first non-null prev frame */
1117 for (i--; i >= 0; i--) {
1118 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1119 DependencyProperty *value_prop = keyframe->GetDependencyProperty ("Value");
1120 if (keyframe->GetValue (value_prop) != NULL) {
1121 previous_keyframe = keyframe;
1122 break;
1126 /* Assign prev frame */
1127 if (prev_frame != NULL)
1128 *prev_frame = previous_keyframe;
1130 return current_keyframe;
1133 void
1134 KeyFrameCollection::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
1136 if (strcmp (subobj_args->GetProperty ()->GetName (), "KeyTime") == 0) {
1137 resolved = false;
1140 Collection::OnSubPropertyChanged (prop, obj, subobj_args);
1143 ColorKeyFrameCollection::ColorKeyFrameCollection ()
1145 SetObjectType (Type::COLORKEYFRAME_COLLECTION);
1148 ColorKeyFrameCollection::~ColorKeyFrameCollection ()
1152 DoubleKeyFrameCollection::DoubleKeyFrameCollection ()
1154 SetObjectType (Type::DOUBLEKEYFRAME_COLLECTION);
1157 DoubleKeyFrameCollection::~DoubleKeyFrameCollection ()
1161 PointKeyFrameCollection::PointKeyFrameCollection ()
1163 SetObjectType (Type::POINTKEYFRAME_COLLECTION);
1166 PointKeyFrameCollection::~PointKeyFrameCollection ()
1170 DoubleKeyFrame::DoubleKeyFrame ()
1172 SetObjectType (Type::DOUBLEKEYFRAME);
1173 SetValue (0.0);
1176 DoubleKeyFrame::~DoubleKeyFrame ()
1180 ColorKeyFrame::ColorKeyFrame ()
1182 SetObjectType (Type::COLORKEYFRAME);
1183 static Color c = Color (0, 0, 0, 1);
1184 SetValue (c);
1187 ColorKeyFrame::~ColorKeyFrame ()
1191 PointKeyFrame::PointKeyFrame ()
1193 SetObjectType (Type::POINTKEYFRAME);
1194 SetValue (Point (0,0));
1197 PointKeyFrame::~PointKeyFrame ()
1201 DiscreteDoubleKeyFrame::DiscreteDoubleKeyFrame ()
1203 SetObjectType(Type::DISCRETEDOUBLEKEYFRAME);
1206 DiscreteDoubleKeyFrame::~DiscreteDoubleKeyFrame ()
1210 Value*
1211 DiscreteDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1213 double *to = GetValue();
1215 if (to && keyFrameProgress == 1.0)
1216 return new Value(*to);
1217 else
1218 return new Value (baseValue->AsDouble());
1221 DiscreteColorKeyFrame::DiscreteColorKeyFrame ()
1223 SetObjectType(Type::DISCRETECOLORKEYFRAME);
1226 DiscreteColorKeyFrame::~DiscreteColorKeyFrame ()
1230 Value*
1231 DiscreteColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1233 Color *to = GetValue();
1235 if (to && keyFrameProgress == 1.0)
1236 return new Value(*to);
1237 else
1238 return new Value (*baseValue->AsColor());
1241 DiscretePointKeyFrame::DiscretePointKeyFrame ()
1243 SetObjectType(Type::DISCRETEPOINTKEYFRAME);
1246 DiscretePointKeyFrame::~DiscretePointKeyFrame ()
1250 Value*
1251 DiscretePointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1253 Point *to = GetValue();
1255 if (to && keyFrameProgress == 1.0)
1256 return new Value(*to);
1257 else
1258 return new Value (*baseValue->AsPoint());
1262 LinearDoubleKeyFrame::LinearDoubleKeyFrame ()
1264 SetObjectType(Type::LINEARDOUBLEKEYFRAME);
1267 LinearDoubleKeyFrame::~LinearDoubleKeyFrame ()
1271 Value*
1272 LinearDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1274 double *to = GetValue();
1276 if (!to)
1277 return new Value (baseValue->AsDouble());
1279 double start, end;
1281 start = baseValue->AsDouble();
1282 end = *to;
1284 return new Value (LERP (start, end, keyFrameProgress));
1287 LinearColorKeyFrame::LinearColorKeyFrame ()
1289 SetObjectType(Type::LINEARCOLORKEYFRAME);
1292 LinearColorKeyFrame::~LinearColorKeyFrame ()
1296 Value*
1297 LinearColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1299 Color *to = GetValue();
1301 if (!to)
1302 return new Value (*baseValue->AsColor());
1304 Color start, end;
1306 start = *baseValue->AsColor();
1307 end = *to;
1309 return new Value (LERP (start, end, keyFrameProgress));
1312 LinearPointKeyFrame::LinearPointKeyFrame ()
1314 SetObjectType(Type::LINEARPOINTKEYFRAME);
1317 LinearPointKeyFrame::~LinearPointKeyFrame ()
1321 Value*
1322 LinearPointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1324 Point *to = GetValue();
1326 if (!to)
1327 return new Value (*baseValue->AsPoint());
1329 Point start, end;
1331 start = *baseValue->AsPoint();
1332 end = *to;
1334 return new Value (LERP (start, end, keyFrameProgress));
1337 SplineDoubleKeyFrame::SplineDoubleKeyFrame ()
1339 SetObjectType (Type::SPLINEDOUBLEKEYFRAME);
1342 SplineDoubleKeyFrame::~SplineDoubleKeyFrame ()
1346 Value *
1347 SplineDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1349 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1351 double *to = GetValue();
1353 if (!to)
1354 return new Value (baseValue->AsDouble());
1355 else if (keyFrameProgress >= 1.0)
1356 return new Value (*to);
1358 double start, end;
1360 start = baseValue->AsDouble();
1361 end = *to;
1363 return new Value (LERP (start, end, splineProgress));
1367 SplineColorKeyFrame::SplineColorKeyFrame ()
1369 SetObjectType (Type::SPLINECOLORKEYFRAME);
1372 SplineColorKeyFrame::~SplineColorKeyFrame ()
1376 Value *
1377 SplineColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1379 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1381 Color *to = GetValue();
1383 if (!to)
1384 return new Value (*baseValue->AsColor());
1385 else if (keyFrameProgress >= 1.0)
1386 return new Value (*to);
1388 Color start, end;
1390 start = *baseValue->AsColor();
1391 end = *to;
1393 return new Value (LERP (start, end, splineProgress));
1397 SplinePointKeyFrame::SplinePointKeyFrame ()
1399 SetObjectType (Type::SPLINEPOINTKEYFRAME);
1402 SplinePointKeyFrame::~SplinePointKeyFrame ()
1406 Value *
1407 SplinePointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1409 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1411 Point *to = GetValue();
1413 if (!to)
1414 return new Value (*baseValue->AsPoint());
1415 else if (keyFrameProgress >= 1.0)
1416 return new Value (*to);
1418 Point start, end;
1420 start = *baseValue->AsPoint();
1421 end = *to;
1423 return new Value (LERP (start, end, splineProgress));
1426 EasingColorKeyFrame::EasingColorKeyFrame ()
1428 SetObjectType (Type::EASINGCOLORKEYFRAME);
1431 EasingColorKeyFrame::~EasingColorKeyFrame ()
1435 Value *
1436 EasingColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1438 Color *to = GetValue();
1440 if (!to)
1441 return new Value (*baseValue->AsColor());
1442 else if (keyFrameProgress >= 1.0)
1443 return new Value (*to);
1445 Color start, end;
1447 start = *baseValue->AsColor();
1448 end = *to;
1450 if (GetEasingFunction ())
1451 GetEasingFunction ()->Ease (keyFrameProgress);
1453 return new Value (LERP (start, end, keyFrameProgress));
1456 EasingDoubleKeyFrame::EasingDoubleKeyFrame ()
1458 SetObjectType (Type::EASINGDOUBLEKEYFRAME);
1461 EasingDoubleKeyFrame::~EasingDoubleKeyFrame ()
1465 Value *
1466 EasingDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1468 double *to = GetValue();
1470 if (!to)
1471 return new Value (baseValue->AsDouble());
1472 else if (keyFrameProgress >= 1.0)
1473 return new Value (*to);
1475 double start, end;
1477 start = baseValue->AsDouble();
1478 end = *to;
1480 if (GetEasingFunction ())
1481 GetEasingFunction ()->Ease (keyFrameProgress);
1483 return new Value (LERP (start, end, keyFrameProgress));
1487 EasingPointKeyFrame::EasingPointKeyFrame ()
1489 SetObjectType (Type::EASINGPOINTKEYFRAME);
1492 EasingPointKeyFrame::~EasingPointKeyFrame ()
1496 Value *
1497 EasingPointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1499 Point *to = GetValue();
1501 if (!to)
1502 return new Value (*baseValue->AsPoint());
1503 else if (keyFrameProgress >= 1.0)
1504 return new Value (*to);
1506 Point start, end;
1508 start = *baseValue->AsPoint();
1509 end = *to;
1511 if (GetEasingFunction ())
1512 GetEasingFunction ()->Ease (keyFrameProgress);
1514 return new Value (LERP (start, end, keyFrameProgress));
1517 /* implements the algorithm specified at the bottom of this page:
1518 http://msdn2.microsoft.com/en-us/library/ms742524.aspx
1520 static void
1521 KeyFrameAnimation_ResolveKeyFrames (Animation *animation, KeyFrameCollection *col)
1523 if (col->resolved)
1524 return;
1526 col->resolved = true;
1528 TimeSpan total_interpolation_time;
1529 bool has_timespan_keyframe = false;
1530 TimeSpan highest_keytime_timespan = 0;
1531 KeyFrame *keyframe;
1532 Value *value;
1533 int i;
1535 for (i = 0; i < col->GetCount (); i++) {
1536 value = col->GetValueAt (i);
1537 keyframe = value->AsKeyFrame ();
1538 keyframe->resolved_keytime = 0;
1539 keyframe->resolved = false;
1542 /* resolve TimeSpan keyframes (step 1 from url) */
1543 for (i = 0; i < col->GetCount (); i++) {
1544 value = col->GetValueAt (i);
1545 keyframe = value->AsKeyFrame ();
1547 if (keyframe->GetKeyTime()->HasTimeSpan()) {
1548 has_timespan_keyframe = true;
1549 TimeSpan ts = keyframe->GetKeyTime()->GetTimeSpan ();
1550 if (ts > highest_keytime_timespan)
1551 highest_keytime_timespan = ts;
1553 keyframe->resolved_keytime = ts;
1554 keyframe->resolved = true;
1558 /* calculate total animation interpolation time (step 2 from url) */
1559 Duration *d = animation->GetDuration();
1560 if (d->HasTimeSpan ()) {
1561 total_interpolation_time = d->GetTimeSpan ();
1563 else if (has_timespan_keyframe) {
1564 total_interpolation_time = highest_keytime_timespan;
1566 else {
1567 total_interpolation_time = TimeSpan_FromSeconds (1);
1570 /* use the total interpolation time to resolve percent keytime keyframes (step 3 from url) */
1571 for (i = 0; i < col->GetCount (); i++) {
1572 value = col->GetValueAt (i);
1573 keyframe = value->AsKeyFrame ();
1575 if (keyframe->GetKeyTime()->HasPercent()) {
1576 keyframe->resolved_keytime = (TimeSpan)(total_interpolation_time * keyframe->GetKeyTime()->GetPercent ());
1577 keyframe->resolved = true;
1581 /* step 4 from url */
1582 KeyTime *kt;
1584 /* if the last frame is KeyTime Uniform or Paced, resolve it
1585 to be equal to the total interpolation time */
1586 if (col->GetCount () > 0) {
1587 value = col->GetValueAt (col->GetCount () - 1);
1588 keyframe = value->AsKeyFrame ();
1590 kt = keyframe->GetKeyTime ();
1591 if (*kt == KeyTime::Paced || *kt == KeyTime::Uniform) {
1592 keyframe->resolved_keytime = total_interpolation_time;
1593 keyframe->resolved = true;
1597 /* if the first frame is KeyTime::Paced:
1598 ** 1. if there is only 1 frame, its KeyTime is the total interpolation time.
1599 ** 2. if there is more than 1 frame, its KeyTime is 0.
1601 ** note 1 is handled in the above block so we only have to
1602 ** handle 2 here.
1604 if (col->GetCount () > 0) {
1605 value = col->GetValueAt (0);
1606 keyframe = value->AsKeyFrame ();
1607 kt = keyframe->GetKeyTime ();
1609 if (!keyframe->resolved && *kt == KeyTime::Paced) {
1610 keyframe->resolved_keytime = 0;
1611 keyframe->resolved = true;
1615 /* XXX resolve remaining KeyTime::Uniform frames (step 5 from url) */
1617 /* XXX resolve frames with unspecified keytimes (step 6 from url)
1619 -- is this possible? is the default keytime NULL? it
1620 seems to be Uniform? */
1622 /* XXX resolve remaining KeyTime::Paced frames (step 7 from url) */
1624 /* insert the nodes into the sorted list using a stable sort
1625 with resolved keytime as primary key, declaration order as
1626 secondary key (step 8 from url) */
1627 g_ptr_array_set_size (col->sorted_list, 0);
1629 for (i = col->GetCount (); i > 0; i--) {
1630 value = col->GetValueAt (i - 1);
1631 keyframe = value->AsKeyFrame ();
1633 if (!keyframe->resolved)
1634 g_warning ("***** unresolved keyframe!");
1636 g_ptr_array_insert_sorted (col->sorted_list, KeyFrameComparer, keyframe);
1640 // Generic validator of KeyFrameCollection's. Collection vallidates
1641 // if all keyframes have valid time.
1642 static bool
1643 generic_keyframe_validator (KeyFrameCollection *col)
1645 KeyFrame *keyframe;
1646 Value *value;
1648 for (int i = 0; i < col->GetCount (); i++) {
1649 value = col->GetValueAt (i);
1650 keyframe = value->AsKeyFrame ();
1651 if (keyframe->GetKeyTime () == NULL)
1652 return false;
1655 return true;
1659 DoubleAnimationUsingKeyFrames::DoubleAnimationUsingKeyFrames ()
1661 SetObjectType (Type::DOUBLEANIMATIONUSINGKEYFRAMES);
1664 DoubleAnimationUsingKeyFrames::~DoubleAnimationUsingKeyFrames ()
1668 void
1669 DoubleAnimationUsingKeyFrames::AddKeyFrame (DoubleKeyFrame *frame)
1671 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1673 key_frames->Add (frame);
1676 void
1677 DoubleAnimationUsingKeyFrames::RemoveKeyFrame (DoubleKeyFrame *frame)
1679 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1681 key_frames->Remove (frame);
1684 Value*
1685 DoubleAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1686 AnimationClock* animationClock)
1688 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1690 /* current segment info */
1691 TimeSpan current_time = animationClock->GetCurrentTime();
1692 DoubleKeyFrame *current_keyframe;
1693 DoubleKeyFrame *previous_keyframe;
1694 DoubleKeyFrame** keyframep = &previous_keyframe;
1695 Value *baseValue;
1696 bool deleteBaseValue;
1698 current_keyframe = (DoubleKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1699 if (current_keyframe == NULL) {
1700 //abort ();
1701 return NULL; /* XXX */
1704 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1705 TimeSpan key_start_time;
1707 if (previous_keyframe == NULL) {
1708 /* the first keyframe, start at the animation's base value */
1709 baseValue = defaultOriginValue;
1710 deleteBaseValue = false;
1711 key_start_time = 0;
1713 else {
1714 /* start at the previous keyframe's target value */
1715 baseValue = new Value (*previous_keyframe->GetValue ());
1716 deleteBaseValue = true;
1717 key_start_time = previous_keyframe->resolved_keytime;
1720 double progress;
1722 if (current_time >= key_end_time) {
1723 progress = 1.0;
1725 else {
1726 TimeSpan key_duration = key_end_time - key_start_time;
1727 if (key_duration == 0)
1728 progress = 1.0;
1729 else
1730 progress = (double)(current_time - key_start_time) / key_duration;
1733 /* get the current value out of that segment */
1734 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1735 if (deleteBaseValue)
1736 delete baseValue;
1737 return rv;
1740 Duration
1741 DoubleAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
1743 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1745 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1747 guint len = key_frames->sorted_list->len;
1748 if (len > 0)
1749 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1750 else
1751 return Duration (0);
1754 bool
1755 DoubleAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1757 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1758 return true;
1761 bool
1762 DoubleAnimationUsingKeyFrames::Validate ()
1764 return generic_keyframe_validator (GetKeyFrames ());
1767 ColorAnimationUsingKeyFrames::ColorAnimationUsingKeyFrames()
1769 SetObjectType (Type::COLORANIMATIONUSINGKEYFRAMES);
1772 ColorAnimationUsingKeyFrames::~ColorAnimationUsingKeyFrames ()
1776 void
1777 ColorAnimationUsingKeyFrames::AddKeyFrame (ColorKeyFrame *frame)
1779 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1781 key_frames->Add (frame);
1784 void
1785 ColorAnimationUsingKeyFrames::RemoveKeyFrame (ColorKeyFrame *frame)
1787 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1789 key_frames->Remove (frame);
1792 Value*
1793 ColorAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1794 AnimationClock* animationClock)
1796 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1797 /* current segment info */
1798 TimeSpan current_time = animationClock->GetCurrentTime();
1799 ColorKeyFrame *current_keyframe;
1800 ColorKeyFrame *previous_keyframe;
1801 ColorKeyFrame** keyframep = &previous_keyframe;
1802 Value *baseValue;
1803 bool deleteBaseValue;
1805 current_keyframe = (ColorKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1806 if (current_keyframe == NULL)
1807 return NULL; /* XXX */
1809 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1810 TimeSpan key_start_time;
1812 if (previous_keyframe == NULL) {
1813 /* the first keyframe, start at the animation's base value */
1814 baseValue = defaultOriginValue;
1815 deleteBaseValue = false;
1816 key_start_time = 0;
1818 else {
1819 /* start at the previous keyframe's target value */
1820 baseValue = new Value(*previous_keyframe->GetValue ());
1821 deleteBaseValue = true;
1822 key_start_time = previous_keyframe->resolved_keytime;
1825 double progress;
1827 if (current_time >= key_end_time) {
1828 progress = 1.0;
1830 else {
1831 TimeSpan key_duration = key_end_time - key_start_time;
1832 if (key_duration == 0)
1833 progress = 1.0;
1834 else
1835 progress = (double)(current_time - key_start_time) / key_duration;
1838 /* get the current value out of that segment */
1839 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1840 if (deleteBaseValue)
1841 delete baseValue;
1842 return rv;;
1845 Duration
1846 ColorAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
1848 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1850 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1852 guint len = key_frames->sorted_list->len;
1853 if (len > 0)
1854 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1855 else
1856 return Duration (0);
1859 bool
1860 ColorAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1862 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1863 return true;
1866 bool
1867 ColorAnimationUsingKeyFrames::Validate ()
1869 return generic_keyframe_validator (GetKeyFrames ());
1872 PointAnimationUsingKeyFrames::PointAnimationUsingKeyFrames()
1874 SetObjectType (Type::POINTANIMATIONUSINGKEYFRAMES);
1877 PointAnimationUsingKeyFrames::~PointAnimationUsingKeyFrames ()
1881 void
1882 PointAnimationUsingKeyFrames::AddKeyFrame (PointKeyFrame *frame)
1884 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1886 key_frames->Add (frame);
1889 void
1890 PointAnimationUsingKeyFrames::RemoveKeyFrame (PointKeyFrame *frame)
1892 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1894 key_frames->Remove (frame);
1897 Value*
1898 PointAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1899 AnimationClock* animationClock)
1901 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1902 /* current segment info */
1903 TimeSpan current_time = animationClock->GetCurrentTime();
1904 PointKeyFrame *current_keyframe;
1905 PointKeyFrame *previous_keyframe;
1906 PointKeyFrame** keyframep = &previous_keyframe;
1907 Value *baseValue;
1908 bool deleteBaseValue;
1910 current_keyframe = (PointKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1911 if (current_keyframe == NULL)
1912 return NULL; /* XXX */
1914 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1915 TimeSpan key_start_time;
1917 if (previous_keyframe == NULL) {
1918 /* the first keyframe, start at the animation's base value */
1919 baseValue = defaultOriginValue;
1920 deleteBaseValue = false;
1921 key_start_time = 0;
1923 else {
1924 /* start at the previous keyframe's target value */
1925 baseValue = new Value(*previous_keyframe->GetValue ());
1926 deleteBaseValue = true;
1927 key_start_time = previous_keyframe->resolved_keytime;
1930 double progress;
1932 if (current_time >= key_end_time) {
1933 progress = 1.0;
1935 else {
1936 TimeSpan key_duration = key_end_time - key_start_time;
1937 if (key_duration == 0)
1938 progress = 1.0;
1939 else
1940 progress = (double)(current_time - key_start_time) / key_duration;
1943 /* get the current value out of that segment */
1944 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1945 if (deleteBaseValue)
1946 delete baseValue;
1947 return rv;
1950 Duration
1951 PointAnimationUsingKeyFrames::GetNaturalDurationCore (Clock* clock)
1953 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1955 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1957 guint len = key_frames->sorted_list->len;
1958 if (len > 0)
1959 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1960 else
1961 return Duration (0);
1964 bool
1965 PointAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1967 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1968 return true;
1971 bool
1972 PointAnimationUsingKeyFrames::Validate ()
1974 return generic_keyframe_validator (GetKeyFrames ());
1977 ObjectKeyFrameCollection::ObjectKeyFrameCollection ()
1979 SetObjectType (Type::OBJECTKEYFRAME_COLLECTION);
1982 ObjectKeyFrameCollection::~ObjectKeyFrameCollection ()
1986 ObjectKeyFrame::ObjectKeyFrame ()
1988 SetObjectType (Type::OBJECTKEYFRAME);
1991 ObjectKeyFrame::~ObjectKeyFrame ()
1995 Value *
1996 ObjectKeyFrame::GetValue ()
1998 return DependencyObject::GetValue (ValueProperty);
2001 DiscreteObjectKeyFrame::DiscreteObjectKeyFrame ()
2003 SetObjectType (Type::DISCRETEOBJECTKEYFRAME);
2006 DiscreteObjectKeyFrame::~DiscreteObjectKeyFrame ()
2010 Value*
2011 DiscreteObjectKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
2013 Value *to = GetConvertedValue ();
2015 if (to && keyFrameProgress == 1.0)
2016 return new Value (*to);
2017 else
2018 return new Value (*baseValue);
2021 ObjectAnimationUsingKeyFrames::ObjectAnimationUsingKeyFrames ()
2023 SetObjectType (Type::OBJECTANIMATIONUSINGKEYFRAMES);
2026 ObjectAnimationUsingKeyFrames::~ObjectAnimationUsingKeyFrames ()
2030 void
2031 ObjectAnimationUsingKeyFrames::AddKeyFrame (ObjectKeyFrame *frame)
2033 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2035 key_frames->Add (frame);
2038 void
2039 ObjectAnimationUsingKeyFrames::RemoveKeyFrame (ObjectKeyFrame *frame)
2041 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2043 key_frames->Remove (frame);
2046 bool
2047 ObjectAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
2049 ObjectKeyFrameCollection *frames = (ObjectKeyFrameCollection *) GetKeyFrames ();
2050 for (int i = 0; i < frames->GetCount (); i++) {
2051 ObjectKeyFrame *frame = frames->GetValueAt (i)->AsObjectKeyFrame ();
2053 Value *value = frame->GetValue ();
2054 if (!value || value->GetIsNull ()) {
2055 // If the value is null, don't convert
2056 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, NULL);
2057 } else if (value->GetKind () == property->GetPropertyType ()) {
2058 // If the value is of the correct type already, don't convert
2059 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, value);
2060 } else {
2061 Value converted;
2062 Application::GetCurrent ()->ConvertKeyframeValue (target->GetType ()->GetKind (), property, value, &converted);
2064 if (converted.GetKind () == Type::INVALID) {
2065 printf ("Couldn't convert value.\n");
2066 return false;
2068 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, converted);
2071 KeyFrameAnimation_ResolveKeyFrames (this, frames);
2072 return true;
2075 Value*
2076 ObjectAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
2077 AnimationClock* animationClock)
2079 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2081 /* current segment info */
2082 TimeSpan current_time = animationClock->GetCurrentTime();
2083 ObjectKeyFrame *current_keyframe;
2084 ObjectKeyFrame *previous_keyframe;
2085 ObjectKeyFrame** keyframep = &previous_keyframe;
2086 Value *baseValue;
2087 bool deleteBaseValue;
2089 current_keyframe = (ObjectKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
2090 if (current_keyframe == NULL)
2091 return NULL; /* XXX */
2093 TimeSpan key_end_time = current_keyframe->resolved_keytime;
2094 TimeSpan key_start_time;
2096 if (previous_keyframe == NULL) {
2097 /* the first keyframe, start at the animation's base value */
2098 baseValue = defaultOriginValue;
2099 deleteBaseValue = false;
2100 key_start_time = 0;
2101 } else {
2102 /* start at the previous keyframe's target value */
2103 baseValue = new Value (*previous_keyframe->GetConvertedValue ());
2104 deleteBaseValue = true;
2105 key_start_time = previous_keyframe->resolved_keytime;
2108 double progress;
2110 if (current_time >= key_end_time) {
2111 progress = 1.0;
2112 } else {
2113 TimeSpan key_duration = key_end_time - key_start_time;
2114 if (key_duration == 0)
2115 progress = 1.0;
2116 else
2117 progress = (double)(current_time - key_start_time) / key_duration;
2120 /* get the current value out of that segment */
2121 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
2123 if (deleteBaseValue)
2124 delete baseValue;
2126 return rv;;
2129 Duration
2130 ObjectAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
2132 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2134 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
2136 guint len = key_frames->sorted_list->len;
2137 if (len > 0)
2138 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
2139 else
2140 return Duration (0);
2143 bool
2144 ObjectAnimationUsingKeyFrames::Validate ()
2146 // Interesting question -- should we check for null here?
2147 return generic_keyframe_validator (GetKeyFrames ());