2009-09-12 Chris Toshok <toshok@ximian.com>
[moon.git] / src / timeline.cpp
blobb51415c4c408c58f1e92a3a0369228c36f02ea78
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * clock.cpp: Clock management
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>
21 #include "timeline.h"
22 #include "timemanager.h"
24 #include "uielement.h"
25 #include "runtime.h"
26 #include "deployment.h"
27 #include "ptr.h"
29 /* timeline */
31 Timeline::Timeline ()
33 SetObjectType (Type::TIMELINE);
35 had_parent = false;
36 manual_target = NULL;
37 timeline_status = TIMELINE_STATUS_OK;
38 clock = NULL;
41 Timeline::~Timeline ()
45 Clock*
46 Timeline::AllocateClock ()
48 clock = new Clock (this);
50 AttachCompletedHandler ();
52 return clock;
55 Clock*
56 Timeline::GetClock ()
58 return clock;
61 bool
62 Timeline::Validate ()
64 RepeatBehavior *repeat = GetRepeatBehavior ();
65 Duration *duration = GetDuration ();
67 if (duration->HasTimeSpan () && duration->GetTimeSpan () == 0 &&
68 (GetFillBehavior () == FillBehaviorStop || (repeat->HasCount () && repeat->GetCount () > 1.0)))
69 timeline_status = TIMELINE_STATUS_DETACHED;
71 // FIXME This should prolly be changed to a more generic if BeginTime > Duration
72 // Need to investigate, though SL checking seems to be very selective
73 if (duration->HasTimeSpan () && duration->GetTimeSpan () == 0 &&
74 this->GetBeginTime () > 0)
75 return false;
77 return true;
80 void
81 Timeline::SetRepeatBehavior (RepeatBehavior behavior)
83 SetValue (Timeline::RepeatBehaviorProperty, Value(behavior));
86 RepeatBehavior *
87 Timeline::GetRepeatBehavior ()
89 return GetValue (Timeline::RepeatBehaviorProperty)->AsRepeatBehavior();
92 void
93 Timeline::SetDuration (Duration duration)
95 SetValue (Timeline::DurationProperty, Value(duration));
98 Duration*
99 Timeline::GetDuration ()
101 return GetValue (Timeline::DurationProperty)->AsDuration();
104 Duration
105 Timeline::GetNaturalDuration (Clock *clock)
107 Duration* d = GetDuration ();
108 if (*d == Duration::Automatic) {
109 // printf ("automatic duration, we need to calculate it\n");
110 Duration cd = GetNaturalDurationCore (clock);
111 // if (cd.HasTimeSpan ())
112 // printf (" + duration (%lld timespan)\n", cd.GetTimeSpan ());
113 // else if (cd == Duration::Automatic)
114 // printf (" + automatic\n");
115 // else if (cd == Duration::Forever)
116 // printf (" + forever\n");
117 return cd;
119 else {
120 return *d;
124 Duration
125 Timeline::GetNaturalDurationCore (Clock *clock)
127 return Duration::Automatic;
130 TimeSpan
131 Timeline::GetBeginTime ()
133 Value *v = GetValue (Timeline::BeginTimeProperty);
134 return v == NULL ? 0LL : v->AsTimeSpan();
137 void
138 Timeline::AttachCompletedHandler ()
140 clock->AddHandler (Clock::CompletedEvent, clock_completed, this);
143 void
144 Timeline::DetachCompletedHandler ()
146 clock->RemoveHandler (Clock::CompletedEvent, clock_completed, this);
149 void
150 Timeline::clock_completed (EventObject *sender, EventArgs *calldata, gpointer closure)
152 Timeline *timeline = (Timeline *) closure;
153 timeline->OnClockCompleted ();
156 void
157 Timeline::OnClockCompleted ()
159 Emit (Timeline::CompletedEvent);
162 void
163 Timeline::TeardownClock ()
165 if (clock) {
166 DetachCompletedHandler ();
167 Clock *c = clock;
168 ClockGroup *group = c->GetParentClock();
169 if (group)
170 group->RemoveChild (c);
171 clock = NULL;
172 c->unref ();
176 /* timeline group */
178 TimelineGroup::TimelineGroup ()
180 SetObjectType (Type::TIMELINEGROUP);
183 TimelineGroup::~TimelineGroup ()
187 Clock *
188 TimelineGroup::AllocateClock ()
190 clock = new ClockGroup (this);
191 TimelineCollection *collection = GetChildren ();
193 for (int i = 0; i < collection->GetCount (); i++)
194 ((ClockGroup*)clock)->AddChild (collection->GetValueAt (i)->AsTimeline ()->AllocateClock ());
196 AttachCompletedHandler ();
197 return clock;
200 // Validate this TimelineGroup by validating all of it's children
201 bool
202 TimelineGroup::Validate ()
204 TimelineCollection *collection = GetChildren ();
205 Timeline *timeline;
207 for (int i = 0; i < collection->GetCount (); i++) {
208 timeline = collection->GetValueAt (i)->AsTimeline ();
209 if (!timeline->Validate ())
210 return false;
213 return Timeline::Validate ();
216 void
217 TimelineGroup::AddChild (Timeline *child)
219 TimelineCollection *children = GetChildren ();
220 children->Add (child);
223 void
224 TimelineGroup::RemoveChild (Timeline *child)
226 TimelineCollection *children = GetChildren ();
228 children->Remove (child);
231 void
232 TimelineGroup::OnCollectionChanged (Collection *col, CollectionChangedEventArgs *args)
234 if (col == GetChildren()) {
235 if (args->GetChangedAction() == CollectionChangedActionAdd ||
236 args->GetChangedAction() == CollectionChangedActionReplace) {
237 Timeline *timeline = args->GetNewItem()->AsTimeline ();
238 if (timeline)
239 timeline->SetHadParent (true);
245 TimelineCollection::TimelineCollection ()
247 SetObjectType (Type::TIMELINE_COLLECTION);
250 TimelineCollection::~TimelineCollection ()
254 ParallelTimeline::ParallelTimeline ()
256 SetObjectType (Type::PARALLELTIMELINE);
259 ParallelTimeline::~ParallelTimeline ()
263 Duration
264 ParallelTimeline::GetNaturalDurationCore (Clock *clock)
266 TimelineCollection *collection = GetChildren ();
267 Duration d = Duration::Automatic;
268 TimeSpan duration_span = 0;
269 Timeline *timeline;
271 if (collection->GetCount () == 0)
272 return Duration::FromSeconds (0);
274 for (int i = 0; i < collection->GetCount (); i++) {
275 timeline = collection->GetValueAt (i)->AsTimeline ();
277 Duration duration = timeline->GetNaturalDuration (clock);
278 if (duration.IsAutomatic())
279 continue;
281 if (duration.IsForever())
282 return Duration::Forever;
284 TimeSpan span = duration.GetTimeSpan ();
286 RepeatBehavior *repeat = timeline->GetRepeatBehavior ();
287 if (repeat->IsForever())
288 return Duration::Forever;
290 if (repeat->HasCount ())
291 span = (TimeSpan) (span * repeat->GetCount ());
293 if (timeline->GetAutoReverse ())
294 span *= 2;
296 // If we have duration-base repeat behavior,
297 // clamp/up our span to that.
298 if (repeat->HasDuration ())
299 span = repeat->GetDuration ();
301 if (span != 0)
302 span = (TimeSpan)(span / timeline->GetSpeedRatio());
304 span += timeline->GetBeginTime ();
306 if (duration_span <= span) {
307 duration_span = span;
308 d = Duration (duration_span);
312 return d;
315 TimelineMarker::TimelineMarker ()
317 SetObjectType (Type::TIMELINEMARKER);
320 TimelineMarker::~TimelineMarker ()
324 DispatcherTimer::DispatcherTimer ()
326 SetObjectType (Type::DISPATCHERTIMER);
328 clock = NULL;
329 stopped = false;
330 started = false;
333 void
334 DispatcherTimer::Start ()
336 started = true;
337 stopped = false;
339 Surface *surface = Deployment::GetCurrent ()->GetSurface ();
341 if (clock) {
342 clock->Reset ();
343 clock->BeginOnTick ();
344 clock->SetRootParentTime (surface->GetTimeManager()->GetCurrentTime());
345 } else {
346 AllocateClock ();
347 char *name = g_strdup_printf ("DispatcherTimer (%p)", this);
348 clock->SetValue (DependencyObject::NameProperty, name);
349 g_free (name);
351 surface->GetTimeManager()->AddClock (clock);
353 clock->BeginOnTick ();
357 void
358 DispatcherTimer::Stop ()
360 clock->Stop ();
361 stopped = true;
362 started = false;
365 void
366 DispatcherTimer::Restart ()
368 started = false;
369 stopped = false;
370 clock->Reset ();
371 TimeSpan time = clock->GetParentClock()->GetCurrentTime();
372 clock->SetRootParentTime (time);
373 clock->Begin (time);
376 void
377 DispatcherTimer::OnClockCompleted ()
379 started = false;
380 Emit (DispatcherTimer::TickEvent);
382 /* if the timer wasn't stopped on started on
383 the tick event, restart it. Unlike Start,
384 which makes it go on the next tick, Restart
385 includes the time spent on the tick.
387 if (!IsStopped () && !IsStarted ())
388 Restart ();
391 Duration
392 DispatcherTimer::GetNaturalDurationCore (Clock *clock)
394 return Duration::FromSeconds (0);
397 void
398 DispatcherTimer::TeardownClock ()
400 if (clock) {
401 Stop ();
402 Timeline::TeardownClock ();