2009-11-13 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / timeline.cpp
blobd3cc84e163a3f662c4dec54e6a812cacca405c73
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 (%" G_GINT64_FORMAT " 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;
331 ontick = false;
334 void
335 DispatcherTimer::Start ()
337 started = true;
338 stopped = false;
340 Surface *surface = Deployment::GetCurrent ()->GetSurface ();
342 if (clock) {
343 clock->Reset ();
344 clock->BeginOnTick ();
345 clock->SetRootParentTime (surface->GetTimeManager()->GetCurrentTime());
346 } else {
347 AllocateClock ();
348 char *name = g_strdup_printf ("DispatcherTimer (%p)", this);
349 clock->SetValue (DependencyObject::NameProperty, name);
350 g_free (name);
352 surface->GetTimeManager()->AddClock (clock);
354 clock->BeginOnTick ();
358 void
359 DispatcherTimer::Stop ()
361 if (clock)
362 clock->Stop ();
363 stopped = true;
364 started = false;
365 if (!ontick)
366 Timeline::TeardownClock ();
369 void
370 DispatcherTimer::Restart ()
372 started = false;
373 stopped = false;
374 clock->Reset ();
375 TimeSpan time = clock->GetParentClock()->GetCurrentTime();
376 clock->SetRootParentTime (time);
377 clock->Begin (time);
380 void
381 DispatcherTimer::OnClockCompleted ()
383 started = false;
384 ontick = true;
385 Emit (DispatcherTimer::TickEvent);
386 ontick = false;
388 /* if the timer wasn't stopped or started on
389 the tick event, restart it. Unlike Start,
390 which makes it go on the next tick, Restart
391 includes the time spent on the tick.
393 if the timer was stopped but not started
394 on the tick event, we don't need to keep
395 the clock around anymore.
397 if (!stopped && !started)
398 Restart ();
399 else if (stopped && !started)
400 Timeline::TeardownClock ();
403 Duration
404 DispatcherTimer::GetNaturalDurationCore (Clock *clock)
406 return Duration::FromSeconds (0);
409 void
410 DispatcherTimer::TeardownClock ()
412 if (clock) {
413 Stop ();
414 Timeline::TeardownClock ();