You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1307 lines
35 KiB
1307 lines
35 KiB
/** |
|
Copyright (c) 2014-present, Facebook, Inc. |
|
All rights reserved. |
|
|
|
This source code is licensed under the BSD-style license found in the |
|
LICENSE file in the root directory of this source tree. An additional grant |
|
of patent rights can be found in the PATENTS file in the same directory. |
|
*/ |
|
|
|
#import "POPAnimatableProperty.h" |
|
|
|
#import <QuartzCore/QuartzCore.h> |
|
|
|
#import "POPAnimationRuntime.h" |
|
#import "POPCGUtils.h" |
|
#import "POPDefines.h" |
|
#import "POPLayerExtras.h" |
|
|
|
// common threshold definitions |
|
static CGFloat const kPOPThresholdColor = 0.01; |
|
static CGFloat const kPOPThresholdPoint = 1.0; |
|
static CGFloat const kPOPThresholdOpacity = 0.01; |
|
static CGFloat const kPOPThresholdScale = 0.005; |
|
static CGFloat const kPOPThresholdRotation = 0.01; |
|
static CGFloat const kPOPThresholdRadius = 0.01; |
|
|
|
#pragma mark - Static |
|
|
|
// CALayer |
|
NSString * const kPOPLayerBackgroundColor = @"backgroundColor"; |
|
NSString * const kPOPLayerBounds = @"bounds"; |
|
NSString * const kPOPLayerCornerRadius = @"cornerRadius"; |
|
NSString * const kPOPLayerBorderWidth = @"borderWidth"; |
|
NSString * const kPOPLayerBorderColor = @"borderColor"; |
|
NSString * const kPOPLayerOpacity = @"opacity"; |
|
NSString * const kPOPLayerPosition = @"position"; |
|
NSString * const kPOPLayerPositionX = @"positionX"; |
|
NSString * const kPOPLayerPositionY = @"positionY"; |
|
NSString * const kPOPLayerRotation = @"rotation"; |
|
NSString * const kPOPLayerRotationX = @"rotationX"; |
|
NSString * const kPOPLayerRotationY = @"rotationY"; |
|
NSString * const kPOPLayerScaleX = @"scaleX"; |
|
NSString * const kPOPLayerScaleXY = @"scaleXY"; |
|
NSString * const kPOPLayerScaleY = @"scaleY"; |
|
NSString * const kPOPLayerSize = @"size"; |
|
NSString * const kPOPLayerSubscaleXY = @"subscaleXY"; |
|
NSString * const kPOPLayerSubtranslationX = @"subtranslationX"; |
|
NSString * const kPOPLayerSubtranslationXY = @"subtranslationXY"; |
|
NSString * const kPOPLayerSubtranslationY = @"subtranslationY"; |
|
NSString * const kPOPLayerSubtranslationZ = @"subtranslationZ"; |
|
NSString * const kPOPLayerTranslationX = @"translationX"; |
|
NSString * const kPOPLayerTranslationXY = @"translationXY"; |
|
NSString * const kPOPLayerTranslationY = @"translationY"; |
|
NSString * const kPOPLayerTranslationZ = @"translationZ"; |
|
NSString * const kPOPLayerZPosition = @"zPosition"; |
|
NSString * const kPOPLayerShadowColor = @"shadowColor"; |
|
NSString * const kPOPLayerShadowOffset = @"shadowOffset"; |
|
NSString * const kPOPLayerShadowOpacity = @"shadowOpacity"; |
|
NSString * const kPOPLayerShadowRadius = @"shadowRadius"; |
|
|
|
// CAShapeLayer |
|
NSString * const kPOPShapeLayerStrokeStart = @"shapeLayer.strokeStart"; |
|
NSString * const kPOPShapeLayerStrokeEnd = @"shapeLayer.strokeEnd"; |
|
NSString * const kPOPShapeLayerStrokeColor = @"shapeLayer.strokeColor"; |
|
NSString * const kPOPShapeLayerFillColor = @"shapeLayer.fillColor"; |
|
NSString * const kPOPShapeLayerLineWidth = @"shapeLayer.lineWidth"; |
|
NSString * const kPOPShapeLayerLineDashPhase = @"shapeLayer.lineDashPhase"; |
|
|
|
// NSLayoutConstraint |
|
NSString * const kPOPLayoutConstraintConstant = @"layoutConstraint.constant"; |
|
|
|
#if TARGET_OS_IPHONE |
|
|
|
// UIView |
|
NSString * const kPOPViewAlpha = @"view.alpha"; |
|
NSString * const kPOPViewBackgroundColor = @"view.backgroundColor"; |
|
NSString * const kPOPViewBounds = kPOPLayerBounds; |
|
NSString * const kPOPViewCenter = @"view.center"; |
|
NSString * const kPOPViewFrame = @"view.frame"; |
|
NSString * const kPOPViewScaleX = @"view.scaleX"; |
|
NSString * const kPOPViewScaleXY = @"view.scaleXY"; |
|
NSString * const kPOPViewScaleY = @"view.scaleY"; |
|
NSString * const kPOPViewSize = kPOPLayerSize; |
|
NSString * const kPOPViewTintColor = @"view.tintColor"; |
|
|
|
// UIScrollView |
|
NSString * const kPOPScrollViewContentOffset = @"scrollView.contentOffset"; |
|
NSString * const kPOPScrollViewContentSize = @"scrollView.contentSize"; |
|
NSString * const kPOPScrollViewZoomScale = @"scrollView.zoomScale"; |
|
NSString * const kPOPScrollViewContentInset = @"scrollView.contentInset"; |
|
NSString * const kPOPScrollViewScrollIndicatorInsets = @"scrollView.scrollIndicatorInsets"; |
|
|
|
// UITableView |
|
NSString * const kPOPTableViewContentOffset = kPOPScrollViewContentOffset; |
|
NSString * const kPOPTableViewContentSize = kPOPScrollViewContentSize; |
|
|
|
// UICollectionView |
|
NSString * const kPOPCollectionViewContentOffset = kPOPScrollViewContentOffset; |
|
NSString * const kPOPCollectionViewContentSize = kPOPScrollViewContentSize; |
|
|
|
// UINavigationBar |
|
NSString * const kPOPNavigationBarBarTintColor = @"navigationBar.barTintColor"; |
|
|
|
// UIToolbar |
|
NSString * const kPOPToolbarBarTintColor = kPOPNavigationBarBarTintColor; |
|
|
|
// UITabBar |
|
NSString * const kPOPTabBarBarTintColor = kPOPNavigationBarBarTintColor; |
|
|
|
// UILabel |
|
NSString * const kPOPLabelTextColor = @"label.textColor"; |
|
|
|
#else |
|
|
|
// NSView |
|
NSString * const kPOPViewFrame = @"view.frame"; |
|
NSString * const kPOPViewBounds = @"view.bounds"; |
|
NSString * const kPOPViewAlphaValue = @"view.alphaValue"; |
|
NSString * const kPOPViewFrameRotation = @"view.frameRotation"; |
|
NSString * const kPOPViewFrameCenterRotation = @"view.frameCenterRotation"; |
|
NSString * const kPOPViewBoundsRotation = @"view.boundsRotation"; |
|
|
|
// NSWindow |
|
NSString * const kPOPWindowFrame = @"window.frame"; |
|
NSString * const kPOPWindowAlphaValue = @"window.alphaValue"; |
|
NSString * const kPOPWindowBackgroundColor = @"window.backgroundColor"; |
|
|
|
#endif |
|
|
|
#if SCENEKIT_SDK_AVAILABLE |
|
|
|
// SceneKit |
|
NSString * const kPOPSCNNodePosition = @"scnode.position"; |
|
NSString * const kPOPSCNNodePositionX = @"scnnode.position.x"; |
|
NSString * const kPOPSCNNodePositionY = @"scnnode.position.y"; |
|
NSString * const kPOPSCNNodePositionZ = @"scnnode.position.z"; |
|
NSString * const kPOPSCNNodeTranslation = @"scnnode.translation"; |
|
NSString * const kPOPSCNNodeTranslationX = @"scnnode.translation.x"; |
|
NSString * const kPOPSCNNodeTranslationY = @"scnnode.translation.y"; |
|
NSString * const kPOPSCNNodeTranslationZ = @"scnnode.translation.z"; |
|
NSString * const kPOPSCNNodeRotation = @"scnnode.rotation"; |
|
NSString * const kPOPSCNNodeRotationX = @"scnnode.rotation.x"; |
|
NSString * const kPOPSCNNodeRotationY = @"scnnode.rotation.y"; |
|
NSString * const kPOPSCNNodeRotationZ = @"scnnode.rotation.z"; |
|
NSString * const kPOPSCNNodeRotationW = @"scnnode.rotation.w"; |
|
NSString * const kPOPSCNNodeEulerAngles = @"scnnode.eulerAngles"; |
|
NSString * const kPOPSCNNodeEulerAnglesX = @"scnnode.eulerAngles.x"; |
|
NSString * const kPOPSCNNodeEulerAnglesY = @"scnnode.eulerAngles.y"; |
|
NSString * const kPOPSCNNodeEulerAnglesZ = @"scnnode.eulerAngles.z"; |
|
NSString * const kPOPSCNNodeOrientation = @"scnnode.orientation"; |
|
NSString * const kPOPSCNNodeOrientationX = @"scnnode.orientation.x"; |
|
NSString * const kPOPSCNNodeOrientationY = @"scnnode.orientation.y"; |
|
NSString * const kPOPSCNNodeOrientationZ = @"scnnode.orientation.z"; |
|
NSString * const kPOPSCNNodeOrientationW = @"scnnode.orientation.w"; |
|
NSString * const kPOPSCNNodeScale = @"scnnode.scale"; |
|
NSString * const kPOPSCNNodeScaleX = @"scnnode.scale.x"; |
|
NSString * const kPOPSCNNodeScaleY = @"scnnode.scale.y"; |
|
NSString * const kPOPSCNNodeScaleZ = @"scnnode.scale.z"; |
|
NSString * const kPOPSCNNodeScaleXY = @"scnnode.scale.xy"; |
|
|
|
#endif |
|
|
|
/** |
|
State structure internal to static animatable property. |
|
*/ |
|
typedef struct |
|
{ |
|
NSString *name; |
|
pop_animatable_read_block readBlock; |
|
pop_animatable_write_block writeBlock; |
|
CGFloat threshold; |
|
} _POPStaticAnimatablePropertyState; |
|
typedef _POPStaticAnimatablePropertyState POPStaticAnimatablePropertyState; |
|
|
|
static POPStaticAnimatablePropertyState _staticStates[] = |
|
{ |
|
/* CALayer */ |
|
|
|
{kPOPLayerBackgroundColor, |
|
^(CALayer *obj, CGFloat values[]) { |
|
POPCGColorGetRGBAComponents(obj.backgroundColor, values); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGColorRef color = POPCGColorRGBACreate(values); |
|
[obj setBackgroundColor:color]; |
|
CGColorRelease(color); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
{kPOPLayerBounds, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_rect(values, [obj bounds]); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setBounds:values_to_rect(values)]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerCornerRadius, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj cornerRadius]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setCornerRadius:values[0]]; |
|
}, |
|
kPOPThresholdRadius |
|
}, |
|
|
|
{kPOPLayerBorderWidth, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj borderWidth]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setBorderWidth:values[0]]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPLayerBorderColor, |
|
^(CALayer *obj, CGFloat values[]) { |
|
POPCGColorGetRGBAComponents(obj.borderColor, values); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGColorRef color = POPCGColorRGBACreate(values); |
|
[obj setBorderColor:color]; |
|
CGColorRelease(color); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
{kPOPLayerPosition, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_point(values, [(CALayer *)obj position]); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setPosition:values_to_point(values)]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerPositionX, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [(CALayer *)obj position].x; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGPoint p = [(CALayer *)obj position]; |
|
p.x = values[0]; |
|
[obj setPosition:p]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerPositionY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [(CALayer *)obj position].y; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGPoint p = [(CALayer *)obj position]; |
|
p.y = values[0]; |
|
[obj setPosition:p]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerOpacity, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj opacity]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setOpacity:((float)values[0])]; |
|
}, |
|
kPOPThresholdOpacity |
|
}, |
|
|
|
{kPOPLayerScaleX, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetScaleX(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetScaleX(obj, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPLayerScaleY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetScaleY(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetScaleY(obj, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPLayerScaleXY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_point(values, POPLayerGetScaleXY(obj)); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetScaleXY(obj, values_to_point(values)); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPLayerSubscaleXY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_point(values, POPLayerGetSubScaleXY(obj)); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetSubScaleXY(obj, values_to_point(values)); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPLayerTranslationX, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetTranslationX(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetTranslationX(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerTranslationY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetTranslationY(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetTranslationY(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerTranslationZ, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetTranslationZ(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetTranslationZ(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerTranslationXY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_point(values, POPLayerGetTranslationXY(obj)); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetTranslationXY(obj, values_to_point(values)); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerSubtranslationX, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetSubTranslationX(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetSubTranslationX(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerSubtranslationY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetSubTranslationY(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetSubTranslationY(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerSubtranslationZ, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetSubTranslationZ(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetSubTranslationZ(obj, values[0]); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerSubtranslationXY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_point(values, POPLayerGetSubTranslationXY(obj)); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetSubTranslationXY(obj, values_to_point(values)); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerZPosition, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj zPosition]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setZPosition:values[0]]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerSize, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_size(values, [obj bounds].size); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGSize size = values_to_size(values); |
|
if (size.width < 0. || size.height < 0.) |
|
return; |
|
|
|
CGRect b = [obj bounds]; |
|
b.size = size; |
|
[obj setBounds:b]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPLayerRotation, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetRotation(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetRotation(obj, values[0]); |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
{kPOPLayerRotationY, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetRotationY(obj); |
|
}, |
|
^(id obj, const CGFloat values[]) { |
|
POPLayerSetRotationY(obj, values[0]); |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
{kPOPLayerRotationX, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetRotationX(obj); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
POPLayerSetRotationX(obj, values[0]); |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
{kPOPLayerShadowColor, |
|
^(CALayer *obj, CGFloat values[]) { |
|
POPCGColorGetRGBAComponents(obj.shadowColor, values); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGColorRef color = POPCGColorRGBACreate(values); |
|
[obj setShadowColor:color]; |
|
CGColorRelease(color); |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPLayerShadowOffset, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values_from_size(values, [obj shadowOffset]); |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
CGSize size = values_to_size(values); |
|
[obj setShadowOffset:size]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPLayerShadowOpacity, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj shadowOpacity]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setShadowOpacity:values[0]]; |
|
}, |
|
kPOPThresholdOpacity |
|
}, |
|
|
|
{kPOPLayerShadowRadius, |
|
^(CALayer *obj, CGFloat values[]) { |
|
values[0] = [obj shadowRadius]; |
|
}, |
|
^(CALayer *obj, const CGFloat values[]) { |
|
[obj setShadowRadius:values[0]]; |
|
}, |
|
kPOPThresholdRadius |
|
}, |
|
|
|
/* CAShapeLayer */ |
|
|
|
{kPOPShapeLayerStrokeStart, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
values[0] = obj.strokeStart; |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
obj.strokeStart = values[0]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPShapeLayerStrokeEnd, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
values[0] = obj.strokeEnd; |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
obj.strokeEnd = values[0]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPShapeLayerStrokeColor, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
POPCGColorGetRGBAComponents(obj.strokeColor, values); |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
CGColorRef color = POPCGColorRGBACreate(values); |
|
[obj setStrokeColor:color]; |
|
CGColorRelease(color); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
{kPOPShapeLayerFillColor, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
POPCGColorGetRGBAComponents(obj.fillColor, values); |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
CGColorRef color = POPCGColorRGBACreate(values); |
|
[obj setFillColor:color]; |
|
CGColorRelease(color); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
{kPOPShapeLayerLineWidth, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
values[0] = obj.lineWidth; |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
obj.lineWidth = values[0]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPShapeLayerLineDashPhase, |
|
^(CAShapeLayer *obj, CGFloat values[]) { |
|
values[0] = obj.lineDashPhase; |
|
}, |
|
^(CAShapeLayer *obj, const CGFloat values[]) { |
|
obj.lineDashPhase = values[0]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
{kPOPLayoutConstraintConstant, |
|
^(NSLayoutConstraint *obj, CGFloat values[]) { |
|
values[0] = obj.constant; |
|
}, |
|
^(NSLayoutConstraint *obj, const CGFloat values[]) { |
|
obj.constant = values[0]; |
|
}, |
|
0.01 |
|
}, |
|
|
|
#if TARGET_OS_IPHONE |
|
|
|
/* UIView */ |
|
|
|
{kPOPViewAlpha, |
|
^(UIView *obj, CGFloat values[]) { |
|
values[0] = obj.alpha; |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
obj.alpha = values[0]; |
|
}, |
|
kPOPThresholdOpacity |
|
}, |
|
|
|
{kPOPViewBackgroundColor, |
|
^(UIView *obj, CGFloat values[]) { |
|
POPUIColorGetRGBAComponents(obj.backgroundColor, values); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
obj.backgroundColor = POPUIColorRGBACreate(values); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
{kPOPViewCenter, |
|
^(UIView *obj, CGFloat values[]) { |
|
values_from_point(values, obj.center); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
obj.center = values_to_point(values); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPViewFrame, |
|
^(UIView *obj, CGFloat values[]) { |
|
values_from_rect(values, obj.frame); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
obj.frame = values_to_rect(values); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPViewScaleX, |
|
^(UIView *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetScaleX(obj.layer); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
POPLayerSetScaleX(obj.layer, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPViewScaleY, |
|
^(UIView *obj, CGFloat values[]) { |
|
values[0] = POPLayerGetScaleY(obj.layer); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
POPLayerSetScaleY(obj.layer, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPViewScaleXY, |
|
^(UIView *obj, CGFloat values[]) { |
|
values_from_point(values, POPLayerGetScaleXY(obj.layer)); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
POPLayerSetScaleXY(obj.layer, values_to_point(values)); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPViewTintColor, |
|
^(UIView *obj, CGFloat values[]) { |
|
POPUIColorGetRGBAComponents(obj.tintColor, values); |
|
}, |
|
^(UIView *obj, const CGFloat values[]) { |
|
obj.tintColor = POPUIColorRGBACreate(values); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
/* UIScrollView */ |
|
|
|
{kPOPScrollViewContentOffset, |
|
^(UIScrollView *obj, CGFloat values[]) { |
|
values_from_point(values, obj.contentOffset); |
|
}, |
|
^(UIScrollView *obj, const CGFloat values[]) { |
|
[obj setContentOffset:values_to_point(values) animated:NO]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPScrollViewContentSize, |
|
^(UIScrollView *obj, CGFloat values[]) { |
|
values_from_size(values, obj.contentSize); |
|
}, |
|
^(UIScrollView *obj, const CGFloat values[]) { |
|
obj.contentSize = values_to_size(values); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPScrollViewZoomScale, |
|
^(UIScrollView *obj, CGFloat values[]) { |
|
values[0]=obj.zoomScale; |
|
}, |
|
^(UIScrollView *obj, const CGFloat values[]) { |
|
obj.zoomScale=values[0]; |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPScrollViewContentInset, |
|
^(UIScrollView *obj, CGFloat values[]) { |
|
values[0] = obj.contentInset.top; |
|
values[1] = obj.contentInset.left; |
|
values[2] = obj.contentInset.bottom; |
|
values[3] = obj.contentInset.right; |
|
}, |
|
^(UIScrollView *obj, const CGFloat values[]) { |
|
obj.contentInset = values_to_edge_insets(values); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPScrollViewScrollIndicatorInsets, |
|
^(UIScrollView *obj, CGFloat values[]) { |
|
values[0] = obj.scrollIndicatorInsets.top; |
|
values[1] = obj.scrollIndicatorInsets.left; |
|
values[2] = obj.scrollIndicatorInsets.bottom; |
|
values[3] = obj.scrollIndicatorInsets.right; |
|
}, |
|
^(UIScrollView *obj, const CGFloat values[]) { |
|
obj.scrollIndicatorInsets = values_to_edge_insets(values); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
/* UINavigationBar */ |
|
|
|
{kPOPNavigationBarBarTintColor, |
|
^(UINavigationBar *obj, CGFloat values[]) { |
|
POPUIColorGetRGBAComponents(obj.barTintColor, values); |
|
}, |
|
^(UINavigationBar *obj, const CGFloat values[]) { |
|
obj.barTintColor = POPUIColorRGBACreate(values); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
/* UILabel */ |
|
|
|
{kPOPLabelTextColor, |
|
^(UILabel *obj, CGFloat values[]) { |
|
POPUIColorGetRGBAComponents(obj.textColor, values); |
|
}, |
|
^(UILabel *obj, const CGFloat values[]) { |
|
obj.textColor = POPUIColorRGBACreate(values); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
#else |
|
|
|
/* NSView */ |
|
|
|
{kPOPViewFrame, |
|
^(NSView *obj, CGFloat values[]) { |
|
values_from_rect(values, NSRectToCGRect(obj.frame)); |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.frame = NSRectFromCGRect(values_to_rect(values)); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPViewBounds, |
|
^(NSView *obj, CGFloat values[]) { |
|
values_from_rect(values, NSRectToCGRect(obj.frame)); |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.bounds = NSRectFromCGRect(values_to_rect(values)); |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPViewAlphaValue, |
|
^(NSView *obj, CGFloat values[]) { |
|
values[0] = obj.alphaValue; |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.alphaValue = values[0]; |
|
}, |
|
kPOPThresholdOpacity |
|
}, |
|
|
|
{kPOPViewFrameRotation, |
|
^(NSView *obj, CGFloat values[]) { |
|
values[0] = obj.frameRotation; |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.frameRotation = values[0]; |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
{kPOPViewFrameCenterRotation, |
|
^(NSView *obj, CGFloat values[]) { |
|
values[0] = obj.frameCenterRotation; |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.frameCenterRotation = values[0]; |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
{kPOPViewBoundsRotation, |
|
^(NSView *obj, CGFloat values[]) { |
|
values[0] = obj.boundsRotation; |
|
}, |
|
^(NSView *obj, const CGFloat values[]) { |
|
obj.boundsRotation = values[0]; |
|
}, |
|
kPOPThresholdRotation |
|
}, |
|
|
|
/* NSWindow */ |
|
|
|
{kPOPWindowFrame, |
|
^(NSWindow *obj, CGFloat values[]) { |
|
values_from_rect(values, NSRectToCGRect(obj.frame)); |
|
}, |
|
^(NSWindow *obj, const CGFloat values[]) { |
|
[obj setFrame:NSRectFromCGRect(values_to_rect(values)) display:YES]; |
|
}, |
|
kPOPThresholdPoint |
|
}, |
|
|
|
{kPOPWindowAlphaValue, |
|
^(NSWindow *obj, CGFloat values[]) { |
|
values[0] = obj.alphaValue; |
|
}, |
|
^(NSWindow *obj, const CGFloat values[]) { |
|
obj.alphaValue = values[0]; |
|
}, |
|
kPOPThresholdOpacity |
|
}, |
|
|
|
{kPOPWindowBackgroundColor, |
|
^(NSWindow *obj, CGFloat values[]) { |
|
POPNSColorGetRGBAComponents(obj.backgroundColor, values); |
|
}, |
|
^(NSWindow *obj, const CGFloat values[]) { |
|
obj.backgroundColor = POPNSColorRGBACreate(values); |
|
}, |
|
kPOPThresholdColor |
|
}, |
|
|
|
#endif |
|
|
|
#if SCENEKIT_SDK_AVAILABLE |
|
|
|
/* SceneKit */ |
|
|
|
{kPOPSCNNodePosition, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values_from_vec3(values, obj.position); |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.position = values_to_vec3(values); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodePositionX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.position.x; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.position = SCNVector3Make(values[0], obj.position.y, obj.position.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodePositionY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.position.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.position = SCNVector3Make(obj.position.x, values[0], obj.position.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodePositionZ, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.position.z; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.position = SCNVector3Make(obj.position.x, obj.position.y, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeTranslation, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.transform.m41; |
|
values[1] = obj.transform.m42; |
|
values[2] = obj.transform.m43; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.transform = SCNMatrix4MakeTranslation(values[0], values[1], values[2]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeTranslationX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.transform.m41; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.transform = SCNMatrix4MakeTranslation(values[0], obj.transform.m42, obj.transform.m43); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeTranslationY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.transform.m42; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.transform = SCNMatrix4MakeTranslation(obj.transform.m41, values[0], obj.transform.m43); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeTranslationY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.transform.m43; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.transform = SCNMatrix4MakeTranslation(obj.transform.m41, obj.transform.m42, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeRotation, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values_from_vec4(values, obj.rotation); |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.rotation = values_to_vec4(values); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeRotationX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.rotation.x; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.rotation = SCNVector4Make(1.0, obj.rotation.y, obj.rotation.z, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeRotationY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.rotation.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.rotation = SCNVector4Make(obj.rotation.x, 1.0, obj.rotation.z, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeRotationZ, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.rotation.z; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.rotation = SCNVector4Make(obj.rotation.x, obj.rotation.y, 1.0, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeRotationW, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.rotation.w; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.rotation = SCNVector4Make(obj.rotation.x, obj.rotation.y, obj.rotation.z, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeEulerAngles, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values_from_vec3(values, obj.eulerAngles); |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.eulerAngles = values_to_vec3(values); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeEulerAnglesX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.eulerAngles.x; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.eulerAngles = SCNVector3Make(values[0], obj.eulerAngles.y, obj.eulerAngles.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeEulerAnglesY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.eulerAngles.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.eulerAngles = SCNVector3Make(obj.eulerAngles.x, values[0], obj.eulerAngles.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeEulerAnglesZ, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.eulerAngles.z; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.eulerAngles = SCNVector3Make(obj.eulerAngles.x, obj.eulerAngles.y, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeOrientation, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values_from_vec4(values, obj.orientation); |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.orientation = values_to_vec4(values); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeOrientationX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.orientation.x; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.orientation = SCNVector4Make(values[0], obj.orientation.y, obj.orientation.z, obj.orientation.w); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeOrientationY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.orientation.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.orientation = SCNVector4Make(obj.orientation.x, values[0], obj.orientation.z, obj.orientation.w); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeOrientationZ, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.orientation.z; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.orientation = SCNVector4Make(obj.orientation.x, obj.orientation.y, values[0], obj.orientation.w); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeOrientationW, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.orientation.w; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.orientation = SCNVector4Make(obj.orientation.x, obj.orientation.y, obj.orientation.z, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeScale, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values_from_vec3(values, obj.scale); |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.scale = values_to_vec3(values); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeScaleX, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.scale.x; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.scale = SCNVector3Make(values[0], obj.scale.y, obj.scale.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeScaleY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.scale.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.position = SCNVector3Make(obj.scale.x, values[0], obj.scale.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeScaleZ, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.scale.z; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.scale = SCNVector3Make(obj.scale.x, obj.scale.y, values[0]); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
{kPOPSCNNodeScaleXY, |
|
^(SCNNode *obj, CGFloat values[]) { |
|
values[0] = obj.scale.x; |
|
values[1] = obj.scale.y; |
|
}, |
|
^(SCNNode *obj, const CGFloat values[]) { |
|
obj.scale = SCNVector3Make(values[0], values[1], obj.scale.z); |
|
}, |
|
kPOPThresholdScale |
|
}, |
|
|
|
#endif |
|
|
|
}; |
|
|
|
static NSUInteger staticIndexWithName(NSString *aName) |
|
{ |
|
NSUInteger idx = 0; |
|
|
|
while (idx < POP_ARRAY_COUNT(_staticStates)) { |
|
if ([_staticStates[idx].name isEqualToString:aName]) |
|
return idx; |
|
idx++; |
|
} |
|
|
|
return NSNotFound; |
|
} |
|
|
|
/** |
|
Concrete static property class. |
|
*/ |
|
@interface POPStaticAnimatableProperty : POPAnimatableProperty |
|
{ |
|
@public |
|
POPStaticAnimatablePropertyState *_state; |
|
} |
|
@end |
|
|
|
@implementation POPStaticAnimatableProperty |
|
|
|
- (NSString *)name |
|
{ |
|
return _state->name; |
|
} |
|
|
|
- (pop_animatable_read_block)readBlock |
|
{ |
|
return _state->readBlock; |
|
} |
|
|
|
- (pop_animatable_write_block)writeBlock |
|
{ |
|
return _state->writeBlock; |
|
} |
|
|
|
- (CGFloat)threshold |
|
{ |
|
return _state->threshold; |
|
} |
|
|
|
@end |
|
|
|
#pragma mark - Concrete |
|
|
|
/** |
|
Concrete immutable property class. |
|
*/ |
|
@interface POPConcreteAnimatableProperty : POPAnimatableProperty |
|
- (instancetype)initWithName:(NSString *)name readBlock:(pop_animatable_read_block)read writeBlock:(pop_animatable_write_block)write threshold:(CGFloat)threshold; |
|
@end |
|
|
|
@implementation POPConcreteAnimatableProperty |
|
|
|
// default synthesis |
|
@synthesize name, readBlock, writeBlock, threshold; |
|
|
|
- (instancetype)initWithName:(NSString *)aName readBlock:(pop_animatable_read_block)aReadBlock writeBlock:(pop_animatable_write_block)aWriteBlock threshold:(CGFloat)aThreshold |
|
{ |
|
self = [super init]; |
|
if (nil != self) { |
|
name = [aName copy]; |
|
readBlock = [aReadBlock copy]; |
|
writeBlock = [aWriteBlock copy]; |
|
threshold = aThreshold; |
|
} |
|
return self; |
|
} |
|
@end |
|
|
|
#pragma mark - Mutable |
|
|
|
@implementation POPMutableAnimatableProperty |
|
|
|
// default synthesis |
|
@synthesize name, readBlock, writeBlock, threshold; |
|
|
|
@end |
|
|
|
#pragma mark - Cluster |
|
|
|
/** |
|
Singleton placeholder property class to support class cluster. |
|
*/ |
|
@interface POPPlaceholderAnimatableProperty : POPAnimatableProperty |
|
|
|
@end |
|
|
|
@implementation POPPlaceholderAnimatableProperty |
|
|
|
// default synthesis |
|
@synthesize name, readBlock, writeBlock, threshold; |
|
|
|
@end |
|
|
|
/** |
|
Cluster class. |
|
*/ |
|
@implementation POPAnimatableProperty |
|
|
|
// avoid creating backing ivars |
|
@dynamic name, readBlock, writeBlock, threshold; |
|
|
|
static POPAnimatableProperty *placeholder = nil; |
|
|
|
+ (void)initialize |
|
{ |
|
if (self == [POPAnimatableProperty class]) { |
|
placeholder = [POPPlaceholderAnimatableProperty alloc]; |
|
} |
|
} |
|
|
|
+ (id)allocWithZone:(struct _NSZone *)zone |
|
{ |
|
if (self == [POPAnimatableProperty class]) { |
|
if (nil == placeholder) { |
|
placeholder = [super allocWithZone:zone]; |
|
} |
|
return placeholder; |
|
} |
|
return [super allocWithZone:zone]; |
|
} |
|
|
|
- (id)copyWithZone:(NSZone *)zone |
|
{ |
|
if ([self isKindOfClass:[POPMutableAnimatableProperty class]]) { |
|
POPConcreteAnimatableProperty *copyProperty = [[POPConcreteAnimatableProperty alloc] initWithName:self.name readBlock:self.readBlock writeBlock:self.writeBlock threshold:self.threshold]; |
|
return copyProperty; |
|
} else { |
|
return self; |
|
} |
|
} |
|
|
|
- (id)mutableCopyWithZone:(NSZone *)zone |
|
{ |
|
POPMutableAnimatableProperty *copyProperty = [[POPMutableAnimatableProperty alloc] init]; |
|
copyProperty.name = self.name; |
|
copyProperty.readBlock = self.readBlock; |
|
copyProperty.writeBlock = self.writeBlock; |
|
copyProperty.threshold = self.threshold; |
|
return copyProperty; |
|
} |
|
|
|
+ (id)propertyWithName:(NSString *)aName |
|
{ |
|
return [self propertyWithName:aName initializer:NULL]; |
|
} |
|
|
|
+ (id)propertyWithName:(NSString *)aName initializer:(void (^)(POPMutableAnimatableProperty *prop))aBlock |
|
{ |
|
POPAnimatableProperty *prop = nil; |
|
|
|
static NSMutableDictionary *_propertyDict = nil; |
|
if (nil == _propertyDict) { |
|
_propertyDict = [[NSMutableDictionary alloc] initWithCapacity:10]; |
|
} |
|
|
|
prop = _propertyDict[aName]; |
|
if (nil != prop) { |
|
return prop; |
|
} |
|
|
|
NSUInteger staticIdx = staticIndexWithName(aName); |
|
|
|
if (NSNotFound != staticIdx) { |
|
POPStaticAnimatableProperty *staticProp = [[POPStaticAnimatableProperty alloc] init]; |
|
staticProp->_state = &_staticStates[staticIdx]; |
|
_propertyDict[aName] = staticProp; |
|
prop = staticProp; |
|
} else if (NULL != aBlock) { |
|
POPMutableAnimatableProperty *mutableProp = [[POPMutableAnimatableProperty alloc] init]; |
|
mutableProp.name = aName; |
|
mutableProp.threshold = 1.0; |
|
aBlock(mutableProp); |
|
prop = [mutableProp copy]; |
|
} |
|
|
|
return prop; |
|
} |
|
|
|
- (NSString *)description |
|
{ |
|
NSMutableString *s = [NSMutableString stringWithFormat:@"%@ name:%@ threshold:%f", super.description, self.name, self.threshold]; |
|
return s; |
|
} |
|
|
|
@end
|
|
|