2009-06-17 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / animation.cpp
blob4fe226d8e6a8727636c35ece5a3565eaac22a4fd
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)
65 this->nonResetableFlag = false;
66 this->clock = clock;
67 this->timeline = timeline;
68 this->targetobj = targetobj;
69 this->targetprop = targetprop;
71 clock->AddHandler (clock->CurrentTimeInvalidatedEvent, update_property_value, this);
72 AttachTargetHandler ();
74 AnimationStorage *prev_storage = targetprop->AttachAnimationStorage (targetobj, this);
76 baseValue = new Value(*targetobj->GetValue (targetprop));
78 if (prev_storage) {
79 Value *v = prev_storage->GetResetValue ();
80 stopValue = new Value (*v);
81 prev_storage->FlagAsNonResetable ();
82 delete prev_storage;
83 } else {
84 stopValue = NULL;
88 void
89 AnimationStorage::target_object_destroyed (EventObject *, EventArgs *, gpointer closure)
91 ((AnimationStorage*)closure)->TargetObjectDestroyed ();
94 void
95 AnimationStorage::TargetObjectDestroyed ()
97 if (targetprop != NULL)
98 targetprop->DetachAnimationStorage (targetobj, this);
99 targetobj = NULL;
100 DetachUpdateHandler ();
103 void
104 AnimationStorage::FlagAsNonResetable ()
106 nonResetableFlag = true;
109 bool
110 AnimationStorage::IsCurrentStorage ()
112 if (targetobj == NULL || targetprop == NULL)
113 return false;
115 if (targetprop->GetAnimationStorageFor (targetobj) == this)
116 return true;
118 return false;
121 Value*
122 AnimationStorage::GetStopValue ()
124 if (stopValue)
125 return stopValue;
127 return baseValue;
130 void
131 AnimationStorage::update_property_value (EventObject *, EventArgs *, gpointer closure)
133 ((AnimationStorage*)closure)->UpdatePropertyValue ();
136 void
137 AnimationStorage::UpdatePropertyValue ()
139 if (targetobj == NULL)
140 return;
142 Value *current_value = clock->GetCurrentValue (baseValue, NULL/*XXX*/);
143 if (current_value != NULL && timeline->GetTimelineStatus () == Timeline::TIMELINE_STATUS_OK) {
144 Applier *applier = clock->GetTimeManager ()->GetApplier ();
145 applier->AddPropertyChange (targetobj, targetprop, new Value (*current_value), APPLIER_PRECEDENCE_ANIMATION);
148 delete current_value;
151 void
152 AnimationStorage::ResetPropertyValue ()
154 if (nonResetableFlag)
155 return;
157 if (targetobj == NULL)
158 return;
160 if (timeline->GetTimelineStatus () != Timeline::TIMELINE_STATUS_OK)
161 return;
163 Applier *applier = clock->GetTimeManager ()->GetApplier ();
165 if (stopValue)
166 applier->AddPropertyChange (targetobj, targetprop, new Value (*stopValue), APPLIER_PRECEDENCE_ANIMATION_RESET);
167 else
168 applier->AddPropertyChange (targetobj, targetprop, new Value (*baseValue), APPLIER_PRECEDENCE_ANIMATION_RESET);
171 void
172 AnimationStorage::DetachFromProperty (void)
174 if (targetobj != NULL && targetprop != NULL) {
175 targetprop->DetachAnimationStorage (targetobj, this);
176 targetprop = NULL;
180 void
181 AnimationStorage::DetachTarget ()
183 DetachUpdateHandler ();
184 if (targetobj) {
185 DetachTargetHandler ();
186 targetobj = NULL;
190 void
191 AnimationStorage::DetachUpdateHandler ()
193 if (clock != NULL)
194 clock->RemoveHandler (Clock::CurrentTimeInvalidatedEvent, update_property_value, this);
197 void
198 AnimationStorage::ReAttachUpdateHandler ()
200 if (clock != NULL)
201 clock->AddHandler (Clock::CurrentTimeInvalidatedEvent, update_property_value, this);
204 void
205 AnimationStorage::AttachTargetHandler ()
207 if (!targetobj) return;
208 targetobj->AddHandler (EventObject::DestroyedEvent, target_object_destroyed, this);
211 void
212 AnimationStorage::DetachTargetHandler ()
214 if (!targetobj) return;
215 targetobj->RemoveHandler (EventObject::DestroyedEvent, target_object_destroyed, this);
218 Value*
219 AnimationStorage::GetResetValue ()
221 if (stopValue)
222 return stopValue;
223 else
224 return baseValue;
227 AnimationStorage::~AnimationStorage ()
229 if (baseValue) {
230 delete baseValue;
231 baseValue = NULL;
234 if (stopValue) {
235 delete stopValue;
236 stopValue = NULL;
239 DetachUpdateHandler ();
241 if (targetobj != NULL) {
242 DetachTargetHandler ();
243 DetachFromProperty ();
246 if (clock != NULL) {
247 clock->DetachFromStorage ();
251 AnimationClock::AnimationClock (Animation *timeline)
252 : Clock (timeline)
254 SetObjectType (Type::ANIMATIONCLOCK);
256 this->timeline = timeline;
257 storage = NULL;
260 bool
261 AnimationClock::HookupStorage (DependencyObject *targetobj, DependencyProperty *targetprop)
263 /* Before hooking up make sure that the values our animation generates
264 (doubles, colors, points...) match the values that the property is
265 ready to receive. If not, print an informative message. */
266 Type *property_type = Type::Find (targetprop->GetPropertyType());
267 if (timeline->GetValueKind () != Type::INVALID && !property_type->IsAssignableFrom (timeline->GetValueKind ())) {
268 Type *timeline_type = Type::Find (timeline->GetValueKind ());
270 const char *timeline_type_name = (timeline_type != NULL) ? timeline_type->GetName () : "Invalid";
271 const char *property_type_name = (property_type != NULL) ? property_type->GetName () : "Invalid";
272 g_warning ("%s.%s property value type is '%s' but animation type is '%s'.",
273 targetobj->GetTypeName (), targetprop->GetName(),
274 property_type_name, timeline_type_name);
276 return false;
279 char *name = g_strdup_printf ("AnimationClock for %s, targetobj = %p/%s, targetprop = %s", GetTypeName(),
280 targetobj,
281 targetobj->GetName(),
282 targetprop->GetName());
283 SetName (name);
285 g_free (name);
287 storage = new AnimationStorage (this, timeline, targetobj, targetprop);
288 return true;
291 Value*
292 AnimationClock::GetCurrentValue (Value* defaultOriginValue, Value* defaultDestinationValue)
294 return timeline->GetCurrentValue (defaultOriginValue, defaultDestinationValue, this);
297 void
298 AnimationClock::Stop ()
300 if (storage) {
301 storage->ResetPropertyValue ();
302 storage->DetachUpdateHandler ();
303 if (storage->IsCurrentStorage ())
304 storage->DetachFromProperty ();
307 Clock::Stop ();
310 void
311 AnimationClock::Begin (TimeSpan parentTime)
313 Clock::Begin (parentTime);
316 AnimationClock::~AnimationClock ()
318 if (storage) {
320 if (storage->IsLonely ())
321 delete storage;
322 else {
323 if (state == Clock::Stopped)
324 delete storage;
325 else {
326 if (storage->IsCurrentStorage ()) {
327 storage->DetachFromProperty ();
328 delete storage;
335 void
336 AnimationClock::DetachFromStorage ()
338 storage = NULL;
341 Clock*
342 Animation::AllocateClock()
344 clock = new AnimationClock (this);
346 AttachCompletedHandler ();
348 return clock;
351 Value*
352 Animation::GetTargetValue (Value* defaultOriginValue)
354 return NULL;
357 Value*
358 Animation::GetCurrentValue (Value* defaultOriginValue, Value* defaultDestinationValue,
359 AnimationClock* animationClock)
361 return NULL;
365 Duration
366 Animation::GetNaturalDurationCore (Clock* clock)
368 return Duration::FromSeconds (1);
374 /* storyboard */
376 Storyboard::Storyboard ()
378 SetObjectType (Type::STORYBOARD);
381 Storyboard::~Storyboard ()
383 if (clock) {
384 //printf ("Clock %p (ref=%d)\n", root_clock, root_clock->refcount);
385 StopWithError (/* ignore any error */ NULL);
386 TeardownClockGroup ();
390 TimeSpan
391 Storyboard::GetCurrentTime ()
393 return GetClock() ? GetClock()->GetCurrentTime () : 0;
397 Storyboard::GetCurrentState ()
399 return GetClock() ? GetClock()->GetClockState () : Clock::Stopped;
402 DependencyProperty *
403 Storyboard::GetTargetDependencyProperty ()
405 PropertyPath *path = GetTargetProperty (this);
406 return path ? path->property : NULL;
409 bool
410 Storyboard::HookupAnimationsRecurse (Clock *clock, DependencyObject *targetObject, PropertyPath *targetPropertyPath, MoonError *error)
412 DependencyObject *localTargetObject = NULL;
413 PropertyPath *localTargetPropertyPath = NULL;
415 Timeline *timeline = clock->GetTimeline ();
417 /* get the target object at this level */
418 if (timeline->HasManualTarget ())
419 localTargetObject = timeline->GetManualTarget ();
420 else {
421 const char *targetName = Storyboard::GetTargetName (timeline);
422 if (targetName)
423 localTargetObject = FindName (targetName);
426 /* get the target property path at this level */
427 localTargetPropertyPath = Storyboard::GetTargetProperty (timeline);
430 /* override the object and property passed from our parent here */
431 if (localTargetObject != NULL)
432 targetObject = localTargetObject;
434 if (localTargetPropertyPath != NULL)
435 targetPropertyPath = localTargetPropertyPath;
438 if (clock->Is (Type::CLOCKGROUP)) {
439 for (GList *l = ((ClockGroup*)clock)->child_clocks; l; l = l->next) {
440 if (!HookupAnimationsRecurse ((Clock*)l->data,
441 targetObject,
442 targetPropertyPath,
443 error))
444 return false;
447 else {
448 DependencyProperty *prop = NULL;
449 DependencyObject *realTargetObject;
451 if (!targetPropertyPath) {
452 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Target Property has not been specified.");
453 g_warning ("No target property!");
454 return false;
457 if (!targetObject) {
458 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "No Target or TargetName has been specified");
459 return false;
462 realTargetObject = targetObject;
464 prop = resolve_property_path (&realTargetObject, targetPropertyPath);
466 if (!prop || !realTargetObject) {
467 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "TargetProperty could not be resolved");
468 g_warning ("No property path %s on object of type type %s!",
469 targetPropertyPath->path, targetObject->GetTypeName());
470 return false;
473 if (clock->Is(Type::ANIMATIONCLOCK)) {
474 Animation *animation = (Animation*)timeline;
476 if (!animation->Resolve (realTargetObject, prop)) {
477 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Storyboard value could not be converted to the correct type");
478 return false;
481 if (!((AnimationClock*)clock)->HookupStorage (realTargetObject, prop))
482 return false;
486 return true;
489 void
490 Storyboard::TeardownClockGroup ()
492 if (GetClock()) {
493 Clock *c = GetClock ();
494 ClockGroup *group = c->GetParentClock();
495 if (group)
496 group->RemoveChild (c);
497 clock = NULL;
501 bool
502 Storyboard::BeginWithError (MoonError *error)
504 if (GetHadParent ()) {
505 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Begin a Storyboard which is not the root Storyboard.");
506 return false;
509 /* destroy the clock hierarchy and recreate it to restart.
510 easier than making Begin work again with the existing clock
511 hierarchy */
512 if (clock) {
513 DetachCompletedHandler ();
514 TeardownClockGroup ();
517 if (Validate () == false)
518 return false;
520 // This creates the clock tree for the hierarchy. if a
521 // Timeline A is a child of TimelineGroup B, then Clock cA
522 // will be a child of ClockGroup cB.
523 Clock *root_clock = AllocateClock ();
524 char *name = g_strdup_printf ("Storyboard, named '%s'", GetName());
525 root_clock->SetValue (DependencyObject::NameProperty, name);
526 g_free (name);
528 // walk the clock tree hooking up the correct properties and
529 // creating AnimationStorage's for AnimationClocks.
530 if (!HookupAnimationsRecurse (root_clock, NULL, NULL, error))
531 return false;
533 Deployment::GetCurrent()->GetSurface()->GetTimeManager()->AddClock (root_clock);
535 if (GetBeginTime() == 0)
536 root_clock->BeginOnTick ();
538 return true;
541 void
542 Storyboard::PauseWithError (MoonError *error)
544 if (GetHadParent ()) {
545 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Pause a Storyboard which is not the root Storyboard.");
546 return;
548 if (clock)
549 clock->Pause ();
552 void
553 Storyboard::ResumeWithError (MoonError *error)
555 if (GetHadParent ()) {
556 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Resume a Storyboard which is not the root Storyboard.");
557 return;
559 if (clock)
560 clock->Resume ();
563 void
564 Storyboard::SeekWithError (TimeSpan timespan, MoonError *error)
566 if (GetHadParent ()) {
567 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Seek a Storyboard which is not the root Storyboard.");
568 return;
570 if (clock)
571 clock->Seek (timespan);
574 void
575 Storyboard::SeekAlignedToLastTickWithError (TimeSpan timespan, MoonError *error)
577 if (GetHadParent ()) {
578 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Seek a Storyboard which is not the root Storyboard.");
579 return;
581 if (clock)
582 clock->SeekAlignedToLastTick (timespan);
585 void
586 Storyboard::SkipToFillWithError (MoonError *error)
588 if (GetHadParent ()) {
589 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot SkipToFill a Storyboard which is not the root Storyboard.");
590 return;
592 if (clock) {
593 clock->SkipToFill ();
597 void
598 Storyboard::StopWithError (MoonError *error)
600 if (GetHadParent ()) {
601 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Cannot Stop a Storyboard which is not the root Storyboard.");
602 return;
604 if (clock) {
605 DetachCompletedHandler ();
606 clock->Stop ();
607 TeardownClockGroup ();
611 BeginStoryboard::BeginStoryboard ()
613 SetObjectType (Type::BEGINSTORYBOARD);
616 BeginStoryboard::~BeginStoryboard ()
620 void
621 BeginStoryboard::Fire ()
623 Storyboard *sb = GetStoryboard ();
624 if (sb) {
625 // FIXME I'd imagine we should be bubbling this error/exception upward, no?
626 sb->BeginWithError (NULL);
631 DoubleAnimation::DoubleAnimation ()
633 SetObjectType (Type::DOUBLEANIMATION);
635 doubleToCached = NULL;
636 doubleFromCached = NULL;
637 doubleByCached = NULL;
638 hasCached = FALSE;
641 void DoubleAnimation::EnsureCache (void)
643 doubleFromCached = GetFrom ();
644 doubleToCached = GetTo ();
645 doubleByCached = GetBy ();
646 hasCached = TRUE;
649 Value*
650 DoubleAnimation::GetTargetValue (Value *defaultOriginValue)
652 if (! hasCached)
653 this->EnsureCache ();
655 double start;
657 if (doubleFromCached)
658 start = *doubleFromCached;
659 else if (defaultOriginValue->Is(Type::DOUBLE))
660 start = defaultOriginValue->AsDouble();
661 else
662 start = 0.0;
664 if (doubleToCached)
665 return new Value (*doubleToCached);
666 else if (doubleByCached)
667 return new Value (start + *doubleByCached);
668 else
669 return new Value (start);
672 Value*
673 DoubleAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
674 AnimationClock* animationClock)
676 if (! hasCached)
677 this->EnsureCache ();
679 double start;
681 if (doubleFromCached)
682 start = *doubleFromCached;
683 else if (defaultOriginValue->Is(Type::DOUBLE))
684 start = defaultOriginValue->AsDouble();
685 else
686 start = 0.0;
688 double end;
690 if (doubleToCached) {
691 end = *doubleToCached;
693 else if (doubleByCached) {
694 end = start + *doubleByCached;
696 else {
697 end = start;
700 double progress = animationClock->GetCurrentProgress ();
702 if (GetEasingFunction ())
703 progress = GetEasingFunction()->Ease (progress);
705 return new Value (LERP (start, end, progress));
708 void
709 DoubleAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
711 if (args->GetProperty ()->GetOwnerType() != Type::DOUBLEANIMATION) {
712 DependencyObject::OnPropertyChanged (args, error);
713 return;
716 // Get rid of the cache
717 hasCached = FALSE;
718 doubleToCached = NULL;
719 doubleFromCached = NULL;
720 doubleByCached = NULL;
722 NotifyListenersOfPropertyChange (args, error);
725 ColorAnimation::ColorAnimation ()
727 SetObjectType (Type::COLORANIMATION);
729 colorToCached = NULL;
730 colorFromCached = NULL;
731 colorByCached = NULL;
732 hasCached = FALSE;
735 void ColorAnimation::EnsureCache (void)
737 colorFromCached = GetFrom ();
738 colorToCached = GetTo ();
739 colorByCached = GetBy ();
740 hasCached = TRUE;
743 Value*
744 ColorAnimation::GetTargetValue (Value *defaultOriginValue)
746 if (! hasCached)
747 this->EnsureCache ();
749 Color start;
751 if (colorFromCached)
752 start = *colorFromCached;
753 else if (defaultOriginValue->Is(Type::COLOR))
754 start = *defaultOriginValue->AsColor();
756 if (colorToCached)
757 return new Value (*colorToCached);
758 else if (colorByCached)
759 return new Value (start + *colorByCached);
760 else
761 return new Value (start);
764 Value*
765 ColorAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
766 AnimationClock* animationClock)
768 if (! hasCached)
769 this->EnsureCache ();
771 Color start;
773 if (colorFromCached)
774 start = *colorFromCached;
775 else if (defaultOriginValue->Is(Type::COLOR))
776 start = *defaultOriginValue->AsColor();
778 Color end;
780 if (colorToCached) {
781 end = *colorToCached;
783 else if (colorByCached) {
784 end = start + *colorByCached;
786 else {
787 end = start;
790 double progress = animationClock->GetCurrentProgress ();
792 if (GetEasingFunction ())
793 progress = GetEasingFunction()->Ease (progress);
795 return new Value (LERP (start, end, progress));
798 void
799 ColorAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
801 if (args->GetProperty ()->GetOwnerType() != Type::COLORANIMATION) {
802 DependencyObject::OnPropertyChanged (args, error);
803 return;
806 // Get rid of the cache
807 colorToCached = NULL;
808 colorFromCached = NULL;
809 colorByCached = NULL;
810 hasCached = FALSE;
812 NotifyListenersOfPropertyChange (args, error);
815 PointAnimation::PointAnimation ()
817 SetObjectType (Type::POINTANIMATION);
819 pointToCached = NULL;
820 pointFromCached = NULL;
821 pointByCached = NULL;
822 hasCached = FALSE;
825 PointAnimation::~PointAnimation ()
829 void PointAnimation::EnsureCache (void)
831 pointFromCached = GetFrom ();
832 pointToCached = GetTo ();
833 pointByCached = GetBy ();
834 hasCached = TRUE;
837 Value*
838 PointAnimation::GetTargetValue (Value *defaultOriginValue)
840 if (! hasCached)
841 this->EnsureCache ();
843 Point start;
845 if (pointFromCached)
846 start = *pointFromCached;
847 else if (defaultOriginValue->Is(Type::POINT))
848 start = *defaultOriginValue->AsPoint();
850 if (pointToCached)
851 return new Value (*pointToCached);
852 else if (pointByCached)
853 return new Value (start + *pointByCached);
854 else
855 return new Value (start);
858 Value*
859 PointAnimation::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
860 AnimationClock* animationClock)
862 if (! hasCached)
863 this->EnsureCache ();
865 Point start;
867 if (pointFromCached)
868 start = *pointFromCached;
869 else if (defaultOriginValue->Is(Type::POINT))
870 start = *defaultOriginValue->AsPoint();
872 Point end;
874 if (pointToCached) {
875 end = *pointToCached;
877 else if (pointByCached) {
878 end = start + *pointByCached;
880 else {
881 end = start;
884 double progress = animationClock->GetCurrentProgress ();
886 if (GetEasingFunction ())
887 progress = GetEasingFunction()->Ease (progress);
889 return new Value (LERP (start, end, progress));
892 void
893 PointAnimation::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
895 if (args->GetProperty ()->GetOwnerType() != Type::POINTANIMATION) {
896 DependencyObject::OnPropertyChanged (args, error);
897 return;
900 // Get rid of the cache
901 pointToCached = NULL;
902 pointFromCached = NULL;
903 pointByCached = NULL;
904 hasCached = FALSE;
906 NotifyListenersOfPropertyChange (args, error);
909 KeySpline::KeySpline ()
911 SetObjectType (Type::KEYSPLINE);
913 quadraticsArray = NULL;
916 KeySpline::KeySpline (Point controlPoint1, Point controlPoint2)
918 SetObjectType (Type::KEYSPLINE);
920 quadraticsArray = NULL;
921 SetControlPoint1 (&controlPoint1);
922 SetControlPoint2 (&controlPoint2);
925 KeySpline::KeySpline (double x1, double y1,
926 double x2, double y2)
928 SetObjectType (Type::KEYSPLINE);
930 quadraticsArray = NULL;
932 Point p1 = Point (x1, y1);
933 Point p2 = Point (x2, y2);
935 SetControlPoint1 (&p1);
936 SetControlPoint2 (&p2);
939 KeySpline::~KeySpline ()
941 g_free (quadraticsArray);
942 quadraticsArray = NULL;
946 void
947 KeySpline::RegenerateQuadratics ()
949 quadraticsArray = (moon_quadratic *) g_malloc (sizeof (moon_quadratic) * KEYSPLINE_TOTAL_COUNT);
951 Point c1 = *GetControlPoint1 ();
952 Point c2 = *GetControlPoint2 ();
954 moon_cubic src;
955 src.c0.x = 0; src.c0.y = 0;
956 src.c1.x = c1.x; src.c1.y = c1.y;
957 src.c2.x = c2.x; src.c2.y = c2.y;
958 src.c3.x = 1.0; src.c3.y = 1.0;
960 moon_cubic carr [KEYSPLINE_TOTAL_COUNT];
962 moon_subdivide_cubic_at_level (carr, KEYSPLINE_PRECISION_LEVEL, &src);
963 moon_convert_cubics_to_quadratics (quadraticsArray, carr, KEYSPLINE_TOTAL_COUNT);
966 void
967 KeySpline::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
969 if (args->GetProperty ()->GetOwnerType() != Type::KEYSPLINE) {
970 DependencyObject::OnPropertyChanged (args, error);
971 return;
974 g_free (quadraticsArray);
975 quadraticsArray = NULL;
977 NotifyListenersOfPropertyChange (args, error);
980 double
981 KeySpline::GetSplineProgress (double linearProgress)
983 if (linearProgress >= 1.0)
984 return 1.0;
986 if (linearProgress <= 0.0)
987 return 0.0;
989 if (quadraticsArray == NULL)
990 RegenerateQuadratics ();
992 return moon_quadratic_array_y_for_x (quadraticsArray, linearProgress, KEYSPLINE_TOTAL_COUNT);
995 KeyFrame::KeyFrame ()
997 SetObjectType (Type::KEYFRAME);
1000 KeyFrame::~KeyFrame ()
1004 Value *
1005 KeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1007 g_warning ("KeyFrame::InterpolateValue has been called. The derived class %s should have overridden it.",
1008 GetName ());
1009 return NULL;
1012 static int
1013 KeyFrameComparer (gconstpointer kf1, gconstpointer kf2)
1015 // Assumes timespan keytimes only
1016 TimeSpan ts1 = (*(KeyFrame **) kf1)->resolved_keytime;
1017 TimeSpan ts2 = (*(KeyFrame **) kf2)->resolved_keytime;
1018 TimeSpan tsdiff = ts1 - ts2;
1020 if (tsdiff == 0)
1021 return 0;
1022 else if (tsdiff < 0)
1023 return -1;
1024 else
1025 return 1;
1028 KeyFrameCollection::KeyFrameCollection ()
1030 SetObjectType (Type::KEYFRAME_COLLECTION);
1032 sorted_list = g_ptr_array_new ();
1033 resolved = false;
1036 KeyFrameCollection::~KeyFrameCollection ()
1038 g_ptr_array_free (sorted_list, true);
1041 bool
1042 KeyFrameCollection::AddedToCollection (Value *value, MoonError *error)
1044 if (!DependencyObjectCollection::AddedToCollection (value, error))
1045 return false;
1047 resolved = false;
1049 return true;
1052 void
1053 KeyFrameCollection::RemovedFromCollection (Value *value)
1055 DependencyObjectCollection::RemovedFromCollection (value);
1057 resolved = false;
1060 bool
1061 KeyFrameCollection::Clear ()
1063 resolved = false;
1064 g_ptr_array_set_size (sorted_list, 0);
1065 return DependencyObjectCollection::Clear ();
1068 KeyFrame *
1069 KeyFrameCollection::GetKeyFrameForTime (TimeSpan t, KeyFrame **prev_frame)
1071 KeyFrame *current_keyframe = NULL;
1072 KeyFrame *previous_keyframe = NULL;
1073 int i;
1075 if (sorted_list->len == 0) {
1076 if (prev_frame)
1077 *prev_frame = NULL;
1079 return NULL;
1082 /* Crawl forward to figure out what segment to use (this assumes the list is sorted) */
1083 for (i = 0; i < (int) sorted_list->len; i++) {
1084 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1085 TimeSpan key_end_time = keyframe->resolved_keytime;
1087 if (key_end_time >= t || (i + 1) >= (int) sorted_list->len)
1088 break;
1091 /* Crawl backward to find first non-null frame */
1092 for (; i >= 0; i--) {
1093 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1094 DependencyProperty *value_prop = keyframe->GetDependencyProperty ("Value");
1095 if (keyframe->GetValue (value_prop) != NULL) {
1096 current_keyframe = keyframe;
1097 break;
1101 /* Crawl backward some more to find first non-null prev frame */
1102 for (i--; i >= 0; i--) {
1103 KeyFrame *keyframe = (KeyFrame *) sorted_list->pdata[i];
1104 DependencyProperty *value_prop = keyframe->GetDependencyProperty ("Value");
1105 if (keyframe->GetValue (value_prop) != NULL) {
1106 previous_keyframe = keyframe;
1107 break;
1111 /* Assign prev frame */
1112 if (prev_frame != NULL)
1113 *prev_frame = previous_keyframe;
1115 return current_keyframe;
1118 void
1119 KeyFrameCollection::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
1121 if (strcmp (subobj_args->GetProperty ()->GetName (), "KeyTime") == 0) {
1122 resolved = false;
1125 Collection::OnSubPropertyChanged (prop, obj, subobj_args);
1128 ColorKeyFrameCollection::ColorKeyFrameCollection ()
1130 SetObjectType (Type::COLORKEYFRAME_COLLECTION);
1133 ColorKeyFrameCollection::~ColorKeyFrameCollection ()
1137 DoubleKeyFrameCollection::DoubleKeyFrameCollection ()
1139 SetObjectType (Type::DOUBLEKEYFRAME_COLLECTION);
1142 DoubleKeyFrameCollection::~DoubleKeyFrameCollection ()
1146 PointKeyFrameCollection::PointKeyFrameCollection ()
1148 SetObjectType (Type::POINTKEYFRAME_COLLECTION);
1151 PointKeyFrameCollection::~PointKeyFrameCollection ()
1155 DoubleKeyFrame::DoubleKeyFrame ()
1157 SetObjectType (Type::DOUBLEKEYFRAME);
1158 SetValue (0.0);
1161 DoubleKeyFrame::~DoubleKeyFrame ()
1165 ColorKeyFrame::ColorKeyFrame ()
1167 SetObjectType (Type::COLORKEYFRAME);
1168 static Color c = Color (0, 0, 0, 1);
1169 SetValue (c);
1172 ColorKeyFrame::~ColorKeyFrame ()
1176 PointKeyFrame::PointKeyFrame ()
1178 SetObjectType (Type::POINTKEYFRAME);
1179 SetValue (Point (0,0));
1182 PointKeyFrame::~PointKeyFrame ()
1186 DiscreteDoubleKeyFrame::DiscreteDoubleKeyFrame ()
1188 SetObjectType(Type::DISCRETEDOUBLEKEYFRAME);
1191 DiscreteDoubleKeyFrame::~DiscreteDoubleKeyFrame ()
1195 Value*
1196 DiscreteDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1198 double *to = GetValue();
1200 if (to && keyFrameProgress == 1.0)
1201 return new Value(*to);
1202 else
1203 return new Value (baseValue->AsDouble());
1206 DiscreteColorKeyFrame::DiscreteColorKeyFrame ()
1208 SetObjectType(Type::DISCRETECOLORKEYFRAME);
1211 DiscreteColorKeyFrame::~DiscreteColorKeyFrame ()
1215 Value*
1216 DiscreteColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1218 Color *to = GetValue();
1220 if (to && keyFrameProgress == 1.0)
1221 return new Value(*to);
1222 else
1223 return new Value (*baseValue->AsColor());
1226 DiscretePointKeyFrame::DiscretePointKeyFrame ()
1228 SetObjectType(Type::DISCRETEPOINTKEYFRAME);
1231 DiscretePointKeyFrame::~DiscretePointKeyFrame ()
1235 Value*
1236 DiscretePointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1238 Point *to = GetValue();
1240 if (to && keyFrameProgress == 1.0)
1241 return new Value(*to);
1242 else
1243 return new Value (*baseValue->AsPoint());
1247 LinearDoubleKeyFrame::LinearDoubleKeyFrame ()
1249 SetObjectType(Type::LINEARDOUBLEKEYFRAME);
1252 LinearDoubleKeyFrame::~LinearDoubleKeyFrame ()
1256 Value*
1257 LinearDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1259 double *to = GetValue();
1261 if (!to)
1262 return new Value (baseValue->AsDouble());
1264 double start, end;
1266 start = baseValue->AsDouble();
1267 end = *to;
1269 return new Value (LERP (start, end, keyFrameProgress));
1272 LinearColorKeyFrame::LinearColorKeyFrame ()
1274 SetObjectType(Type::LINEARCOLORKEYFRAME);
1277 LinearColorKeyFrame::~LinearColorKeyFrame ()
1281 Value*
1282 LinearColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1284 Color *to = GetValue();
1286 if (!to)
1287 return new Value (*baseValue->AsColor());
1289 Color start, end;
1291 start = *baseValue->AsColor();
1292 end = *to;
1294 return new Value (LERP (start, end, keyFrameProgress));
1297 LinearPointKeyFrame::LinearPointKeyFrame ()
1299 SetObjectType(Type::LINEARPOINTKEYFRAME);
1302 LinearPointKeyFrame::~LinearPointKeyFrame ()
1306 Value*
1307 LinearPointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1309 Point *to = GetValue();
1311 if (!to)
1312 return new Value (*baseValue->AsPoint());
1314 Point start, end;
1316 start = *baseValue->AsPoint();
1317 end = *to;
1319 return new Value (LERP (start, end, keyFrameProgress));
1322 SplineDoubleKeyFrame::SplineDoubleKeyFrame ()
1324 SetObjectType (Type::SPLINEDOUBLEKEYFRAME);
1327 SplineDoubleKeyFrame::~SplineDoubleKeyFrame ()
1331 Value *
1332 SplineDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1334 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1336 double *to = GetValue();
1338 if (!to)
1339 return new Value (baseValue->AsDouble());
1340 else if (keyFrameProgress >= 1.0)
1341 return new Value (*to);
1343 double start, end;
1345 start = baseValue->AsDouble();
1346 end = *to;
1348 return new Value (LERP (start, end, splineProgress));
1352 SplineColorKeyFrame::SplineColorKeyFrame ()
1354 SetObjectType (Type::SPLINECOLORKEYFRAME);
1357 SplineColorKeyFrame::~SplineColorKeyFrame ()
1361 Value *
1362 SplineColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1364 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1366 Color *to = GetValue();
1368 if (!to)
1369 return new Value (*baseValue->AsColor());
1370 else if (keyFrameProgress >= 1.0)
1371 return new Value (*to);
1373 Color start, end;
1375 start = *baseValue->AsColor();
1376 end = *to;
1378 return new Value (LERP (start, end, splineProgress));
1382 SplinePointKeyFrame::SplinePointKeyFrame ()
1384 SetObjectType (Type::SPLINEPOINTKEYFRAME);
1387 SplinePointKeyFrame::~SplinePointKeyFrame ()
1391 Value *
1392 SplinePointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1394 double splineProgress = GetKeySpline ()->GetSplineProgress (keyFrameProgress);
1396 Point *to = GetValue();
1398 if (!to)
1399 return new Value (*baseValue->AsPoint());
1400 else if (keyFrameProgress >= 1.0)
1401 return new Value (*to);
1403 Point start, end;
1405 start = *baseValue->AsPoint();
1406 end = *to;
1408 return new Value (LERP (start, end, splineProgress));
1411 EasingColorKeyFrame::EasingColorKeyFrame ()
1413 SetObjectType (Type::EASINGCOLORKEYFRAME);
1416 EasingColorKeyFrame::~EasingColorKeyFrame ()
1420 Value *
1421 EasingColorKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1423 Color *to = GetValue();
1425 if (!to)
1426 return new Value (*baseValue->AsColor());
1427 else if (keyFrameProgress >= 1.0)
1428 return new Value (*to);
1430 Color start, end;
1432 start = *baseValue->AsColor();
1433 end = *to;
1435 if (GetEasingFunction ())
1436 GetEasingFunction ()->Ease (keyFrameProgress);
1438 return new Value (LERP (start, end, keyFrameProgress));
1441 EasingDoubleKeyFrame::EasingDoubleKeyFrame ()
1443 SetObjectType (Type::EASINGDOUBLEKEYFRAME);
1446 EasingDoubleKeyFrame::~EasingDoubleKeyFrame ()
1450 Value *
1451 EasingDoubleKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1453 double *to = GetValue();
1455 if (!to)
1456 return new Value (baseValue->AsDouble());
1457 else if (keyFrameProgress >= 1.0)
1458 return new Value (*to);
1460 double start, end;
1462 start = baseValue->AsDouble();
1463 end = *to;
1465 if (GetEasingFunction ())
1466 GetEasingFunction ()->Ease (keyFrameProgress);
1468 return new Value (LERP (start, end, keyFrameProgress));
1472 EasingPointKeyFrame::EasingPointKeyFrame ()
1474 SetObjectType (Type::EASINGPOINTKEYFRAME);
1477 EasingPointKeyFrame::~EasingPointKeyFrame ()
1481 Value *
1482 EasingPointKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1484 Point *to = GetValue();
1486 if (!to)
1487 return new Value (*baseValue->AsPoint());
1488 else if (keyFrameProgress >= 1.0)
1489 return new Value (*to);
1491 Point start, end;
1493 start = *baseValue->AsPoint();
1494 end = *to;
1496 if (GetEasingFunction ())
1497 GetEasingFunction ()->Ease (keyFrameProgress);
1499 return new Value (LERP (start, end, keyFrameProgress));
1502 /* implements the algorithm specified at the bottom of this page:
1503 http://msdn2.microsoft.com/en-us/library/ms742524.aspx
1505 static void
1506 KeyFrameAnimation_ResolveKeyFrames (Animation *animation, KeyFrameCollection *col)
1508 if (col->resolved)
1509 return;
1511 col->resolved = true;
1513 TimeSpan total_interpolation_time;
1514 bool has_timespan_keyframe = false;
1515 TimeSpan highest_keytime_timespan = 0;
1516 KeyFrame *keyframe;
1517 Value *value;
1518 int i;
1520 for (i = 0; i < col->GetCount (); i++) {
1521 value = col->GetValueAt (i);
1522 keyframe = value->AsKeyFrame ();
1523 keyframe->resolved_keytime = 0;
1524 keyframe->resolved = false;
1527 /* resolve TimeSpan keyframes (step 1 from url) */
1528 for (i = 0; i < col->GetCount (); i++) {
1529 value = col->GetValueAt (i);
1530 keyframe = value->AsKeyFrame ();
1532 if (keyframe->GetKeyTime()->HasTimeSpan()) {
1533 has_timespan_keyframe = true;
1534 TimeSpan ts = keyframe->GetKeyTime()->GetTimeSpan ();
1535 if (ts > highest_keytime_timespan)
1536 highest_keytime_timespan = ts;
1538 keyframe->resolved_keytime = ts;
1539 keyframe->resolved = true;
1543 /* calculate total animation interpolation time (step 2 from url) */
1544 Duration *d = animation->GetDuration();
1545 if (d->HasTimeSpan ()) {
1546 total_interpolation_time = d->GetTimeSpan ();
1548 else if (has_timespan_keyframe) {
1549 total_interpolation_time = highest_keytime_timespan;
1551 else {
1552 total_interpolation_time = TimeSpan_FromSeconds (1);
1555 /* use the total interpolation time to resolve percent keytime keyframes (step 3 from url) */
1556 for (i = 0; i < col->GetCount (); i++) {
1557 value = col->GetValueAt (i);
1558 keyframe = value->AsKeyFrame ();
1560 if (keyframe->GetKeyTime()->HasPercent()) {
1561 keyframe->resolved_keytime = (TimeSpan)(total_interpolation_time * keyframe->GetKeyTime()->GetPercent ());
1562 keyframe->resolved = true;
1566 /* step 4 from url */
1567 KeyTime *kt;
1569 /* if the last frame is KeyTime Uniform or Paced, resolve it
1570 to be equal to the total interpolation time */
1571 if (col->GetCount () > 0) {
1572 value = col->GetValueAt (col->GetCount () - 1);
1573 keyframe = value->AsKeyFrame ();
1575 kt = keyframe->GetKeyTime ();
1576 if (*kt == KeyTime::Paced || *kt == KeyTime::Uniform) {
1577 keyframe->resolved_keytime = total_interpolation_time;
1578 keyframe->resolved = true;
1582 /* if the first frame is KeyTime::Paced:
1583 ** 1. if there is only 1 frame, its KeyTime is the total interpolation time.
1584 ** 2. if there is more than 1 frame, its KeyTime is 0.
1586 ** note 1 is handled in the above block so we only have to
1587 ** handle 2 here.
1589 if (col->GetCount () > 0) {
1590 value = col->GetValueAt (0);
1591 keyframe = value->AsKeyFrame ();
1592 kt = keyframe->GetKeyTime ();
1594 if (!keyframe->resolved && *kt == KeyTime::Paced) {
1595 keyframe->resolved_keytime = 0;
1596 keyframe->resolved = true;
1600 /* XXX resolve remaining KeyTime::Uniform frames (step 5 from url) */
1602 /* XXX resolve frames with unspecified keytimes (step 6 from url)
1604 -- is this possible? is the default keytime NULL? it
1605 seems to be Uniform? */
1607 /* XXX resolve remaining KeyTime::Paced frames (step 7 from url) */
1609 /* insert the nodes into the sorted list using a stable sort
1610 with resolved keytime as primary key, declaration order as
1611 secondary key (step 8 from url) */
1612 g_ptr_array_set_size (col->sorted_list, 0);
1614 for (i = col->GetCount (); i > 0; i--) {
1615 value = col->GetValueAt (i - 1);
1616 keyframe = value->AsKeyFrame ();
1618 if (!keyframe->resolved)
1619 g_warning ("***** unresolved keyframe!");
1621 g_ptr_array_insert_sorted (col->sorted_list, KeyFrameComparer, keyframe);
1625 // Generic validator of KeyFrameCollection's. Collection vallidates
1626 // if all keyframes have valid time.
1627 static bool
1628 generic_keyframe_validator (KeyFrameCollection *col)
1630 KeyFrame *keyframe;
1631 Value *value;
1633 for (int i = 0; i < col->GetCount (); i++) {
1634 value = col->GetValueAt (i);
1635 keyframe = value->AsKeyFrame ();
1636 if (keyframe->GetKeyTime () == NULL)
1637 return false;
1640 return true;
1644 DoubleAnimationUsingKeyFrames::DoubleAnimationUsingKeyFrames ()
1646 SetObjectType (Type::DOUBLEANIMATIONUSINGKEYFRAMES);
1649 DoubleAnimationUsingKeyFrames::~DoubleAnimationUsingKeyFrames ()
1653 void
1654 DoubleAnimationUsingKeyFrames::AddKeyFrame (DoubleKeyFrame *frame)
1656 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1658 key_frames->Add (frame);
1661 void
1662 DoubleAnimationUsingKeyFrames::RemoveKeyFrame (DoubleKeyFrame *frame)
1664 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1666 key_frames->Remove (frame);
1669 Value*
1670 DoubleAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1671 AnimationClock* animationClock)
1673 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1675 /* current segment info */
1676 TimeSpan current_time = animationClock->GetCurrentTime();
1677 DoubleKeyFrame *current_keyframe;
1678 DoubleKeyFrame *previous_keyframe;
1679 DoubleKeyFrame** keyframep = &previous_keyframe;
1680 Value *baseValue;
1681 bool deleteBaseValue;
1683 current_keyframe = (DoubleKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1684 if (current_keyframe == NULL) {
1685 //abort ();
1686 return NULL; /* XXX */
1689 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1690 TimeSpan key_start_time;
1692 if (previous_keyframe == NULL) {
1693 /* the first keyframe, start at the animation's base value */
1694 baseValue = defaultOriginValue;
1695 deleteBaseValue = false;
1696 key_start_time = 0;
1698 else {
1699 /* start at the previous keyframe's target value */
1700 baseValue = new Value (*previous_keyframe->GetValue ());
1701 deleteBaseValue = true;
1702 key_start_time = previous_keyframe->resolved_keytime;
1705 double progress;
1707 if (current_time >= key_end_time) {
1708 progress = 1.0;
1710 else {
1711 TimeSpan key_duration = key_end_time - key_start_time;
1712 if (key_duration == 0)
1713 progress = 1.0;
1714 else
1715 progress = (double)(current_time - key_start_time) / key_duration;
1718 /* get the current value out of that segment */
1719 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1720 if (deleteBaseValue)
1721 delete baseValue;
1722 return rv;
1725 Duration
1726 DoubleAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
1728 DoubleKeyFrameCollection *key_frames = GetKeyFrames ();
1730 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1732 guint len = key_frames->sorted_list->len;
1733 if (len > 0)
1734 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1735 else
1736 return Duration (0);
1739 bool
1740 DoubleAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1742 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1743 return true;
1746 bool
1747 DoubleAnimationUsingKeyFrames::Validate ()
1749 return generic_keyframe_validator (GetKeyFrames ());
1752 ColorAnimationUsingKeyFrames::ColorAnimationUsingKeyFrames()
1754 SetObjectType (Type::COLORANIMATIONUSINGKEYFRAMES);
1757 ColorAnimationUsingKeyFrames::~ColorAnimationUsingKeyFrames ()
1761 void
1762 ColorAnimationUsingKeyFrames::AddKeyFrame (ColorKeyFrame *frame)
1764 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1766 key_frames->Add (frame);
1769 void
1770 ColorAnimationUsingKeyFrames::RemoveKeyFrame (ColorKeyFrame *frame)
1772 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1774 key_frames->Remove (frame);
1777 Value*
1778 ColorAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1779 AnimationClock* animationClock)
1781 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1782 /* current segment info */
1783 TimeSpan current_time = animationClock->GetCurrentTime();
1784 ColorKeyFrame *current_keyframe;
1785 ColorKeyFrame *previous_keyframe;
1786 ColorKeyFrame** keyframep = &previous_keyframe;
1787 Value *baseValue;
1788 bool deleteBaseValue;
1790 current_keyframe = (ColorKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1791 if (current_keyframe == NULL)
1792 return NULL; /* XXX */
1794 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1795 TimeSpan key_start_time;
1797 if (previous_keyframe == NULL) {
1798 /* the first keyframe, start at the animation's base value */
1799 baseValue = defaultOriginValue;
1800 deleteBaseValue = false;
1801 key_start_time = 0;
1803 else {
1804 /* start at the previous keyframe's target value */
1805 baseValue = new Value(*previous_keyframe->GetValue ());
1806 deleteBaseValue = true;
1807 key_start_time = previous_keyframe->resolved_keytime;
1810 double progress;
1812 if (current_time >= key_end_time) {
1813 progress = 1.0;
1815 else {
1816 TimeSpan key_duration = key_end_time - key_start_time;
1817 if (key_duration == 0)
1818 progress = 1.0;
1819 else
1820 progress = (double)(current_time - key_start_time) / key_duration;
1823 /* get the current value out of that segment */
1824 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1825 if (deleteBaseValue)
1826 delete baseValue;
1827 return rv;;
1830 Duration
1831 ColorAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
1833 ColorKeyFrameCollection *key_frames = GetKeyFrames ();
1835 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1837 guint len = key_frames->sorted_list->len;
1838 if (len > 0)
1839 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1840 else
1841 return Duration (0);
1844 bool
1845 ColorAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1847 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1848 return true;
1851 bool
1852 ColorAnimationUsingKeyFrames::Validate ()
1854 return generic_keyframe_validator (GetKeyFrames ());
1857 PointAnimationUsingKeyFrames::PointAnimationUsingKeyFrames()
1859 SetObjectType (Type::POINTANIMATIONUSINGKEYFRAMES);
1862 PointAnimationUsingKeyFrames::~PointAnimationUsingKeyFrames ()
1866 void
1867 PointAnimationUsingKeyFrames::AddKeyFrame (PointKeyFrame *frame)
1869 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1871 key_frames->Add (frame);
1874 void
1875 PointAnimationUsingKeyFrames::RemoveKeyFrame (PointKeyFrame *frame)
1877 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1879 key_frames->Remove (frame);
1882 Value*
1883 PointAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
1884 AnimationClock* animationClock)
1886 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1887 /* current segment info */
1888 TimeSpan current_time = animationClock->GetCurrentTime();
1889 PointKeyFrame *current_keyframe;
1890 PointKeyFrame *previous_keyframe;
1891 PointKeyFrame** keyframep = &previous_keyframe;
1892 Value *baseValue;
1893 bool deleteBaseValue;
1895 current_keyframe = (PointKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
1896 if (current_keyframe == NULL)
1897 return NULL; /* XXX */
1899 TimeSpan key_end_time = current_keyframe->resolved_keytime;
1900 TimeSpan key_start_time;
1902 if (previous_keyframe == NULL) {
1903 /* the first keyframe, start at the animation's base value */
1904 baseValue = defaultOriginValue;
1905 deleteBaseValue = false;
1906 key_start_time = 0;
1908 else {
1909 /* start at the previous keyframe's target value */
1910 baseValue = new Value(*previous_keyframe->GetValue ());
1911 deleteBaseValue = true;
1912 key_start_time = previous_keyframe->resolved_keytime;
1915 double progress;
1917 if (current_time >= key_end_time) {
1918 progress = 1.0;
1920 else {
1921 TimeSpan key_duration = key_end_time - key_start_time;
1922 if (key_duration == 0)
1923 progress = 1.0;
1924 else
1925 progress = (double)(current_time - key_start_time) / key_duration;
1928 /* get the current value out of that segment */
1929 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
1930 if (deleteBaseValue)
1931 delete baseValue;
1932 return rv;
1935 Duration
1936 PointAnimationUsingKeyFrames::GetNaturalDurationCore (Clock* clock)
1938 PointKeyFrameCollection *key_frames = GetKeyFrames ();
1940 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
1942 guint len = key_frames->sorted_list->len;
1943 if (len > 0)
1944 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
1945 else
1946 return Duration (0);
1949 bool
1950 PointAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
1952 KeyFrameAnimation_ResolveKeyFrames (this, GetKeyFrames ());
1953 return true;
1956 bool
1957 PointAnimationUsingKeyFrames::Validate ()
1959 return generic_keyframe_validator (GetKeyFrames ());
1962 ObjectKeyFrameCollection::ObjectKeyFrameCollection ()
1964 SetObjectType (Type::OBJECTKEYFRAME_COLLECTION);
1967 ObjectKeyFrameCollection::~ObjectKeyFrameCollection ()
1971 ObjectKeyFrame::ObjectKeyFrame ()
1973 SetObjectType (Type::OBJECTKEYFRAME);
1976 ObjectKeyFrame::~ObjectKeyFrame ()
1980 Value *
1981 ObjectKeyFrame::GetValue ()
1983 return DependencyObject::GetValue (ValueProperty);
1986 DiscreteObjectKeyFrame::DiscreteObjectKeyFrame ()
1988 SetObjectType (Type::DISCRETEOBJECTKEYFRAME);
1991 DiscreteObjectKeyFrame::~DiscreteObjectKeyFrame ()
1995 Value*
1996 DiscreteObjectKeyFrame::InterpolateValue (Value *baseValue, double keyFrameProgress)
1998 Value *to = GetConvertedValue ();
2000 if (to && keyFrameProgress == 1.0)
2001 return new Value (*to);
2002 else
2003 return new Value (*baseValue);
2006 ObjectAnimationUsingKeyFrames::ObjectAnimationUsingKeyFrames ()
2008 SetObjectType (Type::OBJECTANIMATIONUSINGKEYFRAMES);
2011 ObjectAnimationUsingKeyFrames::~ObjectAnimationUsingKeyFrames ()
2015 void
2016 ObjectAnimationUsingKeyFrames::AddKeyFrame (ObjectKeyFrame *frame)
2018 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2020 key_frames->Add (frame);
2023 void
2024 ObjectAnimationUsingKeyFrames::RemoveKeyFrame (ObjectKeyFrame *frame)
2026 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2028 key_frames->Remove (frame);
2031 bool
2032 ObjectAnimationUsingKeyFrames::Resolve (DependencyObject *target, DependencyProperty *property)
2034 ObjectKeyFrameCollection *frames = (ObjectKeyFrameCollection *) GetKeyFrames ();
2035 for (int i = 0; i < frames->GetCount (); i++) {
2036 ObjectKeyFrame *frame = frames->GetValueAt (i)->AsObjectKeyFrame ();
2038 Value *value = frame->GetValue ();
2039 if (!value || value->GetIsNull ()) {
2040 // If the value is null, don't convert
2041 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, NULL);
2042 } else if (value->GetKind () == property->GetPropertyType ()) {
2043 // If the value is of the correct type already, don't convert
2044 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, value);
2045 } else {
2046 Value converted;
2047 Application::GetCurrent ()->ConvertKeyframeValue (target->GetType ()->GetKind (), property, value, &converted);
2049 if (converted.GetKind () == Type::INVALID) {
2050 printf ("Couldn't convert value.\n");
2051 return false;
2053 frame->SetValue (ObjectKeyFrame::ConvertedValueProperty, converted);
2056 KeyFrameAnimation_ResolveKeyFrames (this, frames);
2057 return true;
2060 Value*
2061 ObjectAnimationUsingKeyFrames::GetCurrentValue (Value *defaultOriginValue, Value *defaultDestinationValue,
2062 AnimationClock* animationClock)
2064 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2066 /* current segment info */
2067 TimeSpan current_time = animationClock->GetCurrentTime();
2068 ObjectKeyFrame *current_keyframe;
2069 ObjectKeyFrame *previous_keyframe;
2070 ObjectKeyFrame** keyframep = &previous_keyframe;
2071 Value *baseValue;
2072 bool deleteBaseValue;
2074 current_keyframe = (ObjectKeyFrame*)key_frames->GetKeyFrameForTime (current_time, (KeyFrame**)keyframep);
2075 if (current_keyframe == NULL)
2076 return NULL; /* XXX */
2078 TimeSpan key_end_time = current_keyframe->resolved_keytime;
2079 TimeSpan key_start_time;
2081 if (previous_keyframe == NULL) {
2082 /* the first keyframe, start at the animation's base value */
2083 baseValue = defaultOriginValue;
2084 deleteBaseValue = false;
2085 key_start_time = 0;
2086 } else {
2087 /* start at the previous keyframe's target value */
2088 baseValue = new Value (*previous_keyframe->GetConvertedValue ());
2089 deleteBaseValue = true;
2090 key_start_time = previous_keyframe->resolved_keytime;
2093 double progress;
2095 if (current_time >= key_end_time) {
2096 progress = 1.0;
2097 } else {
2098 TimeSpan key_duration = key_end_time - key_start_time;
2099 if (key_duration == 0)
2100 progress = 1.0;
2101 else
2102 progress = (double)(current_time - key_start_time) / key_duration;
2105 /* get the current value out of that segment */
2106 Value *rv = current_keyframe->InterpolateValue (baseValue, progress);
2108 if (deleteBaseValue)
2109 delete baseValue;
2111 return rv;;
2114 Duration
2115 ObjectAnimationUsingKeyFrames::GetNaturalDurationCore (Clock *clock)
2117 ObjectKeyFrameCollection *key_frames = GetKeyFrames ();
2119 KeyFrameAnimation_ResolveKeyFrames (this, key_frames);
2121 guint len = key_frames->sorted_list->len;
2122 if (len > 0)
2123 return ((KeyFrame *) key_frames->sorted_list->pdata[len - 1])->resolved_keytime;
2124 else
2125 return Duration (0);
2128 bool
2129 ObjectAnimationUsingKeyFrames::Validate ()
2131 // Interesting question -- should we check for null here?
2132 return generic_keyframe_validator (GetKeyFrames ());