mirror of
https://github.com/zakk4223/CocoaSplit.git
synced 2026-05-15 14:15:50 -06:00
Audio engine mixer nodes now dynamically allocate input busses as needed, and reuse ones from disconnected nodes.
622 lines
14 KiB
Objective-C
622 lines
14 KiB
Objective-C
//
|
|
// CSInputLayer.m
|
|
// CocoaSplit
|
|
//
|
|
// Created by Zakk on 1/6/15.
|
|
// Copyright (c) 2015 Zakk. All rights reserved.
|
|
//
|
|
|
|
#import "CSInputLayer.h"
|
|
#import "CSCaptureBase.h"
|
|
|
|
@implementation CSInputLayer
|
|
|
|
@dynamic animateDummy;
|
|
|
|
@synthesize sourceLayer = _sourceLayer;
|
|
@synthesize scrollXSpeed = _scrollXSpeed;
|
|
@synthesize scrollYSpeed = _scrollYSpeed;
|
|
@synthesize cropRect = _cropRect;
|
|
@synthesize startColor = _startColor;
|
|
@synthesize stopColor = _stopColor;
|
|
|
|
@dynamic fakeHeight;
|
|
@dynamic fakeWidth;
|
|
|
|
|
|
|
|
|
|
-(void)invalidateLayoutOfLayer:(CALayer *)layer
|
|
{
|
|
return [self.layoutManager invalidateLayoutOfLayer:layer];
|
|
}
|
|
|
|
-(void)layoutSublayersOfLayer:(CALayer *)layer
|
|
{
|
|
|
|
|
|
[self.layoutManager layoutSublayersOfLayer:layer];
|
|
|
|
if (layer == _xLayer)
|
|
{
|
|
for (CALayer *sLayer in _xLayer.sublayers)
|
|
{
|
|
CGSize newSize = [self preferredSizeOfLayer:sLayer];
|
|
CGRect bounds = sLayer.bounds;
|
|
bounds.size = newSize;
|
|
sLayer.bounds = bounds;
|
|
|
|
}
|
|
[self setupXAnimation:self.scrollXSpeed];
|
|
[self setupYAnimation:self.scrollYSpeed];
|
|
}
|
|
|
|
|
|
}
|
|
|
|
-(CGSize)preferredSizeOfLayer:(CALayer *)layer
|
|
{
|
|
|
|
CGSize retSize = [self.layoutManager preferredSizeOfLayer:layer];
|
|
|
|
if ([layer isKindOfClass:[CATextLayer class]])
|
|
{
|
|
NSAttributedString *lText = ((CATextLayer *)layer).string;
|
|
if (self.scrollXSpeed != 0)
|
|
{
|
|
|
|
if (lText.size.width > self.bounds.size.width)
|
|
{
|
|
retSize.width = lText.size.width;
|
|
} else {
|
|
retSize.width = self.bounds.size.width;
|
|
}
|
|
}
|
|
|
|
if (self.scrollYSpeed != 0)
|
|
{
|
|
if (lText.size.height > self.bounds.size.height)
|
|
{
|
|
retSize.height = lText.size.height;
|
|
} else {
|
|
retSize.height = self.bounds.size.height;
|
|
}
|
|
|
|
}
|
|
}
|
|
return retSize;
|
|
}
|
|
|
|
-(instancetype)initWithLayer:(id)layer
|
|
{
|
|
if (self = [super initWithLayer:layer])
|
|
{
|
|
|
|
self.fakeHeight = ((CALayer *)layer).bounds.size.height;
|
|
self.fakeWidth = ((CALayer *)layer).bounds.size.width;
|
|
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
+(BOOL)needsDisplayForKey:(NSString *)key
|
|
{
|
|
if ([@"fakeWidth" isEqualToString:key] || [@"fakeHeight" isEqualToString:key])
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
return [super needsDisplayForKey:key];
|
|
}
|
|
|
|
-(void)display
|
|
{
|
|
|
|
|
|
[self setValue:@([self.presentationLayer fakeWidth]) forKeyPath:@"bounds.size.width"];
|
|
[self setValue:@([self.presentationLayer fakeHeight]) forKeyPath:@"bounds.size.height"];
|
|
[super display];
|
|
|
|
|
|
}
|
|
|
|
|
|
-(void)clearGradient
|
|
{
|
|
_startColor = _stopColor = nil;
|
|
[self setupColors];
|
|
|
|
self.startColor = nil;
|
|
self.stopColor = nil;
|
|
}
|
|
|
|
|
|
-(void)setGradientStartX:(CGFloat)gradientStartX
|
|
{
|
|
|
|
CGPoint cBounds = self.startPoint;
|
|
cBounds.x = gradientStartX;
|
|
self.startPoint = cBounds;
|
|
}
|
|
|
|
-(CGFloat)gradientStartX
|
|
{
|
|
return self.startPoint.x;
|
|
}
|
|
|
|
|
|
-(void)setGradientStartY:(CGFloat)gradientStartY
|
|
{
|
|
|
|
CGPoint cBounds = self.startPoint;
|
|
cBounds.y = gradientStartY;
|
|
self.startPoint = cBounds;
|
|
}
|
|
|
|
|
|
|
|
-(CGFloat)gradientStartY
|
|
{
|
|
return self.startPoint.y;
|
|
}
|
|
|
|
-(void)setGradientStopX:(CGFloat)gradientStopX
|
|
{
|
|
CGPoint cBounds = self.endPoint;
|
|
cBounds.x = gradientStopX;
|
|
self.endPoint = cBounds;
|
|
}
|
|
|
|
-(CGFloat)gradientStopX
|
|
{
|
|
return self.endPoint.x;
|
|
}
|
|
|
|
-(void)setGradientStopY:(CGFloat)gradientStopY
|
|
{
|
|
CGPoint cBounds = self.endPoint;
|
|
cBounds.y = gradientStopY;
|
|
self.endPoint = cBounds;
|
|
}
|
|
|
|
-(CGFloat)gradientStopY
|
|
{
|
|
return self.endPoint.y;
|
|
}
|
|
|
|
|
|
-(void)setupColors
|
|
{
|
|
|
|
if (!self.startColor && !self.stopColor)
|
|
{
|
|
self.colors = nil;
|
|
return;
|
|
}
|
|
|
|
CGColorRef firstColor;
|
|
CGColorRef lastColor;
|
|
if (!self.startColor)
|
|
{
|
|
firstColor = CGColorCreateGenericRGB(0, 0, 0, 1);
|
|
} else {
|
|
firstColor = [self.startColor CGColor];
|
|
}
|
|
|
|
if (!self.stopColor)
|
|
{
|
|
lastColor = CGColorCreateGenericRGB(0, 0, 0, 1);
|
|
} else {
|
|
lastColor = [self.stopColor CGColor];
|
|
}
|
|
|
|
|
|
//CGColorRetain(firstColor);
|
|
// CGColorRetain(lastColor);
|
|
|
|
self.colors = [NSArray arrayWithObjects:CFBridgingRelease(firstColor),CFBridgingRelease(lastColor), nil];
|
|
|
|
}
|
|
|
|
-(void)setStartColor:(NSColor *)startColor
|
|
{
|
|
|
|
|
|
_startColor = startColor;
|
|
|
|
|
|
[self setupColors];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSColor *)startColor
|
|
{
|
|
return _startColor;
|
|
}
|
|
|
|
|
|
-(void)setStopColor:(NSColor *)stopColor
|
|
{
|
|
|
|
_stopColor = stopColor;
|
|
|
|
[self setupColors];
|
|
}
|
|
|
|
|
|
|
|
-(NSColor *)stopColor
|
|
{
|
|
return _stopColor;
|
|
}
|
|
|
|
|
|
-(void)frameTick
|
|
{
|
|
|
|
|
|
if (!_xLayer && !_yLayer)
|
|
{
|
|
_xLayer = [CAReplicatorLayer layer];
|
|
_yLayer = [CAReplicatorLayer layer];
|
|
_xLayer.instanceCount = 1;
|
|
_yLayer.instanceCount = 1;
|
|
_yLayer.layoutManager = self.layoutManager;
|
|
_sourceLayer.layoutManager = self.layoutManager;
|
|
[_xLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
|
|
[_xLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
|
|
[_xLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
|
|
[_xLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
|
|
|
|
|
|
[_yLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
|
|
[_yLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
|
|
[_yLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
|
|
[_yLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
|
|
|
|
[_sourceLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:@"superlayer" attribute:kCAConstraintMinX]];
|
|
[_sourceLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:@"superlayer" attribute:kCAConstraintMinY]];
|
|
[_sourceLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX relativeTo:@"superlayer" attribute:kCAConstraintMaxX]];
|
|
[_sourceLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:@"superlayer" attribute:kCAConstraintMaxY]];
|
|
_sourceLayer.actions = @{@"position": NSNull.null, @"bounds":NSNull.null, @"contentsRect":NSNull.null};
|
|
|
|
_xLayer.delegate = self;
|
|
_yLayer.delegate = self;
|
|
|
|
_xLayer.masksToBounds = NO;
|
|
_yLayer.masksToBounds = NO;
|
|
_yLayer.anchorPoint = CGPointMake(0.0, 0.0);
|
|
|
|
[_xLayer addSublayer:_sourceLayer];
|
|
[_yLayer addSublayer:_xLayer];
|
|
[self addSublayer:_yLayer];
|
|
}
|
|
}
|
|
|
|
|
|
-(instancetype)init
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
|
|
self.minificationFilter = kCAFilterTrilinear;
|
|
self.magnificationFilter = kCAFilterTrilinear;
|
|
self.disableAnimation = NO;
|
|
|
|
|
|
//self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
|
|
|
|
|
|
|
|
_cropRect = CGRectZero;
|
|
|
|
self.layoutManager = [CAConstraintLayoutManager layoutManager];
|
|
|
|
|
|
self.sourceLayer = [CALayer layer];
|
|
_sourceLayer.anchorPoint = CGPointMake(0.0, 0.0);
|
|
_sourceLayer.contentsGravity = kCAGravityResize;
|
|
_sourceLayer.frame = CGRectMake(0, 0, 1, 1);
|
|
_scrollAnimation = [CABasicAnimation animation];
|
|
_scrollAnimation.repeatCount = HUGE_VALF;
|
|
self.zPosition = 0;
|
|
|
|
|
|
|
|
|
|
self.masksToBounds = YES;
|
|
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
-(instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
{
|
|
if (self = [super initWithCoder:aDecoder])
|
|
{
|
|
self.sublayers = nil;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
-(void)setScrollXSpeed:(float)scrollXSpeed
|
|
{
|
|
_scrollXSpeed = scrollXSpeed;
|
|
[_xLayer setNeedsLayout];
|
|
|
|
if (scrollXSpeed == 0)
|
|
{
|
|
_xLayer.instanceCount = 1;
|
|
[_yLayer removeAnimationForKey:@"position.x"];
|
|
|
|
} else {
|
|
_xLayer.instanceCount = 2;
|
|
[self setupXAnimation:scrollXSpeed];
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
-(float)scrollXSpeed
|
|
{
|
|
return _scrollXSpeed;
|
|
}
|
|
|
|
-(void)setScrollYSpeed:(float)scrollYSpeed
|
|
{
|
|
if (scrollYSpeed == 0)
|
|
{
|
|
_yLayer.instanceCount = 1;
|
|
[_yLayer removeAnimationForKey:@"position.y"];
|
|
|
|
} else {
|
|
_yLayer.instanceCount = 2;
|
|
|
|
[self setupYAnimation:scrollYSpeed];
|
|
}
|
|
_scrollYSpeed = scrollYSpeed;
|
|
|
|
}
|
|
|
|
-(float)scrollYSpeed
|
|
{
|
|
return _scrollYSpeed;
|
|
}
|
|
|
|
|
|
-(void)setupYAnimation:(float)speed
|
|
{
|
|
if (speed == 0.0f)
|
|
{
|
|
return;
|
|
}
|
|
_scrollAnimation.keyPath = @"position.y";
|
|
|
|
if (speed > 0)
|
|
{
|
|
_scrollAnimation.fromValue = @0.0;
|
|
_scrollAnimation.toValue = [NSNumber numberWithFloat:-self.sourceLayer.bounds.size.height];
|
|
_yLayer.instanceTransform = CATransform3DMakeTranslation(0,self.sourceLayer.bounds.size.height, 0);
|
|
|
|
|
|
} else {
|
|
_scrollAnimation.fromValue = @0.0;
|
|
_scrollAnimation.toValue = [NSNumber numberWithFloat:self.sourceLayer.bounds.size.height];
|
|
_yLayer.instanceTransform = CATransform3DMakeTranslation(0,-self.sourceLayer.bounds.size.height, 0);
|
|
|
|
}
|
|
|
|
_scrollAnimation.duration = fabs(speed);
|
|
[_yLayer addAnimation:_scrollAnimation forKey:@"position.y"];
|
|
|
|
}
|
|
|
|
|
|
-(void)setupXAnimation:(float)speed
|
|
{
|
|
|
|
if (speed == 0.0f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_scrollAnimation.keyPath = @"position.x";
|
|
|
|
if (speed > 0)
|
|
{
|
|
_scrollAnimation.fromValue = @0.0;
|
|
_scrollAnimation.toValue = [NSNumber numberWithFloat:-self.sourceLayer.bounds.size.width];
|
|
|
|
_xLayer.instanceTransform = CATransform3DMakeTranslation(self.sourceLayer.bounds.size.width,0, 0);
|
|
|
|
|
|
|
|
} else {
|
|
_scrollAnimation.fromValue = @0.0;
|
|
_scrollAnimation.toValue = [NSNumber numberWithFloat:self.sourceLayer.bounds.size.width];
|
|
_xLayer.instanceTransform = CATransform3DMakeTranslation(-self.sourceLayer.bounds.size.width,0, 0);
|
|
|
|
}
|
|
|
|
_scrollAnimation.duration = fabs(speed);
|
|
[_yLayer addAnimation:_scrollAnimation forKey:@"position.x"];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)copySourceSettings:(CALayer *)toLayer
|
|
{
|
|
toLayer.anchorPoint = _sourceLayer.anchorPoint;
|
|
toLayer.filters = _sourceLayer.filters;
|
|
toLayer.contentsGravity = _sourceLayer.contentsGravity;
|
|
toLayer.contentsRect = _sourceLayer.contentsRect;
|
|
toLayer.autoresizingMask = _sourceLayer.autoresizingMask;
|
|
toLayer.constraints = _sourceLayer.constraints;
|
|
//toLayer.delegate = self;
|
|
toLayer.actions = @{@"position": NSNull.null, @"bounds":NSNull.null, @"contentsRect":NSNull.null};
|
|
|
|
}
|
|
|
|
|
|
-(void)transitionsDisabled
|
|
{
|
|
_yLayer.hidden = NO;
|
|
}
|
|
|
|
|
|
/*
|
|
-(void)setHidden:(BOOL)hidden
|
|
{
|
|
_yLayer.hidden = hidden;
|
|
}*/
|
|
|
|
|
|
-(void)transitionToLayer:(CALayer *)toLayer fromLayer:(CALayer *)fromLayer withTransition:(CATransition *)transition
|
|
{
|
|
[CATransaction begin];
|
|
CALayer *realTo = toLayer;
|
|
CALayer *realFrom = fromLayer;
|
|
|
|
if (toLayer == self)
|
|
{
|
|
realTo = _yLayer;
|
|
}
|
|
|
|
if (fromLayer == self)
|
|
{
|
|
realFrom = _yLayer;
|
|
}
|
|
|
|
|
|
[realTo addAnimation:transition forKey:nil];
|
|
[realFrom addAnimation:transition forKey:nil];
|
|
realFrom.hidden = YES;
|
|
realTo.hidden = NO;
|
|
[CATransaction commit];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(CALayer *)sourceLayer
|
|
{
|
|
return _sourceLayer;
|
|
}
|
|
|
|
|
|
-(void)setSourceLayer:(CALayer *)sourceLayer
|
|
{
|
|
[CATransaction begin];
|
|
|
|
if (_sourceLayer)
|
|
{
|
|
|
|
if (sourceLayer)
|
|
{
|
|
[self copySourceSettings:sourceLayer];
|
|
[_sourceLayer.superlayer replaceSublayer:_sourceLayer with:sourceLayer];
|
|
} else {
|
|
[_sourceLayer removeFromSuperlayer];
|
|
}
|
|
_sourceLayer.constraints = nil;
|
|
_sourceLayer.filters = nil;
|
|
_sourceLayer.backgroundFilters = nil;
|
|
}
|
|
|
|
|
|
|
|
_sourceLayer = sourceLayer;
|
|
|
|
[self setNeedsLayout];
|
|
if (_sourceLayer)
|
|
{
|
|
[_sourceLayer layoutIfNeeded];
|
|
}
|
|
|
|
|
|
[self setupXAnimation:_scrollXSpeed];
|
|
[self setupYAnimation:_scrollYSpeed];
|
|
[CATransaction commit];
|
|
}
|
|
|
|
|
|
|
|
|
|
//If the layout isn't forced weird stuff happens, I dunno.
|
|
|
|
-(void)setConstraints:(NSArray *)constraints
|
|
{
|
|
[super setConstraints:constraints];
|
|
[self setNeedsLayout];
|
|
[self layoutIfNeeded];
|
|
|
|
}
|
|
|
|
|
|
-(void)setCropRect:(CGRect)cropRect
|
|
{
|
|
self.contentsRect = cropRect;
|
|
self.sourceLayer.contentsRect = cropRect;
|
|
}
|
|
|
|
|
|
-(CGRect)cropRect
|
|
{
|
|
return self.sourceLayer.contentsRect;
|
|
}
|
|
|
|
/*
|
|
-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
|
|
{
|
|
return (id<CAAction>)[NSNull null];
|
|
}
|
|
*/
|
|
|
|
- (id<CAAction>)actionForKey:(NSString *)key
|
|
{
|
|
|
|
return nil;
|
|
}
|
|
|
|
-(BOOL)containsPoint:(CGPoint)p
|
|
{
|
|
if (self.hidden)
|
|
{
|
|
return NO;
|
|
} else {
|
|
return [super containsPoint:p];
|
|
}
|
|
}
|
|
|
|
|
|
- (CALayer *)hitTest:(CGPoint)hitPoint
|
|
{
|
|
|
|
CGPoint hitPointConv = [self convertPoint:hitPoint fromLayer:self.superlayer];
|
|
if ([self containsPoint:hitPointConv])
|
|
{
|
|
CALayer *hitLayer = [super hitTest:hitPoint];
|
|
if (hitLayer == self || hitLayer == _sourceLayer || hitLayer == _xLayer || hitLayer == _yLayer)
|
|
{
|
|
return self;
|
|
} else {
|
|
return hitLayer;
|
|
}
|
|
} else {
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@end
|