5 var _CPAnimationContextStack = nil,
6 _animationFlushingObserver = nil;
12 Function _completionHandlerAgent;
13 Map _animationsByObject;
26 [
self _scheduleAnimationContextStackFlush];
34 if (!_CPAnimationContextStack)
35 _CPAnimationContextStack = [CPArray array];
37 return _CPAnimationContextStack;
40 + (void)runAnimationGroup:(Function)animationsBlock completionHandler:(Function)aCompletionHandler
45 [context setCompletionHandler:aCompletionHandler];
47 animationsBlock(context);
58 _completionHandlerAgent = nil;
59 _animationsByObject =
new Map();
67 [context setDuration:[
self duration]];
74 + (void)_scheduleAnimationContextStackFlush
76 if (!_animationFlushingObserver)
79 CPLog.debug(
"create new observer");
90 if ([_CPAnimationContextStack count])
93 newContext = [currentContext copy];
100 [_CPAnimationContextStack addObject:newContext];
105 if (![_CPAnimationContextStack count])
108 var context = [_CPAnimationContextStack lastObject];
109 [context _flushAnimations];
110 [_CPAnimationContextStack removeLastObject];
113 CPLog.debug(_cmd +
"context stack =" + _CPAnimationContextStack);
118 - (void)_enqueueActionForObject:(
id)anObject keyPath:(id)aKeyPath targetValue:(
id)aTargetValue animationCompletion:(id)animationCompletion
120 var resolvedAction = [
self _actionForObject:anObject keyPath:aKeyPath targetValue:aTargetValue animationCompletion:animationCompletion];
125 var animByKeyPath = _animationsByObject.get(anObject);
129 var newAnimByKeyPath = @{aKeyPath:resolvedAction};
130 _animationsByObject.set(anObject, newAnimByKeyPath);
133 [animByKeyPath setObject:resolvedAction forKey:aKeyPath];
136 - (Object)_actionForObject:(
id)anObject keyPath:(
CPString)aKeyPath targetValue:(
id)aTargetValue animationCompletion:(Function)animationCompletion
144 needsPeriodicFrameUpdates,
145 objectId = [anObject UID];
147 if (!aKeyPath || !anObject || !(animation = [anObject animationForKey:aKeyPath]) || ![animation isKindOfClass:[
CAAnimation class]])
150 duration = [animation duration] || [
self duration];
151 needsPeriodicFrameUpdates = [[anObject animator] needsPeriodicFrameUpdatesForKeyPath:aKeyPath];
153 if (_completionHandlerAgent)
154 _completionHandlerAgent.increment();
156 var animatorClass = [[anObject class] animatorClass];
158 var completionFunction =
function()
160 if (needsPeriodicFrameUpdates)
161 [animatorClass stopUpdaterWithIdentifier:objectId];
163 if (animationCompletion)
164 animationCompletion();
166 if (needsPeriodicFrameUpdates || animationCompletion)
169 if (_completionHandlerAgent)
170 _completionHandlerAgent.decrement();
173 if (![animation isKindOfClass:[
CAPropertyAnimation class]] || !(animatedKeyPath = [animation keyPath]))
174 animatedKeyPath = aKeyPath;
178 values = [animation values];
179 keyTimes = [animation keyTimes];
180 timingFunctions = [animation timingFunctionsControlPoints];
188 if (!isBasicAnimation || (fromValue = [animation fromValue]) == nil)
189 fromValue = [anObject valueForKey:animatedKeyPath];
191 if (!isBasicAnimation || (toValue = [animation toValue]) == nil)
192 toValue = aTargetValue;
194 values = [fromValue, toValue];
196 timingFunctions = isBasicAnimation ? [animation timingFunctionControlPoints] : [_timingFunction controlPoints];
202 keypath:animatedKeyPath,
206 timingfunctions:timingFunctions,
207 completion:completionFunction
211 - (void)_flushAnimations
213 if (![_CPAnimationContextStack count])
216 if (_animationsByObject.size == 0)
218 if (_completionHandlerAgent)
219 _completionHandlerAgent.fire();
222 [
self _startAnimations];
225 - (void)_startAnimations
227 var cssAnimations = [],
230 _animationsByObject.forEach(
function(animByKeyPath, targetView)
232 [animByKeyPath enumerateKeysAndObjectsUsingBlock:function(aKey, anAction, stop)
238 _animationsByObject.clear();
241 var k = timers.length;
245 CPLog.debug(
"START TIMER " + timers[k].
description());
251 var n = cssAnimations.length;
255 CPLog.debug(
"START ANIMATION " + cssAnimations[n].
description());
257 cssAnimations[n].start();
261 - (void)getAnimations:(CPArray)cssAnimations getTimers:(CPArray)timers usingAction:(Object)anAction cssAnimate:(BOOL)needsCSSAnimation
263 var values = anAction.values;
265 if (values.length == 2)
267 var
start = values[0],
270 if (anAction.keypath ==
@"frame" && CGRectEqualToRect(start, end)
271 || anAction.keypath ==
@"frameSize" && CGSizeEqualToSize(start, end)
272 || anAction.keypath ==
@"frameOrigin" && CGPointEqualToPoint(start, end))
276 var targetView = anAction.object,
277 keyPath = anAction.keypath,
278 isFrameKeyPath = (keyPath ==
@"frame" || keyPath ==
@"frameSize"),
279 customLayout = [targetView hasCustomLayoutSubviews],
280 customDrawing = [targetView hasCustomDrawRect],
281 declarative_subviews_layout = (!customLayout || [targetView implementsSelector:
@selector(frameRectOfView:inSuperviewSize:)]),
282 needsPeriodicFrameUpdates = [[targetView animator] needsPeriodicFrameUpdatesForKeyPath:keyPath],
284 animatorClass = [[targetView
class] animatorClass];
286 if (needsCSSAnimation)
288 [animatorClass addAnimations:cssAnimations forAction:anAction];
291 if (needsPeriodicFrameUpdates)
293 [animatorClass addFrameUpdaters:timers forAction:anAction];
296 var subviews = [targetView subviews],
297 count = [subviews count];
299 if (count && isFrameKeyPath)
301 [subviews enumerateObjectsUsingBlock:function(aSubview, idx, stop)
303 if (!declarative_subviews_layout && [aSubview autoresizingMask] == 0)
307 targetFrame = [action.values lastObject];
309 if (CGRectEqualToRect([aSubview frame], targetFrame))
312 if ([aSubview hasCustomDrawRect])
314 action.completion = function()
316 [aSubview setFrame:targetFrame];
318 CPLog.debug(aSubview + " setFrame: " + CPStringFromRect(targetFrame));
320 if (idx == count - 1)
321 [animatorClass stopUpdaterWithIdentifier:[anAction.root UID]];
325 var animate = !needsPeriodicFrameUpdates;
331 - (Object)actionFromAction:(Object)anAction forAnimatedSubview:(
CPView)aView
333 var targetValue = [anAction.values lastObject],
334 startFrame = [aView
frame],
338 if (anAction.keypath ==
"frame")
339 targetValue = targetValue.size;
342 values = [startFrame, endFrame];
351 timingfunctions:anAction.timingfunctions
355 - (void)setCompletionHandler:(Function)aCompletionHandler
357 if (_completionHandlerAgent)
358 _completionHandlerAgent.invalidate();
365 if (!_completionHandlerAgent)
368 return _completionHandlerAgent.completionHandler();
375 - (CGRect)frameRectOfView:(
CPView)aView inSuperviewSize:(CGSize)aSize
380 - (CGRect)frameWithNewSuperviewSize:(CGSize)newSize
387 var oldSize = _superview._frame.size,
388 newFrame = CGRectMakeCopy(_frame),
389 dX = newSize.width - oldSize.width,
390 dY = newSize.height - oldSize.height,
395 (mask &
CPViewMaxXMargin ? oldSize.width - _frame.size.width - _frame.origin.x : 0),
398 (mask &
CPViewMaxYMargin ? oldSize.height - _frame.size.height - _frame.origin.y : 0);
402 newFrame.origin.x += dX * (baseX > 0 ? _frame.origin.x / baseX : evenFractionX);
404 newFrame.size.width += dX * (baseX > 0 ? _frame.size.width / baseX : evenFractionX);
407 newFrame.origin.y += dY * (baseY > 0 ? _frame.origin.y / baseY : evenFractionY);
409 newFrame.size.height += dY * (baseY > 0 ? _frame.size.height / baseY : evenFractionY);
414 - (BOOL)hasCustomDrawRect
416 return self._viewClassFlags & 1;
419 - (BOOL)hasCustomLayoutSubviews
421 return self._viewClassFlags & 2;
428 - (CPArray)controlPoints
430 return [_c1x, _c1y, _c2x, _c2y];
437 - (CPArray)timingFunctionControlPoints
440 return [_timingFunction controlPoints];
449 - (CPArray)timingFunctionsControlPoints
451 var result = [CPArray array];
453 [_timingFunctions enumerateObjectsUsingBlock:function(timingFunction, idx)
465 this._completionHandler = aCompletionHandler;
472 return this._completionHandler;
477 this._completionHandler();
492 if (this.valid && this.total == 0)
503 var _animationFlushingObserverCallback =
function()
506 CPLog.debug(
"_animationFlushingObserverCallback");
508 if ([_CPAnimationContextStack count] == 1)
510 var context = [_CPAnimationContextStack lastObject];
511 [context _flushAnimations];
512 [_CPAnimationContextStack removeLastObject];
516 CPLog.debug(
"_animationFlushingObserver "+_animationFlushingObserver+
" stack:" + [_CPAnimationContextStack count]);
519 if (_animationFlushingObserver && ![_CPAnimationContextStack count])
522 CPLog.debug(
"removeObserver");
525 _animationFlushingObserver = nil;
542 - (void)setDuration:(
double)aValue
552 return _timingFunction;
560 _timingFunction = aValue;
function CFRunLoopAddObserver(runloop, observer, mode)
function CFRunLoopObserverInvalidate(runloop, observer, mode)
var CompletionHandlerAgent
The main run loop for the application.
CPRunLoop currentRunLoop()
void getAnimations:getTimers:usingAction:cssAnimate:(CPArray cssAnimations, [getTimers] CPArray timers, [usingAction] Object anAction, [cssAnimate] BOOL needsCSSAnimation)
An immutable string (collection of characters).
CGRect frameRectOfView:inSuperviewSize:(CPView aView, [inSuperviewSize] CGSize aSize)
global appkit_tag_dom_elements typedef _CPViewFullScreenModeState CPViewNotSizable
CAMediaTimingFunction timingFunction()
CGRect frameWithNewSuperviewSize:(CGSize newSize)
CAMediaTimingFunction timingFunction()
FrameUpdater prototype start
Object actionFromAction:forAnimatedSubview:(Object anAction, [forAnimatedSubview] CPView aView)
unsigned autoresizingMask()
CompletionHandlerAgent prototype fire
CAMediaTimingFunction timingFunction()
function CFRunLoopObserverCreate(activities, repeats, order, callout, context)