From 6b027d9cb6b0a8e75bf1d0ba24f050de5b244628 Mon Sep 17 00:00:00 2001 From: jerome Date: Wed, 18 Mar 2015 02:41:00 +0100 Subject: [PATCH] Added 'show', 'hide' and 'removeFromParent' methods to SPTween. Added new SPGroup class. Added 'isEmpty' property to SPJuggler --- sparrow/src/Classes/SPGroup.h | 70 +++++++++ sparrow/src/Classes/SPGroup.m | 133 ++++++++++++++++++ sparrow/src/Classes/SPJuggler.h | 3 + sparrow/src/Classes/SPJuggler.m | 5 + sparrow/src/Classes/SPTween.h | 9 ++ sparrow/src/Classes/SPTween.m | 35 +++++ sparrow/src/Classes/Sparrow.h | 1 + sparrow/src/Sparrow.xcodeproj/project.pbxproj | 8 ++ 8 files changed, 264 insertions(+) create mode 100644 sparrow/src/Classes/SPGroup.h create mode 100644 sparrow/src/Classes/SPGroup.m diff --git a/sparrow/src/Classes/SPGroup.h b/sparrow/src/Classes/SPGroup.h new file mode 100644 index 00000000..1b6c533e --- /dev/null +++ b/sparrow/src/Classes/SPGroup.h @@ -0,0 +1,70 @@ +// +// SPGroup.h +// Sparrow +// +// Created by Jérôme Cabanis on 17/03/2015. +// Copyright 2015 Lauraly. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the Simplified BSD License. +// + +#import +#import +#import + +/** ------------------------------------------------------------------------------------------------ + + The SPGroup takes objects that implement SPAnimatable (e.g. `SPTween`s) and executes them, just like + SPJuggler does but objects can be animated sequentially or in parallel. + + A SPGroup can be added to a SPJuggler or to an other SPGroup + + Furthermore, an object can request to be removed from the SPGroup by dispatching an + `SPEventTypeRemoveFromJuggler` event and SPGroup dispach `SPEventTypeRemoveFromJuggler` event. + + SPGroup provide block-based callbacks that are executed in certain phases of it's life time: + + - `onStart`: Invoked once when the group starts. + - `onUpdate`: Invoked every time it is advanced. + - `onComplete`: Invoked when all objects are completed. + + ------------------------------------------------------------------------------------------------- */ + + +@interface SPGroup : SPEventDispatcher + ++ (instancetype)parallelGroupWithObjects:(NSArray*)objects; ++ (instancetype)serialGroupWithObjects:(NSArray*)objects; + +/// Removes an object from the group. Use this function if the object does not dispatch `SPEventTypeRemoveFromJuggler` events +- (void)removeObject:(id)object; + +/// ---------------- +/// @name Properties +/// ---------------- + +/// The delay before the group is started. +@property (nonatomic, assign) double delay; + +/// The total life time of the group. +@property (nonatomic, readonly) double elapsedTime; + +/// The speed factor adjusts how fast the group's animatables run. +/// For example, a speed factor of 2.0 means the group runs twice as fast. +@property (nonatomic, assign) float speed; + +/// Indicates if the group execution is complete. +@property (nonatomic, readonly) BOOL isComplete; + +/// A block that will be called when the group starts (after a possible delay). +@property (nonatomic, copy) SPCallbackBlock onStart; + +/// A block that will be called each time the group is advanced. +@property (nonatomic, copy) SPCallbackBlock onUpdate; + +/// A block that will be called when the group execution is complete. +@property (nonatomic, copy) SPCallbackBlock onComplete; + + +@end diff --git a/sparrow/src/Classes/SPGroup.m b/sparrow/src/Classes/SPGroup.m new file mode 100644 index 00000000..28da1fd5 --- /dev/null +++ b/sparrow/src/Classes/SPGroup.m @@ -0,0 +1,133 @@ +// +// SPGroup.m +// Sparrow +// +// Created by Jérôme on 17/03/2015. +// +// + +#import + +@implementation SPGroup +{ + NSMutableOrderedSet *_objects; + BOOL _serial; + BOOL _started; + BOOL _finished; +} + +#pragma mark Initialization + +- (instancetype)initWithObjects:(NSArray*)objects serial:(BOOL)serial +{ + if ((self = [super init])) + { + _objects = [[NSMutableOrderedSet alloc] init]; + _serial = serial; + _elapsedTime = 0.0; + _speed = 1.0f; + _delay = 0; + _started = NO; + _finished = NO; + + for (id object in objects) + { + if([object conformsToProtocol:@protocol(SPAnimatable)] && ![_objects containsObject:object]) + { + [_objects addObject:object]; + if ([(id)object isKindOfClass:[SPEventDispatcher class]]) + [(SPEventDispatcher *)object addEventListener:@selector(onRemove:) atObject:self forType:SPEventTypeRemoveFromJuggler]; + } + } + } + return self; +} + +- (void)dealloc +{ + [_objects release]; + [super dealloc]; +} + ++ (instancetype)parallelGroupWithObjects:(NSArray*)objects +{ + return [[[SPGroup alloc] initWithObjects:objects serial:NO] autorelease]; +} + ++(instancetype)serialGroupWithObjects:(NSArray *)objects +{ + return [[[SPGroup alloc] initWithObjects:objects serial:YES] autorelease]; +} + +#pragma mark Methods + +- (void)onRemove:(SPEvent *)event +{ + [self removeObject:(id)[[event.target retain] autorelease]]; +} + +- (void)removeObject:(id)object +{ + if([_objects containsObject:object]) + { + [_objects removeObject:object]; + + if ([(id)object isKindOfClass:[SPEventDispatcher class]]) + [(SPEventDispatcher *)object removeEventListenersAtObject:self forType:SPEventTypeRemoveFromJuggler]; + } +} + + +#pragma mark SPAnimatable + +- (void)advanceTime:(double)seconds +{ + if(_isComplete) return; + + if (seconds < 0.0) + [NSException raise:SPExceptionInvalidOperation format:@"time must be positive"]; + + seconds *= _speed; + + if (seconds > 0.0) + { + _elapsedTime += seconds; + + if(_elapsedTime < _delay) + return; + + if(!_started) + { + _started = YES; + if (_onStart) _onStart(); + } + + if(_serial) + { + id object = [_objects firstObject]; + if(object) + [object advanceTime:seconds]; + } + else + { + // we need work with a copy, since user-code could modify the collection while enumerating + NSArray* objectsCopy = [[_objects array] copy]; + + for (id object in objectsCopy) + [object advanceTime:seconds]; + + [objectsCopy release]; + } + + if (_onUpdate) _onUpdate(); + + if([_objects count] == 0) + { + _isComplete = YES; + [self dispatchEventWithType:SPEventTypeRemoveFromJuggler]; + if (_onComplete) _onComplete(); + } + } +} + +@end diff --git a/sparrow/src/Classes/SPJuggler.h b/sparrow/src/Classes/SPJuggler.h index fe39f3bc..9535e4e7 100644 --- a/sparrow/src/Classes/SPJuggler.h +++ b/sparrow/src/Classes/SPJuggler.h @@ -103,4 +103,7 @@ /// For example, a speed factor of 2.0 means the juggler runs twice as fast. @property (nonatomic, assign) float speed; +/// Determines if the juggler is empty. +@property (nonatomic, readonly, getter=isEmpty) BOOL empty; + @end diff --git a/sparrow/src/Classes/SPJuggler.m b/sparrow/src/Classes/SPJuggler.m index b858e933..c42bc597 100644 --- a/sparrow/src/Classes/SPJuggler.m +++ b/sparrow/src/Classes/SPJuggler.m @@ -115,6 +115,11 @@ - (BOOL)containsObject:(id)object return [_objects containsObject:object]; } +-(BOOL)isEmpty +{ + return [_objects count] == 0; +} + - (id)delayInvocationAtTarget:(id)target byTime:(double)time { SPDelayedInvocation *delayedInv = [SPDelayedInvocation invocationWithTarget:target delay:time]; diff --git a/sparrow/src/Classes/SPTween.h b/sparrow/src/Classes/SPTween.h index 0c595126..8ab96fd9 100644 --- a/sparrow/src/Classes/SPTween.h +++ b/sparrow/src/Classes/SPTween.h @@ -87,6 +87,15 @@ /// Animates the `alpha` property. - (void)fadeTo:(float)alpha; +/// Show the target when the tween starts +- (void)show; + +/// Hide the target when the tween is complete +- (void)hide; + +/// Remove the target from his parent when the tween is complete +- (void)removeFromParent; + /// ---------------- /// @name Properties /// ---------------- diff --git a/sparrow/src/Classes/SPTween.m b/sparrow/src/Classes/SPTween.m index c81448ba..44d80429 100644 --- a/sparrow/src/Classes/SPTween.m +++ b/sparrow/src/Classes/SPTween.m @@ -17,6 +17,14 @@ typedef float (*FnPtrTransition) (id, SEL, float); +@protocol VisibleProtocol +-(void)setVisible:(BOOL)visible; +@end + +@protocol RemoveFromParentProtocol +- (void)removeFromParent; +@end + @implementation SPTween { id _target; @@ -32,6 +40,9 @@ @implementation SPTween double _repeatDelay; BOOL _reverse; int _currentCycle; + BOOL _show; + BOOL _hide; + BOOL _removeFromParent; SPCallbackBlock _onStart; SPCallbackBlock _onUpdate; @@ -54,6 +65,9 @@ - (instancetype)initWithTarget:(id)target time:(double)time transition:(NSString _repeatCount = 1; _currentCycle = -1; _reverse = NO; + _show = NO; + _hide = NO; + _removeFromParent = NO; // create function pointer for transition NSString *transMethod = [transition stringByAppendingString:TRANS_SUFFIX]; @@ -123,6 +137,21 @@ - (void)scaleTo:(float)scale [self animateProperty:@"scaleY" targetValue:scale]; } +-(void)show +{ + _show = YES; +} + +-(void)hide +{ + _hide = YES; +} + +-(void)removeFromParent +{ + _removeFromParent = YES; +} + #pragma mark SPAnimatable - (void)advanceTime:(double)time @@ -143,6 +172,8 @@ - (void)advanceTime:(double)time if (isStarting) { _currentCycle++; + if(_show && [_target respondsToSelector:@selector(setVisible:)]) + [(id)_target setVisible:YES]; if (_onStart) _onStart(); } @@ -172,6 +203,10 @@ - (void)advanceTime:(double)time } else { + if(_hide && [_target respondsToSelector:@selector(setVisible:)]) + [(id)_target setVisible:NO]; + if(_removeFromParent && [_target respondsToSelector:@selector(removeFromParent)]) + [(id)_target removeFromParent]; [self dispatchEventWithType:SPEventTypeRemoveFromJuggler]; if (_onComplete) _onComplete(); } diff --git a/sparrow/src/Classes/Sparrow.h b/sparrow/src/Classes/Sparrow.h index b47f0875..49dded15 100644 --- a/sparrow/src/Classes/Sparrow.h +++ b/sparrow/src/Classes/Sparrow.h @@ -35,6 +35,7 @@ #import #import #import +#import #import #import #import diff --git a/sparrow/src/Sparrow.xcodeproj/project.pbxproj b/sparrow/src/Sparrow.xcodeproj/project.pbxproj index a61d2967..af1b432b 100755 --- a/sparrow/src/Sparrow.xcodeproj/project.pbxproj +++ b/sparrow/src/Sparrow.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 02488C2A1AB8A12800912C73 /* SPGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 02488C281AB8A12800912C73 /* SPGroup.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 02488C2B1AB8A12800912C73 /* SPGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 02488C291AB8A12800912C73 /* SPGroup.m */; }; 872F5C3D1880C9E30016071B /* SPFragmentFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 872F5C3B1880C9E30016071B /* SPFragmentFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 872F5C3E1880C9E30016071B /* SPFragmentFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 872F5C3C1880C9E30016071B /* SPFragmentFilter.m */; }; 872F5C471880E2B50016071B /* SPBlurFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 872F5C451880E2B50016071B /* SPBlurFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -193,6 +195,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 02488C281AB8A12800912C73 /* SPGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPGroup.h; sourceTree = ""; }; + 02488C291AB8A12800912C73 /* SPGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPGroup.m; sourceTree = ""; }; 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28FD14FF0DC6FC520079059D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -687,6 +691,8 @@ DED859440FB883EE00D3D7D2 /* SPTransitions.m */, DE7044750FB62080007F5ECC /* SPTween.h */, DE7044760FB62080007F5ECC /* SPTween.m */, + 02488C281AB8A12800912C73 /* SPGroup.h */, + 02488C291AB8A12800912C73 /* SPGroup.m */, ); name = Animation; sourceTree = ""; @@ -806,6 +812,7 @@ DED29C0716DFB48E000C2BD7 /* SPEventListener.h in Headers */, 872F5C3D1880C9E30016071B /* SPFragmentFilter.h in Headers */, DE61138D134F8FA600AB742E /* SPGLTexture.h in Headers */, + 02488C2A1AB8A12800912C73 /* SPGroup.h in Headers */, DE611388134F8F8300AB742E /* SPImage.h in Headers */, DE611392134F8FBD00AB742E /* SPJuggler.h in Headers */, DE611396134F8FBD00AB742E /* SPMacros.h in Headers */, @@ -1039,6 +1046,7 @@ DE019C3A1026361200ECB0AC /* SPDelayedInvocation.m in Sources */, DE019C3B1026363D00ECB0AC /* SPNSExtensions.m in Sources */, 872F5C541880E57A0016071B /* SPColorMatrix.m in Sources */, + 02488C2B1AB8A12800912C73 /* SPGroup.m in Sources */, DE019C3C1026364800ECB0AC /* SPJuggler.m in Sources */, 872F5C501880E2DD0016071B /* SPDisplacementMapFilter.m in Sources */, 872F5C66188236D80016071B /* SPContext.m in Sources */,