LOTAnimatorNode.m 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. //
  2. // LOTAnimatorNode.m
  3. // Pods
  4. //
  5. // Created by brandon_withrow on 6/27/17.
  6. //
  7. //
  8. #import "LOTAnimatorNode.h"
  9. #import "LOTHelpers.h"
  10. #import "LOTValueInterpolator.h"
  11. NSInteger indentation_level = 0;
  12. @implementation LOTAnimatorNode
  13. - (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode *_Nullable)inputNode
  14. keyName:(NSString *_Nullable)keyname {
  15. self = [super init];
  16. if (self) {
  17. _keyname = keyname;
  18. _inputNode = inputNode;
  19. }
  20. return self;
  21. }
  22. /// To be overwritten by subclass. Defaults to YES
  23. - (BOOL)needsUpdateForFrame:(NSNumber *)frame {
  24. return YES;
  25. }
  26. /// 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
  27. - (BOOL)updateWithFrame:(NSNumber *_Nonnull)frame {
  28. return [self updateWithFrame:frame withModifierBlock:NULL forceLocalUpdate:NO];
  29. }
  30. - (BOOL)updateWithFrame:(NSNumber *_Nonnull)frame
  31. withModifierBlock:(void (^_Nullable)(LOTAnimatorNode * _Nonnull inputNode))modifier
  32. forceLocalUpdate:(BOOL)forceUpdate {
  33. if ([_currentFrame isEqual:frame] && !forceUpdate) {
  34. return NO;
  35. }
  36. if (ENABLE_DEBUG_LOGGING) [self logString:[NSString stringWithFormat:@"%lu %@ Checking for update", (unsigned long)self.hash, self.keyname]];
  37. BOOL localUpdate = [self needsUpdateForFrame:frame] || forceUpdate;
  38. if (localUpdate && ENABLE_DEBUG_LOGGING) {
  39. [self logString:[NSString stringWithFormat:@"%lu %@ Performing update", (unsigned long)self.hash, self.keyname]];
  40. }
  41. BOOL inputUpdated = [_inputNode updateWithFrame:frame
  42. withModifierBlock:modifier
  43. forceLocalUpdate:forceUpdate];
  44. _currentFrame = frame;
  45. if (localUpdate) {
  46. [self performLocalUpdate];
  47. if (modifier) {
  48. modifier(self);
  49. }
  50. }
  51. if (inputUpdated || localUpdate) {
  52. [self rebuildOutputs];
  53. }
  54. return (inputUpdated || localUpdate);
  55. }
  56. - (void)forceSetCurrentFrame:(NSNumber *_Nonnull)frame {
  57. _currentFrame = frame;
  58. }
  59. - (void)logString:(NSString *)string {
  60. NSMutableString *logString = [NSMutableString string];
  61. [logString appendString:@"|"];
  62. for (int i = 0; i < indentation_level; i ++) {
  63. [logString appendString:@" "];
  64. }
  65. [logString appendString:string];
  66. NSLog(@"%@ %@", NSStringFromClass([self class]), logString);
  67. }
  68. // TOBO BW Perf, make updates perform only when necessary. Currently everything in a node is updated
  69. /// Performs any local content update and updates self.localPath
  70. - (void)performLocalUpdate {
  71. self.localPath = [[LOTBezierPath alloc] init];
  72. }
  73. /// Rebuilds outputs by adding localPath to inputNodes output path.
  74. - (void)rebuildOutputs {
  75. if (self.inputNode) {
  76. self.outputPath = [self.inputNode.outputPath copy];
  77. [self.outputPath LOT_appendPath:self.localPath];
  78. } else {
  79. self.outputPath = self.localPath;
  80. }
  81. }
  82. - (void)setPathShouldCacheLengths:(BOOL)pathShouldCacheLengths {
  83. _pathShouldCacheLengths = pathShouldCacheLengths;
  84. self.inputNode.pathShouldCacheLengths = pathShouldCacheLengths;
  85. }
  86. - (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
  87. [self.inputNode searchNodesForKeypath:keypath];
  88. if ([keypath pushKey:self.keyname]) {
  89. // Matches self. Check interpolators
  90. if (keypath.endOfKeypath) {
  91. // Add self
  92. [keypath addSearchResultForCurrentPath:self];
  93. } else if (self.valueInterpolators[keypath.currentKey] != nil) {
  94. [keypath pushKey:keypath.currentKey];
  95. // We have a match!
  96. [keypath addSearchResultForCurrentPath:self];
  97. [keypath popKey];
  98. }
  99. [keypath popKey];
  100. }
  101. }
  102. - (void)setValueDelegate:(id<LOTValueDelegate> _Nonnull)delegate
  103. forKeypath:(LOTKeypath * _Nonnull)keypath {
  104. if ([keypath pushKey:self.keyname]) {
  105. // Matches self. Check interpolators
  106. LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
  107. if (interpolator) {
  108. // We have a match!
  109. [interpolator setValueDelegate:delegate];
  110. }
  111. [keypath popKey];
  112. }
  113. [self.inputNode setValueDelegate:delegate forKeypath:keypath];
  114. }
  115. @end