diff --git a/CocoaSplit.xcodeproj/project.pbxproj b/CocoaSplit.xcodeproj/project.pbxproj index e3fa7848..4fc5488c 100644 --- a/CocoaSplit.xcodeproj/project.pbxproj +++ b/CocoaSplit.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 342346BB15F5FBD700C8C77E /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 342346BA15F5FBD700C8C77E /* CoreMedia.framework */; }; 342346BE15F6103D00C8C77E /* FFMpegTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 342346BD15F6103D00C8C77E /* FFMpegTask.m */; }; 342346CF15F9F07E00C8C77E /* CSAbstractCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 342346CE15F9F07E00C8C77E /* CSAbstractCaptureDevice.m */; }; + 3427864B1EA4337400877B7B /* CSTransitionAnimationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3427864A1EA4337400877B7B /* CSTransitionAnimationDelegate.m */; }; 342B33B3198073EC00492CB7 /* line.fgsh in Resources */ = {isa = PBXBuildFile; fileRef = 342B33B2198073EC00492CB7 /* line.fgsh */; }; 342B33B4198075F200492CB7 /* line.fgsh in CopyFiles */ = {isa = PBXBuildFile; fileRef = 342B33B2198073EC00492CB7 /* line.fgsh */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 342B33B61980771200492CB7 /* line.vtsh in Resources */ = {isa = PBXBuildFile; fileRef = 342B33B51980771200492CB7 /* line.vtsh */; }; @@ -703,6 +704,8 @@ 342346CC15F9D52000C8C77E /* CSCaptureSourceProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CSCaptureSourceProtocol.h; path = PluginHeaders/CSCaptureSourceProtocol.h; sourceTree = ""; }; 342346CD15F9F07E00C8C77E /* CSAbstractCaptureDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSAbstractCaptureDevice.h; path = PluginHeaders/CSAbstractCaptureDevice.h; sourceTree = ""; }; 342346CE15F9F07E00C8C77E /* CSAbstractCaptureDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSAbstractCaptureDevice.m; sourceTree = ""; }; + 342786491EA4337400877B7B /* CSTransitionAnimationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSTransitionAnimationDelegate.h; sourceTree = ""; }; + 3427864A1EA4337400877B7B /* CSTransitionAnimationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSTransitionAnimationDelegate.m; sourceTree = ""; }; 342B33B2198073EC00492CB7 /* line.fgsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = line.fgsh; path = Shaders/line.fgsh; sourceTree = ""; }; 342B33B51980771200492CB7 /* line.vtsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = line.vtsh; path = Shaders/line.vtsh; sourceTree = ""; }; 342F73F41A245316007AA99F /* CSPcmPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSPcmPlayer.h; path = PluginHeaders/CSPcmPlayer.h; sourceTree = ""; }; @@ -1363,6 +1366,8 @@ 34B5FAD31E74C34B0078FC51 /* CSSequenceItemLayout.m */, 34B5FAD51E75120C0078FC51 /* CSSequenceItemTransition.h */, 34B5FAD61E75120C0078FC51 /* CSSequenceItemTransition.m */, + 342786491EA4337400877B7B /* CSTransitionAnimationDelegate.h */, + 3427864A1EA4337400877B7B /* CSTransitionAnimationDelegate.m */, ); path = CocoaSplit; sourceTree = ""; @@ -2657,6 +2662,7 @@ 34B5FADD1E75BC910078FC51 /* CSLayoutSwitcherViewController.m in Sources */, 34ED8C851B07371C002C0674 /* MIKMIDIMetaTextEvent.m in Sources */, 34B5FACB1E7461E60078FC51 /* CSLayoutSequence.m in Sources */, + 3427864B1EA4337400877B7B /* CSTransitionAnimationDelegate.m in Sources */, 34348C2A19BDBDC000A122C2 /* PluginManagerWindowController.m in Sources */, 34CFE4A018F154DD00092C6A /* AVFChannelManager.m in Sources */, 34ED8C6B1B07371C002C0674 /* MIKMIDIMacDebugQuickLookSupport.m in Sources */, diff --git a/CocoaSplit.xcodeproj/project.xcworkspace/xcuserdata/zakk.xcuserdatad/UserInterfaceState.xcuserstate b/CocoaSplit.xcodeproj/project.xcworkspace/xcuserdata/zakk.xcuserdatad/UserInterfaceState.xcuserstate index b88760bb..78796efa 100644 Binary files a/CocoaSplit.xcodeproj/project.xcworkspace/xcuserdata/zakk.xcuserdatad/UserInterfaceState.xcuserstate and b/CocoaSplit.xcodeproj/project.xcworkspace/xcuserdata/zakk.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/CocoaSplit/CSAnimationRunner/CSAnimationBlock.py b/CocoaSplit/CSAnimationRunner/CSAnimationBlock.py index eb2f8677..d3e48002 100644 --- a/CocoaSplit/CSAnimationRunner/CSAnimationBlock.py +++ b/CocoaSplit/CSAnimationRunner/CSAnimationBlock.py @@ -55,7 +55,9 @@ class AnimationBlock: def add_waitmarker(self, duration=0, target=None, wait_only=None, **kwargs): - + if not self.current_begin_time: + self.current_begin_time = self.layout.rootLayer().convertTime_fromLayer_(CACurrentMediaTime(), None) + new_mark = CSAnimation(None, "__CS_WAIT_MARK", None, **kwargs) new_mark.isWaitMark = True new_mark.duration = duration @@ -85,6 +87,8 @@ class AnimationBlock: if animation.label: self.label_map[animation.label] = animation + NSLog("CURRENT BEGIN %f", self.current_begin_time) + a_duration = animation.apply(self.current_begin_time) self.latest_end_time = animation.end_time diff --git a/CocoaSplit/CSAnimationRunner/cocoasplit.py b/CocoaSplit/CSAnimationRunner/cocoasplit.py index 08244621..de27fdf8 100644 --- a/CocoaSplit/CSAnimationRunner/cocoasplit.py +++ b/CocoaSplit/CSAnimationRunner/cocoasplit.py @@ -110,33 +110,36 @@ def switchToLayout(name): layout = layoutByName(name) if layout: target_layout = getCurrentLayout() - target_layout.replaceWithSourceLayout_(layout) if (CSAnimationBlock.current_frame() and target_layout.transitionName() or target_layout.transitionFilter()) and target_layout.transitionDuration() > 0: dummy_animation = CSAnimation(None, None, None) dummy_animation.duration = target_layout.transitionDuration() CSAnimationBlock.current_frame().add_animation(dummy_animation, None, None) + target_layout.replaceWithSourceLayout_(layout) + def mergeLayout(name): layout = layoutByName(name) if layout: target_layout = getCurrentLayout() - target_layout.mergeSourceLayout_(layout) if (CSAnimationBlock.current_frame() and target_layout.transitionName() or target_layout.transitionFilter()) and target_layout.transitionDuration() > 0: dummy_animation = CSAnimation(None, None, None) dummy_animation.duration = target_layout.transitionDuration() CSAnimationBlock.current_frame().add_animation(dummy_animation, None, None) + target_layout.mergeSourceLayout_(layout) + def removeLayout(name): layout = layoutByName(name) if layout: target_layout = getCurrentLayout() - target_layout.removeSourceLayout_(layout) if (CSAnimationBlock.current_frame() and target_layout.transitionName() or target_layout.transitionFilter()) and target_layout.transitionDuration() > 0: dummy_animation = CSAnimation(None, None, None) dummy_animation.duration = target_layout.transitionDuration() CSAnimationBlock.current_frame().add_animation(dummy_animation, None, None) + target_layout.removeSourceLayout_(layout) + def inputByName(name): diff --git a/CocoaSplit/CSTransitionAnimationDelegate.h b/CocoaSplit/CSTransitionAnimationDelegate.h new file mode 100644 index 00000000..76faed61 --- /dev/null +++ b/CocoaSplit/CSTransitionAnimationDelegate.h @@ -0,0 +1,27 @@ +// +// CSTransitionAnimationDelegate.h +// CocoaSplit +// +// Created by Zakk on 4/16/17. +// Copyright © 2017 Zakk. All rights reserved. +// + +#import +#import +#import "SourceLayout.h" + +@interface CSTransitionAnimationDelegate : NSObject +@property (strong) NSArray *changedInputs; +@property (strong) NSArray *removedInputs; +@property (strong) NSArray *addedInputs; +@property (strong) NSArray *changeremoveInputs; + +@property (strong) CAAnimation *useAnimation; +@property (assign) bool fullScreen; + +@property (weak) SourceLayout *forLayout; + +-(void)animationDidStart:(CAAnimation *)anim; +-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag; + +@end diff --git a/CocoaSplit/CSTransitionAnimationDelegate.m b/CocoaSplit/CSTransitionAnimationDelegate.m new file mode 100644 index 00000000..254f3c07 --- /dev/null +++ b/CocoaSplit/CSTransitionAnimationDelegate.m @@ -0,0 +1,69 @@ +// +// CSTransitionAnimationDelegate.m +// CocoaSplit +// +// Created by Zakk on 4/16/17. +// Copyright © 2017 Zakk. All rights reserved. +// + +#import "CSTransitionAnimationDelegate.h" +#import "InputSource.h" + +@implementation CSTransitionAnimationDelegate + +-(void)animationDidStart:(CAAnimation *)anim +{ + NSLog(@"DELEGATE ANIMATION STARTED"); + + if (self.fullScreen) + { + [self.forLayout.rootLayer addAnimation:self.useAnimation forKey:nil]; + } + + for (InputSource *nSrc in self.addedInputs) + { + if (self.useAnimation && !self.fullScreen) + { + [nSrc.layer addAnimation:self.useAnimation forKey:nil]; + } + nSrc.layer.hidden = NO; + + } + + for (InputSource *cSrc in self.changedInputs) + { + if (self.useAnimation && !self.fullScreen) + { + [cSrc.layer addAnimation:self.useAnimation forKey:nil]; + } + cSrc.layer.hidden = NO; + + } + + for (InputSource *cSrc in self.changeremoveInputs) + { + if (self.useAnimation && !self.fullScreen) + { + [cSrc.layer addAnimation:self.useAnimation forKey:nil]; + } + cSrc.layer.hidden = YES; + + } + + for (InputSource *rSrc in self.removedInputs) + { + if (self.useAnimation && !self.fullScreen) + { + [rSrc.layer addAnimation:self.useAnimation forKey:nil]; + } + rSrc.layer.hidden = YES; + } + +} + + +-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag +{ + NSLog(@"DELEGATE ANIMATION STOPPED"); +} +@end diff --git a/CocoaSplit/SourceLayout.h b/CocoaSplit/SourceLayout.h index ced66ba9..2abcb264 100644 --- a/CocoaSplit/SourceLayout.h +++ b/CocoaSplit/SourceLayout.h @@ -25,6 +25,7 @@ GLuint _rFbo; dispatch_queue_t _animationQueue; NSMutableDictionary *_uuidMap; + NSMutableDictionary *_uuidMapPresentation; bool _noSceneTransactions; NSMutableArray *_topLevelSourceArray; bool _skipRefCounting; @@ -45,6 +46,8 @@ @property (strong) NSMutableArray *sourceList; +@property (strong) NSMutableArray *sourceListPresentation; + @property (readonly) NSArray *topLevelSourceList; @property (strong) NSData *savedSourceListData; diff --git a/CocoaSplit/SourceLayout.m b/CocoaSplit/SourceLayout.m index c28c00b0..95e83242 100644 --- a/CocoaSplit/SourceLayout.m +++ b/CocoaSplit/SourceLayout.m @@ -9,6 +9,7 @@ #import "SourceLayout.h" #import "InputSource.h" #import "CaptureController.h" +#import "CSTransitionAnimationDelegate.h" @implementation SourceLayout @@ -30,6 +31,8 @@ _fboTexture = 0; _rFbo = 0; _uuidMap = [NSMutableDictionary dictionary]; + _uuidMapPresentation = [NSMutableDictionary dictionary]; + _pendingScripts = [NSMutableDictionary dictionary]; @@ -42,6 +45,8 @@ //self.rootLayer.geometryFlipped = YES; _rootSize = NSMakeSize(_canvas_width, _canvas_height); self.sourceList = [NSMutableArray array]; + self.sourceListPresentation = [NSMutableArray array]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inputAttachEvent:) name:CSNotificationInputAttached object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inputAttachEvent:) name:CSNotificationInputDetached object:nil]; @@ -612,6 +617,8 @@ -(void)replaceWithSourceLayout:(SourceLayout *)layout withCompletionBlock:(void (^)(void))completionBlock { + + if (self.undoManager) { [self.undoManager beginUndoGrouping]; @@ -668,13 +675,34 @@ NSArray *sameInputs = diffResult[@"same"]; NSArray *newInputs = diffResult[@"new"]; + NSNumber *aStart = nil; + + id athing = [CATransaction valueForKey:@"__CS_BLOCK_OBJECT__"]; + if (athing) + { + aStart = [athing valueForKey:@"current_begin_time"]; + } CATransition *rTrans = nil; + CABasicAnimation *bTrans = nil; + + CSTransitionAnimationDelegate *transitionDelegate = [[CSTransitionAnimationDelegate alloc] init]; + transitionDelegate.addedInputs = newInputs; + transitionDelegate.changedInputs = changedInputs; + transitionDelegate.removedInputs = removedInputs; + if (self.transitionName || self.transitionFilter) { rTrans = [CATransition animation]; + + if (aStart) + { + [rTrans setBeginTime:aStart.floatValue]; + } + + rTrans.type = self.transitionName; rTrans.duration = self.transitionDuration; rTrans.removedOnCompletion = YES; @@ -683,14 +711,33 @@ { rTrans.filter = self.transitionFilter; } + + } + //We always create a dummy animation so we play nice with scripts that do additional animations. This way we don't do final remove/reveal until the proper time + NSString *dummyKey = [NSString stringWithFormat:@"__DUMMY_KEY_%f", aStart.floatValue]; + bTrans = [CABasicAnimation animationWithKeyPath:dummyKey]; + bTrans.removedOnCompletion = YES; + bTrans.fillMode = kCAFillModeForwards; + bTrans.beginTime = aStart.floatValue; + if (rTrans) + { + bTrans.duration = self.transitionDuration; + } + transitionDelegate.useAnimation = rTrans; + + bTrans.fromValue = @0; + bTrans.toValue = @1; + bTrans.delegate = transitionDelegate; + if (aStart) + { + bTrans.beginTime = aStart.floatValue; } - [CATransaction begin]; [CATransaction setCompletionBlock:^{ - + for (InputSource *rSrc in removedInputs) { [self deleteSource:rSrc]; @@ -709,58 +756,45 @@ completionBlock(); } }]; - - if (self.transitionFullScene) + + if (bTrans) { - if (rTrans) - { - [self.rootLayer addAnimation:rTrans forKey:kCATransition]; - } + transitionDelegate.forLayout = self; + transitionDelegate.fullScreen = self.transitionFullScene; + [self.rootLayer addAnimation:bTrans forKey:bTrans.keyPath]; } - + for (InputSource *rSrc in removedInputs) { - if (!self.transitionFullScene) - { - [rSrc.layer addAnimation:rTrans forKey:nil]; - } - rSrc.layer.hidden = YES; + [self deleteSourceFromPresentation:rSrc]; } for (InputSource *cSrc in changedInputs) { InputSource *mSrc = [self inputForUUID:cSrc.uuid]; - if (!self.transitionFullScene) - { - [mSrc.layer addAnimation:rTrans forKey:nil]; - } - + + [self deleteSourceFromPresentation:mSrc]; [changedRemove addObject:mSrc]; - if (!self.transitionFullScene) - { - cSrc.layer.hidden = YES; - } + cSrc.layer.hidden = YES; [self addSource:cSrc withParentLayer:mSrc.layer.superlayer]; - mSrc.layer.hidden = YES; + } + transitionDelegate.changeremoveInputs = changedRemove; for (InputSource *nSrc in newInputs) { - - if (!self.transitionFullScene) - { - nSrc.layer.hidden = YES; - } - + + nSrc.layer.hidden = YES; + [self addSource:nSrc]; - + } @@ -768,31 +802,8 @@ [CATransaction commit]; - - [CATransaction flush]; - if (!self.transitionFullScene) - { - dispatch_async(dispatch_get_main_queue(), ^{ - [CATransaction begin]; - for (InputSource *nSrc in newInputs) - { - - [nSrc.layer addAnimation:rTrans forKey:nil]; - nSrc.layer.hidden = NO; - } - - for (InputSource *cSrc in changedInputs) - { - [cSrc.layer addAnimation:rTrans forKey:nil]; - cSrc.layer.hidden = NO; - } - - - [CATransaction commit]; - }); - } - + [CATransaction flush]; _noSceneTransactions = NO; @@ -867,12 +878,34 @@ NSArray *removedInputs = diffResult[@"removed"]; NSArray *sameInputs = diffResult[@"same"]; NSArray *newInputs = diffResult[@"new"]; - + + NSNumber *aStart = nil; + + id athing = [CATransaction valueForKey:@"__CS_BLOCK_OBJECT__"]; + if (athing) + { + aStart = [athing valueForKey:@"current_begin_time"]; + } + + CATransition *rTrans = nil; + CABasicAnimation *bTrans = nil; + CSTransitionAnimationDelegate *transitionDelegate = [[CSTransitionAnimationDelegate alloc] init]; + transitionDelegate.addedInputs = newInputs; + transitionDelegate.changedInputs = changedInputs; + + if (self.transitionName || self.transitionFilter) { rTrans = [CATransition animation]; + + if (aStart) + { + [rTrans setBeginTime:aStart.floatValue]; + } + + rTrans.type = self.transitionName; rTrans.duration = self.transitionDuration; rTrans.removedOnCompletion = YES; @@ -881,9 +914,24 @@ { rTrans.filter = self.transitionFilter; } + } - + //We always create a dummy animation so we play nice with scripts that do additional animations. This way we don't do final remove/reveal until the proper time + NSString *dummyKey = [NSString stringWithFormat:@"__DUMMY_KEY_%f", aStart.floatValue]; + bTrans = [CABasicAnimation animationWithKeyPath:dummyKey]; + bTrans.removedOnCompletion = YES; + bTrans.fillMode = kCAFillModeForwards; + if (aStart) + { + bTrans.beginTime = aStart.floatValue; + } + bTrans.fromValue = @0; + bTrans.toValue = @1; + bTrans.duration = self.transitionDuration; + transitionDelegate.useAnimation = rTrans; + bTrans.delegate = transitionDelegate; + [CATransaction begin]; @@ -894,65 +942,65 @@ [self deleteSource:cSrc]; } - - if (completionBlock) + if (bTrans) { - completionBlock(); - } - }]; - - if (self.transitionFullScene) - { - [self.rootLayer addAnimation:rTrans forKey:nil]; - } - - for (InputSource *nSrc in newInputs) - { - if (!self.transitionFullScene) - { - nSrc.layer.hidden = YES; - } - - [self addSource:nSrc]; - } - - for (InputSource *cSrc in changedInputs) - { - InputSource *mSrc = [self inputForUUID:cSrc.uuid]; - [changedRemove addObject:mSrc]; - mSrc.layer.hidden = YES; - cSrc.layer.hidden = YES; - [self addSource:cSrc]; - [self incrementInputRef:cSrc]; - } - [CATransaction commit]; - [CATransaction flush]; - - if (!self.transitionFullScene) - { - - CABasicAnimation *hackAnim = [CABasicAnimation animationWithKeyPath:@"dummyKeyPath"]; - hackAnim.duration = rTrans.duration; - hackAnim.fromValue = @0; - hackAnim.toValue = @100; - hackAnim.removedOnCompletion = YES; - - [self.rootLayer addAnimation:hackAnim forKey:@"dummyKey"]; - - dispatch_async(dispatch_get_main_queue(), ^{ for (InputSource *nSrc in newInputs) { - [nSrc.layer addAnimation:rTrans forKey:nil]; nSrc.layer.hidden = NO; } for (InputSource *cSrc in changedInputs) { - [cSrc.layer addAnimation:rTrans forKey:nil]; cSrc.layer.hidden = NO; } - }); + + + + } + + + if (completionBlock) + { + completionBlock(); + } + + + }]; + + if (bTrans) + { + transitionDelegate.forLayout = self; + transitionDelegate.fullScreen = self.transitionFullScene; + + [self.rootLayer addAnimation:bTrans forKey:bTrans.keyPath]; } + + + for (InputSource *nSrc in newInputs) + { + + nSrc.layer.hidden = YES; + [self addSource:nSrc]; + + } + + for (InputSource *cSrc in changedInputs) + { + InputSource *mSrc = [self inputForUUID:cSrc.uuid]; + [self deleteSourceFromPresentation:mSrc]; + [changedRemove addObject:mSrc]; + + + cSrc.layer.hidden = YES; + + [self addSource:cSrc withParentLayer:mSrc.layer.superlayer]; + [self incrementInputRef:cSrc]; + } + transitionDelegate.changeremoveInputs = changedRemove; + + [CATransaction commit]; + [CATransaction flush]; + [self adjustAllInputs]; } @@ -993,6 +1041,8 @@ NSDictionary *diffResult = [self diffSourceListWithData:toRemove]; + NSMutableArray *realRemove = [NSMutableArray array]; + NSArray *changedInputs = diffResult[@"changed"]; NSArray *sameInputs = diffResult[@"same"]; NSArray *newInputs = diffResult[@"new"]; @@ -1000,12 +1050,31 @@ NSMutableArray *removeInputs = [NSMutableArray arrayWithArray:changedInputs]; [removeInputs addObjectsFromArray:sameInputs]; [removeInputs addObjectsFromArray:newInputs]; + NSNumber *aStart = nil; + + id athing = [CATransaction valueForKey:@"__CS_BLOCK_OBJECT__"]; + if (athing) + { + aStart = [athing valueForKey:@"current_begin_time"]; + } + CATransition *rTrans = nil; + CABasicAnimation *bTrans = nil; + + CSTransitionAnimationDelegate *transitionDelegate = [[CSTransitionAnimationDelegate alloc] init]; + if (self.transitionName || self.transitionFilter) { rTrans = [CATransition animation]; + + if (aStart) + { + [rTrans setBeginTime:aStart.floatValue]; + } + + rTrans.type = self.transitionName; rTrans.duration = self.transitionDuration; rTrans.removedOnCompletion = YES; @@ -1015,16 +1084,34 @@ rTrans.filter = self.transitionFilter; } } - + + + //We always create a dummy animation so we play nice with scripts that do additional animations. This way we don't do final remove/reveal until the proper time + NSString *dummyKey = [NSString stringWithFormat:@"__DUMMY_KEY_%f", aStart.floatValue]; + bTrans = [CABasicAnimation animationWithKeyPath:dummyKey]; + bTrans.removedOnCompletion = YES; + bTrans.fillMode = kCAFillModeForwards; + if (aStart) + { + bTrans.beginTime = aStart.floatValue; + } + bTrans.fromValue = @0; + bTrans.toValue = @1; + if (rTrans) + { + bTrans.duration = self.transitionDuration; + } + transitionDelegate.useAnimation = rTrans; + bTrans.delegate = transitionDelegate; + [CATransaction begin]; [CATransaction setCompletionBlock:^{ - for (InputSource *rSrc in removeInputs) + for (InputSource *rSrc in realRemove) { - InputSource *eSrc = [self inputForUUID:rSrc.uuid]; - [self decrementInputRef:eSrc]; - [self deleteSource:eSrc]; + [self decrementInputRef:rSrc]; + [self deleteSource:rSrc]; } if (completionBlock) @@ -1033,6 +1120,16 @@ } }]; + + if (bTrans) + { + transitionDelegate.forLayout = self; + transitionDelegate.fullScreen = self.transitionFullScene; + + [self.rootLayer addAnimation:bTrans forKey:bTrans.keyPath]; + } + + if (self.transitionFullScene) { [self.rootLayer addAnimation:rTrans forKey:nil]; @@ -1045,13 +1142,11 @@ if (eSrc) { - if (!self.transitionFullScene) - { - [eSrc.layer addAnimation:rTrans forKey:kCAOnOrderOut]; - } - eSrc.layer.hidden = YES; - + [realRemove addObject:eSrc]; + [self deleteSourceFromPresentation:eSrc]; } + + transitionDelegate.removedInputs = realRemove; } [CATransaction commit]; @@ -1135,6 +1230,9 @@ self.sourceList = [NSMutableArray array]; _uuidMap = [NSMutableDictionary dictionary]; + self.sourceListPresentation = [NSMutableArray array]; + _uuidMapPresentation = [NSMutableDictionary dictionary]; + if (!withData) @@ -1206,6 +1304,21 @@ +-(void)deleteSourceFromPresentation:(InputSource *)delSource +{ + @synchronized (self) { + [self.sourceListPresentation removeObject:delSource]; + } + + InputSource *uSrc; + + uSrc = _uuidMapPresentation[delSource.uuid]; + if ([uSrc isEqual:delSource]) + { + [_uuidMapPresentation removeObjectForKey:delSource.uuid]; + } + +} -(void)deleteSource:(InputSource *)delSource { @@ -1214,6 +1327,7 @@ [self willChangeValueForKey:@"topLevelSourceList"]; @synchronized (self) { [[self mutableArrayValueForKey:@"sourceList" ] removeObject:delSource]; + [self.sourceListPresentation removeObject:delSource]; } [self generateTopLevelSourceList]; [self didChangeValueForKey:@"topLevelSourceList"]; @@ -1226,6 +1340,12 @@ [_uuidMap removeObjectForKey:delSource.uuid]; } + uSrc = _uuidMapPresentation[delSource.uuid]; + if ([uSrc isEqual:delSource]) + { + [_uuidMapPresentation removeObjectForKey:delSource.uuid]; + } + //[self.sourceList removeObject:delSource]; if (delSource == self.layoutTimingSource) { @@ -1280,6 +1400,7 @@ newSource.sourceLayout = self; newSource.is_live = self.isActive; + [self.sourceListPresentation addObject:newSource]; [[self mutableArrayValueForKey:@"sourceList" ] addObject:newSource]; @@ -1290,7 +1411,7 @@ newSource.needsAdjustment = YES; - + [_uuidMapPresentation setObject:newSource forKey:newSource.uuid]; [_uuidMap setObject:newSource forKey:newSource.uuid]; [self incrementInputRef:newSource]; @@ -1308,11 +1429,13 @@ @synchronized(self) { [self.sourceList removeAllObjects]; + [self.sourceListPresentation removeAllObjects]; [self generateTopLevelSourceList]; } [_uuidMap removeAllObjects]; + [_uuidMapPresentation removeAllObjects]; } @@ -1503,7 +1626,10 @@ -(InputSource *)inputForName:(NSString *)name { - for (InputSource *tSrc in self.sourceList) + + NSArray *useList = self.sourceListPresentation; + + for (InputSource *tSrc in useList) { if (tSrc.name && [tSrc.name isEqualToString:name]) { @@ -1516,7 +1642,7 @@ -(InputSource *)inputForUUID:(NSString *)uuid { - return [_uuidMap objectForKey:uuid]; + return [_uuidMapPresentation objectForKey:uuid]; }