mirror of
https://github.com/zakk4223/CocoaSplit.git
synced 2026-05-15 06:05:49 -06:00
When a new audio device connects don't force add every device to the audio engine. Implement layout delete event in layout capture Various fixes for some multithread access issues
521 lines
16 KiB
Objective-C
521 lines
16 KiB
Objective-C
//
|
|
// InputPopupControllerViewController.m
|
|
// CocoaSplit
|
|
//
|
|
// Created by Zakk on 7/26/14.
|
|
//
|
|
|
|
#import "InputPopupControllerViewController.h"
|
|
#import "InputSource.h"
|
|
#import "CSCIFilterConfigProxy.h"
|
|
#import "CSFilterChooserWindowController.h"
|
|
#import "SourceLayout.h"
|
|
|
|
@interface InputPopupControllerViewController ()
|
|
|
|
@end
|
|
|
|
@implementation InputPopupControllerViewController
|
|
@synthesize inputSource = _inputSource;
|
|
|
|
|
|
|
|
-(instancetype) init
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
self = [super initWithNibName:@"InputPopupControllerViewController" bundle:nil];
|
|
self.inputConstraintMap = @{@"Left Edge": @(kCAConstraintMinX),
|
|
@"Right Edge": @(kCAConstraintMaxX),
|
|
@"Top Edge": @(kCAConstraintMaxY),
|
|
@"Bottom Edge": @(kCAConstraintMinY),
|
|
@"Horizontal Center": @(kCAConstraintMidX),
|
|
@"Vertical Center": @(kCAConstraintMidY),
|
|
@"Width": @(kCAConstraintWidth),
|
|
@"Height": @(kCAConstraintHeight),
|
|
};
|
|
|
|
|
|
self.constraintSortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"value" ascending:YES]];
|
|
self.availableTransitions = [NSMutableDictionary dictionary];
|
|
|
|
NSArray *caTransitionNames = @[kCATransitionFade, kCATransitionPush, kCATransitionMoveIn, kCATransitionReveal, @"cube", @"alignedCube", @"flip", @"alignedFlip"];
|
|
NSArray *ciTransitionNames = [CIFilter filterNamesInCategory:kCICategoryTransition];
|
|
|
|
for (NSString *caName in caTransitionNames)
|
|
{
|
|
[self.availableTransitions setObject:caName forKey:caName];
|
|
}
|
|
|
|
for (NSString *ciName in ciTransitionNames)
|
|
{
|
|
NSString *niceName = [CIFilter localizedNameForFilterName:ciName];
|
|
[self.availableTransitions setObject:niceName forKey:ciName];
|
|
}
|
|
|
|
self.compositionFilterNames = [CIFilter filterNamesInCategory:kCICategoryCompositeOperation];
|
|
|
|
self.scriptTypes = @[@"After Add", @"Before Delete", @"FrameTick", @"Before Merge", @"After Merge", @"Before Remove", @"Before Replace", @"After Replace"];
|
|
self.scriptKeys = @[@"selection.script_afterAdd", @"selection.script_beforeDelete", @"selection.script_frameTick", @"selection.script_beforeMerge", @"selection.script_afterMerge", @"selection.script_beforeRemove", @"selection.script_beforeReplace", @"selection.script_afterReplace"];
|
|
|
|
self.resizeFilters = @[kCAFilterLinear, kCAFilterNearest, kCAFilterTrilinear];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorWellActivate:) name:@"CSColorWellActivated" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorWellDeactivate:) name:@"CSColorWellDeactivated" object:nil];
|
|
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
|
|
-(void)awakeFromNib
|
|
{
|
|
if (self.inputobjctrl)
|
|
{
|
|
self.inputobjctrl.undoDelegate = self;
|
|
}
|
|
}
|
|
|
|
|
|
-(void)performUndoForKeyPath:(NSString *)keyPath usingValue:(id)usingValue
|
|
{
|
|
|
|
if (!self.undoManager)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!self.inputSource.sourceLayout)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NSString *propName = [[keyPath componentsSeparatedByString:@"."] lastObject];
|
|
|
|
[[self.undoManager prepareWithInvocationTarget:self.inputSource.sourceLayout] modifyUUID:self.inputSource.uuid withBlock:^(NSObject<CSInputSourceProtocol> *input) {
|
|
[input setValue:usingValue forKey:propName];
|
|
}];
|
|
|
|
NSString *actionName = [self.inputSource undoNameForKeyPath:propName usingValue:usingValue];
|
|
if (actionName)
|
|
{
|
|
[self.undoManager setActionName:actionName];
|
|
}
|
|
}
|
|
|
|
|
|
-(void)colorWellActivate:(NSNotification *)notification
|
|
{
|
|
NSColorWell *well = notification.object;
|
|
|
|
if (well.window != self.view.window)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NSDictionary *bindInfo = [well infoForBinding:@"value"];
|
|
NSString *keyPath = bindInfo[NSObservedKeyPathKey];
|
|
[self.inputobjctrl setValue:well.color forKeyPath:keyPath];
|
|
[self.inputobjctrl pauseUndoForKeyPath:keyPath];
|
|
}
|
|
|
|
|
|
-(void)colorWellDeactivate:(NSNotification *)notification
|
|
{
|
|
|
|
|
|
NSColorWell *well = notification.object;
|
|
|
|
if (well.window != self.view.window)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NSDictionary *bindInfo = [well infoForBinding:@"value"];
|
|
NSString *keyPath = bindInfo[NSObservedKeyPathKey];
|
|
[self.inputobjctrl resumeUndoForKeyPath:keyPath];
|
|
[self.inputobjctrl setValue:well.color forKeyPath:keyPath];
|
|
}
|
|
|
|
|
|
+(NSSet *)keyPathsForValuesAffectingSelectedVideoType
|
|
{
|
|
return [NSSet setWithObjects:@"inputSource", nil];
|
|
}
|
|
|
|
|
|
-(void)setInputSource:(InputSource *)inputSource
|
|
{
|
|
_inputSource = inputSource;
|
|
|
|
[self sourceConfigurationView];
|
|
self.backgroundFilterViewController.baseLayer = inputSource.layer;
|
|
self.backgroundFilterViewController.filterArrayName = @"backgroundFilters";
|
|
self.inputFilterViewController.baseLayer = inputSource.layer;
|
|
self.inputFilterViewController.filterArrayName = @"filters";
|
|
self.sourceFilterViewController.baseLayer = inputSource.layer.sourceLayer;
|
|
self.sourceFilterViewController.filterArrayName = @"filters";
|
|
}
|
|
|
|
-(InputSource *)inputSource
|
|
{
|
|
return _inputSource;
|
|
}
|
|
|
|
|
|
-(NSString *)selectedVideoType
|
|
{
|
|
|
|
return self.inputSource.selectedVideoType;
|
|
}
|
|
|
|
-(IBAction) configureInputTransition:(NSButton *)sender
|
|
{
|
|
if (self.inputSource.advancedTransition)
|
|
{
|
|
[self openTransitionFilterPanel:self.inputSource.advancedTransition];
|
|
}
|
|
}
|
|
|
|
- (IBAction)scriptSaveAll:(id)sender
|
|
{
|
|
[self.inputobjctrl commitEditing];
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)configureFilter:(NSSegmentedControl *)sender
|
|
{
|
|
CIFilter *selectedFilter;
|
|
CALayer *useLayer = nil;
|
|
|
|
NSString *filterType = @"filters";
|
|
|
|
if (sender.tag == 1)
|
|
{
|
|
selectedFilter = [self.inputSource.layer.backgroundFilters objectAtIndex:self.backgroundFilterTableView.selectedRow];
|
|
useLayer = self.inputSource.layer;
|
|
filterType = @"backgroundFilters";
|
|
} else if (sender.tag == 2) {
|
|
|
|
selectedFilter = [self.inputSource.layer.sourceLayer.filters objectAtIndex:self.sourceFilterTableView.selectedRow];
|
|
useLayer = self.inputSource.layer.sourceLayer;
|
|
} else if (sender.tag == 3) {
|
|
selectedFilter = [self.inputSource.layer.filters objectAtIndex:self.layerFilterTableView.selectedRow];
|
|
useLayer = self.inputSource.layer;
|
|
}
|
|
|
|
if (selectedFilter)
|
|
{
|
|
[self openUserFilterPanel:selectedFilter forLayer:useLayer withType:filterType];
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- (IBAction)removeFilter:(NSSegmentedControl *)sender
|
|
{
|
|
CIFilter *selectedFilter;
|
|
|
|
|
|
if (sender.tag == 1)
|
|
{
|
|
selectedFilter = [self.inputSource.layer.backgroundFilters objectAtIndex:self.backgroundFilterTableView.selectedRow];
|
|
[self.inputSource deleteBackgroundFilter:selectedFilter.name];
|
|
|
|
} else if (sender.tag == 2) {
|
|
|
|
selectedFilter = [self.inputSource.layer.sourceLayer.filters objectAtIndex:self.sourceFilterTableView.selectedRow];
|
|
[self.inputSource deleteSourceFilter:selectedFilter.name];
|
|
|
|
} else if (sender.tag == 3) {
|
|
selectedFilter = [self.inputSource.layer.filters objectAtIndex:self.layerFilterTableView.selectedRow];
|
|
[self.inputSource deleteLayerFilter:selectedFilter.name];
|
|
}
|
|
}
|
|
|
|
- (IBAction)filterControlAction:(NSSegmentedControl *)sender
|
|
{
|
|
NSInteger segment = sender.selectedSegment;
|
|
|
|
switch (segment)
|
|
{
|
|
case 0:
|
|
[self addFilterAction:sender];
|
|
break;
|
|
case 1:
|
|
[self removeFilter:sender];
|
|
break;
|
|
case 2:
|
|
[self configureFilter:sender];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
-(void)setSelectedVideoType:(NSString *)selectedVideoType
|
|
{
|
|
self.inputSource.selectedVideoType = selectedVideoType;
|
|
[self sourceConfigurationView];
|
|
}
|
|
|
|
|
|
-(void)sourceConfigurationView
|
|
{
|
|
|
|
self.inputConfigViewController = [self.inputSource sourceConfigurationView];
|
|
|
|
|
|
NSView *configView = self.inputConfigViewController.view;
|
|
self.view.hidden = NO;
|
|
|
|
|
|
NSArray *currentSubviews = self.sourceConfigView.subviews;
|
|
NSView *currentSubview = currentSubviews.firstObject;
|
|
|
|
|
|
if (!configView)
|
|
{
|
|
[currentSubview removeFromSuperview];
|
|
} else if (currentSubview) {
|
|
[[self.sourceConfigView animator] replaceSubview:currentSubview with:configView ];
|
|
[configView setFrameOrigin:NSMakePoint(configView.frame.origin.x, NSMaxY(self.sourceConfigView.frame) - configView.frame.size.height)];
|
|
|
|
} else {
|
|
[[self.sourceConfigView animator] addSubview:configView];
|
|
[configView setFrameOrigin:NSMakePoint(configView.frame.origin.x, NSMaxY(self.sourceConfigView.frame) - configView.frame.size.height)];
|
|
}
|
|
|
|
}
|
|
|
|
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
|
{
|
|
|
|
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
|
if (self) {
|
|
// Initialization code here.
|
|
}
|
|
return self;
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)popoverDidClose:(NSNotification *)notification
|
|
{
|
|
|
|
NSString *closeReason = [[notification userInfo] valueForKey:NSPopoverCloseReasonKey];
|
|
|
|
if (closeReason && closeReason == NSPopoverCloseReasonStandard)
|
|
{
|
|
// closeReason can be:
|
|
// NSPopoverCloseReasonStandard
|
|
// NSPopoverCloseReasonDetachToWindow
|
|
//
|
|
// add new code here if you want to respond "after" the popover closes
|
|
//
|
|
self.inputSource.editorController = nil;
|
|
}
|
|
|
|
[self.inputSource editorPopoverDidClose];
|
|
}
|
|
|
|
|
|
|
|
-(void)openUserFilterPanel:(CIFilter *)forFilter forLayer:(CALayer *)forLayer withType:(NSString *)withType
|
|
{
|
|
if (!forFilter)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CSCIFilterConfigProxy *filterProxy = [[CSCIFilterConfigProxy alloc] init];
|
|
|
|
|
|
filterProxy.baseLayer = forLayer;
|
|
filterProxy.layerFilterName = forFilter.name;
|
|
filterProxy.filterType = withType;
|
|
|
|
|
|
IKFilterUIView *filterView = [forFilter viewForUIConfiguration:@{IKUISizeFlavor:IKUISizeMini} excludedKeys:@[kCIInputImageKey, kCIInputTargetImageKey, kCIInputTimeKey]];
|
|
|
|
|
|
|
|
if (forLayer)
|
|
{
|
|
CSCIFilterConfigProxy *filterProxy = [[CSCIFilterConfigProxy alloc] init];
|
|
filterProxy.baseLayer = forLayer;
|
|
filterProxy.layerFilterName = forFilter.name;
|
|
filterProxy.filterType = withType;
|
|
|
|
[filterProxy rebindViewControls:filterView];
|
|
|
|
}
|
|
|
|
self.userFilterWindow = [[NSWindow alloc] init];
|
|
|
|
self.userFilterWindow.delegate = self;
|
|
[self.userFilterWindow setContentSize:filterView.bounds.size];
|
|
[self.userFilterWindow.contentView addSubview:filterView];
|
|
self.userFilterWindow.styleMask = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable;
|
|
[self.userFilterWindow setReleasedWhenClosed:NO];
|
|
|
|
[self.userFilterWindow makeKeyAndOrderFront:self.userFilterWindow];
|
|
|
|
}
|
|
|
|
- (IBAction)addFilterAction:(NSSegmentedControl *)sender
|
|
{
|
|
NSString *filterName = [CSFilterChooserWindowController run];
|
|
|
|
if (sender.tag == 1)
|
|
{
|
|
[self.inputSource addBackgroundFilter:filterName];
|
|
} else if (sender.tag == 2) {
|
|
[self.inputSource addSourceFilter:filterName];
|
|
} else if (sender.tag == 3) {
|
|
[self.inputSource addLayerFilter:filterName];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-(void)tableViewSelectionDidChange:(NSNotification *)notification
|
|
{
|
|
NSTableView *tableView = notification.object;
|
|
|
|
if (tableView == self.backgroundFilterTableView)
|
|
{
|
|
if (tableView.selectedRow > -1)
|
|
{
|
|
self.backgroundTableHasSelection = YES;
|
|
} else {
|
|
self.backgroundTableHasSelection = NO;
|
|
}
|
|
} else if (tableView == self.sourceFilterTableView) {
|
|
if (tableView.selectedRow > -1)
|
|
{
|
|
self.sourceTableHasSelection = YES;
|
|
} else {
|
|
self.sourceTableHasSelection = NO;
|
|
}
|
|
|
|
} else if (tableView == self.layerFilterTableView) {
|
|
if (tableView.selectedRow > -1)
|
|
{
|
|
self.layerTableHasSelection = YES;
|
|
} else {
|
|
self.layerTableHasSelection = NO;
|
|
}
|
|
} else if (tableView == self.scriptTableView) {
|
|
NSString *scriptKey = self.scriptKeys[tableView.selectedRow];
|
|
[self scriptSaveAll:nil];
|
|
[self.scriptTextView bind:@"value" toObject:self.inputobjctrl withKeyPath:scriptKey options:nil];
|
|
|
|
}
|
|
}
|
|
|
|
-(void)openTransitionFilterPanel:(CIFilter *)forFilter
|
|
{
|
|
if (!forFilter)
|
|
{
|
|
return;
|
|
}
|
|
|
|
IKFilterUIView *filterView = [forFilter viewForUIConfiguration:@{IKUISizeFlavor:IKUISizeMini} excludedKeys:@[kCIInputImageKey, kCIInputTargetImageKey, kCIInputTimeKey]];
|
|
|
|
|
|
self.transitionFilterWindow = [[NSWindow alloc] init];
|
|
self.transitionFilterWindow.delegate = self;
|
|
[self.transitionFilterWindow setContentSize:filterView.bounds.size];
|
|
[self.transitionFilterWindow.contentView addSubview:filterView];
|
|
|
|
self.transitionFilterWindow.styleMask = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable;
|
|
[self.transitionFilterWindow setReleasedWhenClosed:NO];
|
|
|
|
[self.transitionFilterWindow makeKeyAndOrderFront:self.transitionFilterWindow];
|
|
|
|
}
|
|
|
|
|
|
|
|
-(IBAction) clearGradient:(NSButton *)sender
|
|
{
|
|
|
|
[self.undoManager beginUndoGrouping];
|
|
self.inputSource.startColor = nil;
|
|
self.inputSource.stopColor = nil;
|
|
[self.undoManager setActionName:@"Clear Gradient"];
|
|
[self.undoManager endUndoGrouping];
|
|
}
|
|
|
|
|
|
-(void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem
|
|
{
|
|
[self scriptSaveAll:nil];
|
|
}
|
|
|
|
-(IBAction)scriptUndo:(NSButton *)sender
|
|
{
|
|
[self.inputobjctrl discardEditing];
|
|
}
|
|
|
|
|
|
- (IBAction)resetConstraints:(id)sender
|
|
{
|
|
NSMutableDictionary *oldConstraints = self.inputSource.constraintMap;
|
|
|
|
[[self.inputSource.sourceLayout.undoManager prepareWithInvocationTarget:self.inputSource.sourceLayout] modifyUUID:self.inputSource.uuid withBlock:^(NSObject<CSInputSourceProtocol> *input) {
|
|
|
|
((InputSource *)input).constraintMap = oldConstraints;
|
|
}];
|
|
|
|
|
|
[self.inputSource resetConstraints];
|
|
|
|
}
|
|
|
|
- (IBAction)deleteMultiSource:(id)sender
|
|
{
|
|
|
|
NSTableView *bTable = (NSTableView *)sender;
|
|
NSInteger deleteRow = [bTable clickedRow];
|
|
|
|
InputSource *toConfig = [self.multiSourceController.arrangedObjects objectAtIndex:deleteRow];
|
|
|
|
|
|
InputPopupControllerViewController *windowController = [[InputPopupControllerViewController alloc] init];
|
|
|
|
windowController.inputSource = toConfig;
|
|
NSWindow *configWindow = [[NSWindow alloc] init];
|
|
|
|
NSRect newFrame = [configWindow frameRectForContentRect:NSMakeRect(0.0f, 0.0f, windowController.view.frame.size.width, windowController.view.frame.size.height)];
|
|
|
|
[configWindow setFrame:newFrame display:NO];
|
|
|
|
[configWindow setReleasedWhenClosed:NO];
|
|
|
|
|
|
[configWindow.contentView addSubview:windowController.view];
|
|
configWindow.title = [NSString stringWithFormat:@"CocoaSplit Input (%@)", windowController.inputSource.name];
|
|
configWindow.delegate = windowController.inputSource;
|
|
|
|
configWindow.styleMask = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable;
|
|
|
|
windowController.inputSource.editorWindow = configWindow;
|
|
windowController.inputSource.editorController = windowController;
|
|
[configWindow makeKeyAndOrderFront:NSApp];
|
|
}
|
|
|
|
|
|
@end
|