123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- //
- // LOTAnimatorNode.m
- // Pods
- //
- // Created by brandon_withrow on 6/27/17.
- //
- //
- #import "LOTAnimatorNode.h"
- #import "LOTHelpers.h"
- #import "LOTValueInterpolator.h"
- NSInteger indentation_level = 0;
- @implementation LOTAnimatorNode
- - (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode *_Nullable)inputNode
- keyName:(NSString *_Nullable)keyname {
- self = [super init];
- if (self) {
- _keyname = keyname;
- _inputNode = inputNode;
- }
- return self;
- }
- /// To be overwritten by subclass. Defaults to YES
- - (BOOL)needsUpdateForFrame:(NSNumber *)frame {
- return YES;
- }
- /// The node checks if local update or if upstream update required. If upstream update outputs are rebuilt. If local update local update is performed. Returns no if no action
- - (BOOL)updateWithFrame:(NSNumber *_Nonnull)frame {
- return [self updateWithFrame:frame withModifierBlock:NULL forceLocalUpdate:NO];
- }
- - (BOOL)updateWithFrame:(NSNumber *_Nonnull)frame
- withModifierBlock:(void (^_Nullable)(LOTAnimatorNode * _Nonnull inputNode))modifier
- forceLocalUpdate:(BOOL)forceUpdate {
- if ([_currentFrame isEqual:frame] && !forceUpdate) {
- return NO;
- }
- if (ENABLE_DEBUG_LOGGING) [self logString:[NSString stringWithFormat:@"%lu %@ Checking for update", (unsigned long)self.hash, self.keyname]];
- BOOL localUpdate = [self needsUpdateForFrame:frame] || forceUpdate;
- if (localUpdate && ENABLE_DEBUG_LOGGING) {
- [self logString:[NSString stringWithFormat:@"%lu %@ Performing update", (unsigned long)self.hash, self.keyname]];
- }
- BOOL inputUpdated = [_inputNode updateWithFrame:frame
- withModifierBlock:modifier
- forceLocalUpdate:forceUpdate];
- _currentFrame = frame;
- if (localUpdate) {
- [self performLocalUpdate];
- if (modifier) {
- modifier(self);
- }
- }
-
- if (inputUpdated || localUpdate) {
- [self rebuildOutputs];
- }
- return (inputUpdated || localUpdate);
- }
- - (void)forceSetCurrentFrame:(NSNumber *_Nonnull)frame {
- _currentFrame = frame;
- }
- - (void)logString:(NSString *)string {
- NSMutableString *logString = [NSMutableString string];
- [logString appendString:@"|"];
- for (int i = 0; i < indentation_level; i ++) {
- [logString appendString:@" "];
- }
- [logString appendString:string];
- NSLog(@"%@ %@", NSStringFromClass([self class]), logString);
- }
- // TOBO BW Perf, make updates perform only when necessary. Currently everything in a node is updated
- /// Performs any local content update and updates self.localPath
- - (void)performLocalUpdate {
- self.localPath = [[LOTBezierPath alloc] init];
- }
- /// Rebuilds outputs by adding localPath to inputNodes output path.
- - (void)rebuildOutputs {
- if (self.inputNode) {
- self.outputPath = [self.inputNode.outputPath copy];
- [self.outputPath LOT_appendPath:self.localPath];
- } else {
- self.outputPath = self.localPath;
- }
- }
- - (void)setPathShouldCacheLengths:(BOOL)pathShouldCacheLengths {
- _pathShouldCacheLengths = pathShouldCacheLengths;
- self.inputNode.pathShouldCacheLengths = pathShouldCacheLengths;
- }
- - (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
- [self.inputNode searchNodesForKeypath:keypath];
- if ([keypath pushKey:self.keyname]) {
- // Matches self. Check interpolators
- if (keypath.endOfKeypath) {
- // Add self
- [keypath addSearchResultForCurrentPath:self];
- } else if (self.valueInterpolators[keypath.currentKey] != nil) {
- [keypath pushKey:keypath.currentKey];
- // We have a match!
- [keypath addSearchResultForCurrentPath:self];
- [keypath popKey];
- }
- [keypath popKey];
- }
- }
- - (void)setValueDelegate:(id<LOTValueDelegate> _Nonnull)delegate
- forKeypath:(LOTKeypath * _Nonnull)keypath {
- if ([keypath pushKey:self.keyname]) {
- // Matches self. Check interpolators
- LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
- if (interpolator) {
- // We have a match!
- [interpolator setValueDelegate:delegate];
- }
- [keypath popKey];
- }
- [self.inputNode setValueDelegate:delegate forKeypath:keypath];
- }
- @end
|