diff --git a/RMBlurredView.h b/RMBlurredView.h new file mode 100644 index 0000000..2fbfa05 --- /dev/null +++ b/RMBlurredView.h @@ -0,0 +1,32 @@ +// +// RMBlurredView.h +// +// Created by Raffael Hannemann on 08.10.13. +// Copyright (c) 2013 Raffael Hannemann. All rights reserved. +// + +#import + +// Make sure to import QuartzCore and add it to your Linked Libraries of your target +#import + +@interface RMBlurredView : NSView { + // Keep a reference to the filters for later modification + CIFilter *_blurFilter, *_saturationFilter; + CALayer *_hostedLayer; +} + +/** The layer will be tinted using the tint color. By default it is a 70% White Color */ +@property (strong,nonatomic) NSColor *tintColor; + +/** To get more vibrant colors, a filter to increase the saturation of the colors can be applied. The default value is 2.5. */ +@property (assign,nonatomic) float saturationFactor; + +/** The blur radius defines the strength of the Gaussian Blur filter. The default value is 20.0. */ +@property (assign,nonatomic) float blurRadius; + +/** Use the following property names in the User Defined Runtime Attributes in Interface Builder to set up your RMBlurredView on the fly. Note: The color can be set up, too, using 'tintColor'. */ +@property (strong,nonatomic) NSNumber *saturationFactorNumber; +@property (strong,nonatomic) NSNumber *blurRadiusNumber; + +@end diff --git a/RMBlurredView.m b/RMBlurredView.m new file mode 100644 index 0000000..86e12e6 --- /dev/null +++ b/RMBlurredView.m @@ -0,0 +1,115 @@ +// +// RMBlurredView.m +// +// Created by Raffael Hannemann on 08.10.13. +// Copyright (c) 2013 Raffael Hannemann. All rights reserved. +// + +#import "RMBlurredView.h" + +#define kRMBlurredViewDefaultTintColor [NSColor colorWithCalibratedWhite:1.0 alpha:0.7] +#define kRMBlurredViewDefaultSaturationFactor 2.0 +#define kRMBlurredViewDefaultBlurRadius 20.0 + +@implementation RMBlurredView + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self setUp]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self setUp]; + } + return self; +} + +- (void) setTintColor:(NSColor *)tintColor { + _tintColor = tintColor; + + // Since we need a CGColor reference, store it for the drawing of the layer. + if (_tintColor) { + [self.layer setBackgroundColor:_tintColor.CGColor]; + } + + // Trigger a re-drawing of the layer + [self.layer setNeedsDisplay]; +} + +- (void) setBlurRadius:(float)blurRadius { + // Setting the blur radius requires a resetting of the filters + _blurRadius = blurRadius; + [self resetFilters]; +} + +- (void) setBlurRadiusNumber:(NSNumber *)blurRadiusNumber { + [self setBlurRadius:blurRadiusNumber.floatValue]; +} + +- (void) setSaturationFactor:(float)saturationFactor { + // Setting the saturation factor also requires a resetting of the filters + _saturationFactor = saturationFactor; + [self resetFilters]; +} + +- (void) setSaturationFactorNumber:(NSNumber *)saturationFactorNumber { + [self setSaturationFactor:saturationFactorNumber.floatValue]; +} + +- (void) setUp { + // Instantiate a new CALayer and set it as the NSView's layer (layer-hosting) + _hostedLayer = [CALayer layer]; + [self setWantsLayer:YES]; + [self setLayer:_hostedLayer]; + + // Set up the default parameters + _blurRadius = kRMBlurredViewDefaultBlurRadius; + _saturationFactor = kRMBlurredViewDefaultSaturationFactor; + [self setTintColor:kRMBlurredViewDefaultTintColor]; + + // It's important to set the layer to mask to its bounds, otherwise the whole parent view might get blurred + [self.layer setMasksToBounds:YES]; + + // To apply CIFilters on OS X 10.9, we need to set the property accordingly: + if ([self respondsToSelector:@selector(setLayerUsesCoreImageFilters:)]) { + BOOL flag = YES; + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(setLayerUsesCoreImageFilters:)]]; + [inv setSelector:@selector(setLayerUsesCoreImageFilters:)]; + [inv setArgument:&flag atIndex:2]; + [inv invokeWithTarget:self]; + } + + // Set the layer to redraw itself once it's size is changed + [self.layer setNeedsDisplayOnBoundsChange:YES]; + + // Initially create the filter instances + [self resetFilters]; +} + +- (void) resetFilters { + + // To get a higher color saturation, we create a ColorControls filter + _saturationFilter = [CIFilter filterWithName:@"CIColorControls"]; + [_saturationFilter setDefaults]; + [_saturationFilter setValue:[NSNumber numberWithFloat:_saturationFactor] forKey:@"inputSaturation"]; + + // Next, we create the blur filter + _blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; + [_blurFilter setDefaults]; + [_blurFilter setValue:[NSNumber numberWithFloat:_blurRadius] forKey:@"inputRadius"]; + + // Now we apply the two filters as the layer's background filters + [self.layer setBackgroundFilters:@[_saturationFilter, _blurFilter]]; + + // ... and trigger a refresh + [self.layer setNeedsDisplay]; +} + +@end diff --git a/Sweeper.xcodeproj/project.pbxproj b/Sweeper.xcodeproj/project.pbxproj index 5f958e6..93439b5 100644 --- a/Sweeper.xcodeproj/project.pbxproj +++ b/Sweeper.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 1907A37E1960B287006645DA /* RMBlurredView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1907A37D1960B287006645DA /* RMBlurredView.m */; }; + 1907A3801960B338006645DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1907A37F1960B338006645DA /* QuartzCore.framework */; }; 190953F31876BD0C00943549 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 190953F11876BD0C00943549 /* OCMock.framework */; }; 190953F61876BD6600943549 /* OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 190953F11876BD0C00943549 /* OCMock.framework */; }; 190953F81876BD9C00943549 /* OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 190953F11876BD0C00943549 /* OCMock.framework */; }; @@ -72,6 +74,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1907A37C1960B287006645DA /* RMBlurredView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMBlurredView.h; sourceTree = ""; }; + 1907A37D1960B287006645DA /* RMBlurredView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMBlurredView.m; sourceTree = ""; }; + 1907A37F1960B338006645DA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 190953F11876BD0C00943549 /* OCMock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OCMock.framework; path = Frameworks/OCMock.framework; sourceTree = ""; }; 19487F2B1876A9A2003B637B /* SWProcessedFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SWProcessedFile.h; path = Models/SWProcessedFile.h; sourceTree = ""; }; 19487F2C1876A9A2003B637B /* SWProcessedFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SWProcessedFile.m; path = Models/SWProcessedFile.m; sourceTree = ""; }; @@ -115,6 +120,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1907A3801960B338006645DA /* QuartzCore.framework in Frameworks */, 19B94DEB18ED0C7D00C7436F /* QuickLook.framework in Frameworks */, 19738E4E1875A6D900461F96 /* Cocoa.framework in Frameworks */, ); @@ -134,6 +140,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1907A3781960B23B006645DA /* RMBlurredView */ = { + isa = PBXGroup; + children = ( + 1907A37C1960B287006645DA /* RMBlurredView.h */, + 1907A37D1960B287006645DA /* RMBlurredView.m */, + ); + name = RMBlurredView; + sourceTree = ""; + }; 19738E411875A6D900461F96 = { isa = PBXGroup; children = ( @@ -156,6 +171,8 @@ 19738E4C1875A6D900461F96 /* Frameworks */ = { isa = PBXGroup; children = ( + 1907A37F1960B338006645DA /* QuartzCore.framework */, + 1907A3781960B23B006645DA /* RMBlurredView */, 19B94DEA18ED0C7D00C7436F /* QuickLook.framework */, 190953F11876BD0C00943549 /* OCMock.framework */, 19738E4D1875A6D900461F96 /* Cocoa.framework */, @@ -365,6 +382,7 @@ 19487F2D1876A9A2003B637B /* SWProcessedFile.m in Sources */, 19738E5A1875A6D900461F96 /* main.m in Sources */, 198D297D187BE7C2001DA802 /* SWDirectorySearchCellView.m in Sources */, + 1907A37E1960B287006645DA /* RMBlurredView.m in Sources */, 19ACB3BD1876540E00168B38 /* SWFileStackViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sweeper/Controllers/SWFileStackViewController.m b/Sweeper/Controllers/SWFileStackViewController.m index 288675f..fa7bb03 100644 --- a/Sweeper/Controllers/SWFileStackViewController.m +++ b/Sweeper/Controllers/SWFileStackViewController.m @@ -13,6 +13,7 @@ #import "SWAppDelegate.h" #import "SWDirectorySearchCellView.h" #import "NSURL+Sweeper.h" +#import "RMBlurredView.h" static CGFloat const SEARCHBAR_ANIMATION_DURATION = 0.3; @@ -44,6 +45,8 @@ @interface SWFileStackViewController () @property (nonatomic) BOOL initialized; @property (nonatomic, assign) NSUInteger selectedRowIndex; @property (nonatomic, retain) NSMutableArray *directoriesInUserHomeDirectory; +@property (nonatomic, strong) RMBlurredView *blurredFilterView; + - (NSString *)systemUserName; @end @@ -81,6 +84,7 @@ - (void)awakeFromNib { [directorySearchBar setEnabled:NO]; [fileTableView setAllowsTypeSelect:NO]; [fileTableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone]; + [self initBlurredFilterView]; #ifdef RELEASE [NSApp setServicesProvider:self]; NSUpdateDynamicServices(); @@ -218,6 +222,18 @@ - (void)initDataStorageWithPath:(NSString *)path { #endif } +- (void)initBlurredFilterView { + CGFloat width = self.bounds.size.width; + CGFloat height = self.bounds.size.height - [self.fileTableView rowHeight]; + CGFloat xPos = 0; + CGFloat yPos = 0; + self.blurredFilterView = [[RMBlurredView alloc] initWithFrame:CGRectMake(xPos, yPos, width, height)]; + [self.blurredFilterView setBlurRadius:5.0]; + [self.blurredFilterView setAlphaValue:0.0]; + [self setWantsLayer:YES]; + [self addSubview:self.blurredFilterView]; +} + /* Initialize the app using Services