From: Kent Sutherland Date: Sun, 5 Feb 2006 07:44:44 +0000 (+0000) Subject: Added a new core image ripple effect. X-Git-Tag: MenuTunes-1.7~5 X-Git-Url: http://git.ithinksw.org/ITKit.git/commitdiff_plain/4701dfd179c4ea4a898bc394ddbb138a1bc4f6b4 Added a new core image ripple effect. --- diff --git a/ITCoreImageView.h b/ITCoreImageView.h new file mode 100644 index 0000000..0b124aa --- /dev/null +++ b/ITCoreImageView.h @@ -0,0 +1,19 @@ +/* + * ITKit + * ITCoreImageView.h + * + * View subclass that provides the view for the masking window of a Core Image effect + * + * Copyright (c) 2006 by iThink Software. + * All Rights Reserved. + * + * $Id$ + * + */ + +#import + +@interface ITCoreImageView : NSView { +} + +@end diff --git a/ITCoreImageView.m b/ITCoreImageView.m new file mode 100644 index 0000000..1ba1044 --- /dev/null +++ b/ITCoreImageView.m @@ -0,0 +1,24 @@ +/* + * ITKit + * ITCoreImageView.m + * + * View subclass that provides the view for the masking window of a Core Image effect + * + * Copyright (c) 2006 by iThink Software. + * All Rights Reserved. + * + * $Id$ + * + */ + +#import "ITCoreImageView.h" + +@implementation ITCoreImageView + +-(void)drawRect:(NSRect)rect +{ + [[NSColor clearColor] set]; + NSRectFill(rect); +} + +@end diff --git a/ITCoreImageWindowEffect.h b/ITCoreImageWindowEffect.h new file mode 100644 index 0000000..043c4f4 --- /dev/null +++ b/ITCoreImageWindowEffect.h @@ -0,0 +1,41 @@ +/* + * ITKit + * ITCoreImageWindowEffect.h + * + * Effect subclass which performs a Core Image ripple effect on a window. + * + * Copyright (c) 2005 by iThink Software. + * All Rights Reserved. + * + * $Id$ + * + */ + +#import +#import +#import "ITCoreGraphicsHacks.h" +#import + +@interface CICGSFilter : NSObject +{ + void *_cid; + unsigned int _filter_id; +} + ++ (id)filterWithFilter:(CIFilter *)filter connectionID:(CGSConnectionID)cid; +- (id)initWithFilter:(CIFilter *)filter connectionID:(CGSConnectionID)cid; +- (void)dealloc; +- (void)setValue:(id)value forKey:(NSString *)key; +- (void)setValuesForKeysWithDictionary:(NSDictionary *)dict; +- (int)addToWindow:(CGSWindowID)windowID flags:(unsigned int)flags; +- (int)removeFromWindow:(CGSWindowID)windowID; +- (id)description; +@end + +@interface ITCoreImageWindowEffect : ITWindowEffect { + NSWindow *_effectWindow; + CIFilter *_effectFilter; + CICGSFilter *_windowFilter; +} + +@end \ No newline at end of file diff --git a/ITCoreImageWindowEffect.m b/ITCoreImageWindowEffect.m new file mode 100644 index 0000000..1c751af --- /dev/null +++ b/ITCoreImageWindowEffect.m @@ -0,0 +1,252 @@ +#import "ITCoreImageWindowEffect.h" +#import "ITTransientStatusWindow.h" +#import "ITCoreGraphicsHacks.h" +#import "ITCoreImageView.h" + +@interface ITCoreImageWindowEffect (Private) +- (void)performAppearFromProgress:(float)progress effectTime:(float)time; +- (void)appearStep; +- (void)appearFinish; +- (void)performVanishFromProgress:(float)progress effectTime:(float)time; +- (void)vanishStep; +- (void)vanishFinish; + +- (void)setupEffect; +@end + +@implementation ITCoreImageWindowEffect + ++ (NSString *)effectName +{ + return @"Core Image - Ripple"; +} + ++ (NSDictionary *)supportedPositions +{ + return [NSDictionary dictionaryWithObjectsAndKeys: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], @"Left", + [NSNumber numberWithBool:YES], @"Center", + [NSNumber numberWithBool:YES], @"Right", nil] , @"Top" , + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], @"Left", + [NSNumber numberWithBool:YES], @"Center", + [NSNumber numberWithBool:YES], @"Right", nil] , @"Middle" , + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], @"Left", + [NSNumber numberWithBool:YES], @"Center", + [NSNumber numberWithBool:YES], @"Right", nil] , @"Bottom" , nil]; +} + ++ (unsigned int)listOrder +{ + return 800; +} + +/*************************************************************************/ +#pragma mark - +#pragma mark APPEAR METHODS +/*************************************************************************/ + +- (void)performAppear +{ + __idle = NO; + + [self setWindowVisibility:ITWindowAppearingState]; + [self performAppearFromProgress:0.0 effectTime:_effectTime]; +} + +- (void)performAppearFromProgress:(float)progress effectTime:(float)time +{ + [_window setEffectProgress:progress]; + _effectSpeed = (1.0 / (EFFECT_FPS * time)); + + if ( progress == 0.0 ) { + [_window setAlphaValue:0.0]; + } + + [_window orderFront:self]; + + _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS) + target:self + selector:@selector(appearStep) + userInfo:nil + repeats:YES]; + [self setupEffect]; +} + +- (void)appearStep +{ + float interFade = 0.0; + [_window setEffectProgress:([_window effectProgress] + _effectSpeed)]; + [_window setEffectProgress:( ([_window effectProgress] < 1.0) ? [_window effectProgress] : 1.0)]; + interFade = (( sin(([_window effectProgress] * pi) - (pi / 2)) + 1 ) / 2); + [_window setAlphaValue:interFade]; + + if ( [_window effectProgress] >= 1.0 ) { + [self appearFinish]; + } +} + +- (void)appearFinish +{ + [_effectTimer invalidate]; + _effectTimer = nil; + + [self setWindowVisibility:ITWindowVisibleState]; + + __idle = YES; + if ( __shouldReleaseWhenIdle ) { + [self release]; + } +} + +- (void)cancelAppear +{ + [self setWindowVisibility:ITWindowVanishingState]; + + [_effectTimer invalidate]; + _effectTimer = nil; + + [self performVanishFromProgress:[_window effectProgress] effectTime:(_effectTime / 3.5)]; +} + + +/*************************************************************************/ +#pragma mark - +#pragma mark VANISH METHODS +/*************************************************************************/ + +- (void)performVanish +{ + __idle = NO; + + [self setWindowVisibility:ITWindowVanishingState]; + [self performVanishFromProgress:1.0 effectTime:_effectTime]; +} + +- (void)performVanishFromProgress:(float)progress effectTime:(float)time +{ + [_window setEffectProgress:progress]; + _effectSpeed = (1.0 / (EFFECT_FPS * time)); + if ( progress == 1.0 ) { + [_window setAlphaValue:1.0]; + } + + [_window orderFront:self]; + + _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS) + target:self + selector:@selector(vanishStep) + userInfo:nil + repeats:YES]; + [self setupEffect]; +} + +- (void)vanishStep +{ + float interFade = 1.0; + [_window setEffectProgress:([_window effectProgress] - _effectSpeed)]; + [_window setEffectProgress:( ([_window effectProgress] > 0.0) ? [_window effectProgress] : 0.0)]; + interFade = (( sin(([_window effectProgress] * pi) - (pi / 2)) + 1 ) / 2); + [_window setAlphaValue:interFade]; + + if ( [_window effectProgress] <= 0.0 ) { + [self vanishFinish]; + } +} + +- (void)vanishFinish +{ + [_effectTimer invalidate]; + _effectTimer = nil; + [_window orderOut:self]; + [_window setAlphaValue:1.0]; + + [self setWindowVisibility:ITWindowHiddenState]; + + __idle = YES; + + if ( __shouldReleaseWhenIdle ) { + [self release]; + } +} + +- (void)cancelVanish +{ + [self setWindowVisibility:ITWindowVanishingState]; + + [_effectTimer invalidate]; + _effectTimer = nil; + + [self performAppearFromProgress:[_window effectProgress] effectTime:(_effectTime / 3.5)]; +} + +/*************************************************************************/ +#pragma mark - +#pragma mark CORE IMAGE METHODS +/*************************************************************************/ + +- (void)setupEffect +{ + NSRect rippleRect = [_window frame]; + NSRect screenRect = [[_window screen] frame]; + + rippleRect.origin.y = - (NSMaxY(rippleRect) - screenRect.size.height); + + _effectWindow = [[NSWindow alloc] initWithContentRect:NSInsetRect([_window frame], -200, -200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [_effectWindow setBackgroundColor:[NSColor clearColor]]; + [_effectWindow setAlphaValue:1.0]; + [_effectWindow setOpaque:NO]; + [_effectWindow setHasShadow:NO]; + [_effectWindow setContentView:[[ITCoreImageView alloc] initWithFrame:[_window frame]]]; + [_effectWindow setLevel:[_window level]]; + + [_effectWindow orderFrontRegardless]; + [_window orderWindow:NSWindowAbove relativeTo:[_effectWindow windowNumber]]; + + _effectFilter = [[CIFilter filterWithName:@"CIShapedWaterRipple"] retain]; + [_effectFilter setDefaults]; + [_effectFilter setValue:[NSNumber numberWithFloat:50.0] forKey:@"inputCornerRadius"]; + [_effectFilter setValue:[CIVector vectorWithX:rippleRect.origin.x Y:rippleRect.origin.y] forKey:@"inputPoint0"]; + [_effectFilter setValue:[CIVector vectorWithX:(rippleRect.origin.x + rippleRect.size.width) Y:(rippleRect.origin.y + rippleRect.size.height)] forKey:@"inputPoint1"]; + [_effectFilter setValue:[NSNumber numberWithFloat:0.0] forKey:@"inputPhase"]; + + _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain]; + [_windowFilter addToWindow:(CGSWindowID)[_effectWindow windowNumber] flags:1]; + + [NSThread detachNewThreadSelector:@selector(runFilterAnimation:) toTarget:self withObject:self]; +} + +- (void)runFilterAnimation:(id)sender +{ + NSAutoreleasePool *pool; + CICGSFilter *oldFilter; + CFAbsoluteTime startTime, time; + CGSWindowID windowNumber = (CGSWindowID)[_effectWindow windowNumber]; + + pool = [[NSAutoreleasePool alloc] init]; + + startTime = CFAbsoluteTimeGetCurrent(); + time = CFAbsoluteTimeGetCurrent(); + + while (time < (startTime + 2.5) && (time >= startTime)) { + oldFilter = _windowFilter; + [_effectFilter setValue:[NSNumber numberWithFloat:160*(time - startTime)] forKey:@"inputPhase"]; + _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain]; + [_windowFilter addToWindow:windowNumber flags:1]; + [oldFilter removeFromWindow:windowNumber]; + [oldFilter release]; + time = CFAbsoluteTimeGetCurrent(); + } + + [_windowFilter removeFromWindow:windowNumber]; + [_windowFilter release]; + [_effectFilter release]; + [_effectWindow orderOut:self]; + [[_effectWindow contentView] release]; + [_effectWindow release]; + [pool release]; +} + +@end diff --git a/ITKit.xcodeproj/project.pbxproj b/ITKit.xcodeproj/project.pbxproj index 6688930..e14c010 100644 --- a/ITKit.xcodeproj/project.pbxproj +++ b/ITKit.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 2AC83142056D00F700A7D7E2 /* ITImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AC83140056D00F700A7D7E2 /* ITImageView.m */; }; 2AC8319D056D037700A7D7E2 /* ITImageCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AC8319B056D037700A7D7E2 /* ITImageCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2AC8319E056D037700A7D7E2 /* ITImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AC8319C056D037700A7D7E2 /* ITImageCell.m */; }; + 370C98540995CC7E008C3200 /* ITCoreImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 370C98520995CC7E008C3200 /* ITCoreImageView.h */; }; + 370C98550995CC7E008C3200 /* ITCoreImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 370C98530995CC7E008C3200 /* ITCoreImageView.m */; }; 3710912305C0821000ED0F36 /* ITIconAndTextStatusWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 3710911A05C07F6D00ED0F36 /* ITIconAndTextStatusWindow.m */; }; 3710912805C0825900ED0F36 /* ITIconAndTextStatusWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 3710911905C07F6D00ED0F36 /* ITIconAndTextStatusWindow.h */; settings = {ATTRIBUTES = (Public, ); }; }; 372C5814068FE72F00CEF54A /* ITZoomWindowEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 372C5812068FE72F00CEF54A /* ITZoomWindowEffect.m */; }; @@ -29,6 +31,9 @@ 37B7F6750754F87A0089C005 /* ITSplashWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 37B7F66E0754F87A0089C005 /* ITSplashWindow.m */; }; 37B7F6760754F87A0089C005 /* ITSplashScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 37B7F66F0754F87A0089C005 /* ITSplashScreen.m */; }; 37B7F6780754F87A0089C005 /* ITSplashScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 37B7F6710754F87A0089C005 /* ITSplashScreen.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 37FA493F094DE2650078A329 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37FA493E094DE2650078A329 /* QuartzCore.framework */; }; + 37FA494D094DE28B0078A329 /* ITCoreImageWindowEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 37FA494B094DE28B0078A329 /* ITCoreImageWindowEffect.h */; }; + 37FA494E094DE28B0078A329 /* ITCoreImageWindowEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 37FA494C094DE28B0078A329 /* ITCoreImageWindowEffect.m */; }; 7C02300B08A8488B00DDBD03 /* ITAboutWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C02300908A8488B00DDBD03 /* ITAboutWindowController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7C02300C08A8488B00DDBD03 /* ITAboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C02300A08A8488B00DDBD03 /* ITAboutWindowController.m */; }; 7C02301D08A84A1E00DDBD03 /* ITAboutWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 7C02301B08A84A1E00DDBD03 /* ITAboutWindow.nib */; }; @@ -199,6 +204,8 @@ 2AC8319B056D037700A7D7E2 /* ITImageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITImageCell.h; sourceTree = ""; }; 2AC8319C056D037700A7D7E2 /* ITImageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ITImageCell.m; sourceTree = ""; }; 32DBCF5E0370ADEE00C91783 /* ITKit_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITKit_Prefix.pch; sourceTree = ""; }; + 370C98520995CC7E008C3200 /* ITCoreImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITCoreImageView.h; sourceTree = ""; }; + 370C98530995CC7E008C3200 /* ITCoreImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ITCoreImageView.m; sourceTree = ""; }; 3710911905C07F6D00ED0F36 /* ITIconAndTextStatusWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITIconAndTextStatusWindow.h; sourceTree = ""; }; 3710911A05C07F6D00ED0F36 /* ITIconAndTextStatusWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ITIconAndTextStatusWindow.m; sourceTree = ""; }; 372C5812068FE72F00CEF54A /* ITZoomWindowEffect.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ITZoomWindowEffect.m; sourceTree = ""; }; @@ -213,6 +220,9 @@ 37B7F66E0754F87A0089C005 /* ITSplashWindow.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ITSplashWindow.m; sourceTree = ""; }; 37B7F66F0754F87A0089C005 /* ITSplashScreen.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ITSplashScreen.m; sourceTree = ""; }; 37B7F6710754F87A0089C005 /* ITSplashScreen.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ITSplashScreen.h; sourceTree = ""; }; + 37FA493E094DE2650078A329 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = ""; }; + 37FA494B094DE28B0078A329 /* ITCoreImageWindowEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITCoreImageWindowEffect.h; sourceTree = ""; }; + 37FA494C094DE28B0078A329 /* ITCoreImageWindowEffect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ITCoreImageWindowEffect.m; sourceTree = ""; }; 7C02300908A8488B00DDBD03 /* ITAboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITAboutWindowController.h; sourceTree = ""; }; 7C02300A08A8488B00DDBD03 /* ITAboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ITAboutWindowController.m; sourceTree = ""; }; 7C02301C08A84A1E00DDBD03 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ITAboutWindow.nib; sourceTree = SOURCE_ROOT; }; @@ -319,6 +329,7 @@ 7CC84BE1054F6CA2001DC704 /* ApplicationServices.framework in Frameworks */, 7CC84BE5054F6CAA001DC704 /* Carbon.framework in Frameworks */, 7C105BDC07D787C0002DE061 /* ITFoundation.framework in Frameworks */, + 37FA493F094DE2650078A329 /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,6 +403,7 @@ 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( + 37FA493E094DE2650078A329 /* QuartzCore.framework */, 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */, 7CC84BE4054F6CAA001DC704 /* Carbon.framework */, 7CC84BE0054F6CA2001DC704 /* ApplicationServices.framework */, @@ -563,6 +575,10 @@ 37B3906A06923D1200E828B9 /* ITSpinWindowEffect.m */, 3747E3F806950A0D001ACA46 /* ITSpinAndZoomWindowEffect.h */, 3747E3F906950A0D001ACA46 /* ITSpinAndZoomWindowEffect.m */, + 37FA494B094DE28B0078A329 /* ITCoreImageWindowEffect.h */, + 37FA494C094DE28B0078A329 /* ITCoreImageWindowEffect.m */, + 370C98520995CC7E008C3200 /* ITCoreImageView.h */, + 370C98530995CC7E008C3200 /* ITCoreImageView.m */, ); name = ITWindowEffects; sourceTree = ""; @@ -797,6 +813,8 @@ 37B7F6780754F87A0089C005 /* ITSplashScreen.h in Headers */, 7CEA43CA07D77F1600CACD9D /* ITLoginItem.h in Headers */, 7C02300B08A8488B00DDBD03 /* ITAboutWindowController.h in Headers */, + 37FA494D094DE28B0078A329 /* ITCoreImageWindowEffect.h in Headers */, + 370C98540995CC7E008C3200 /* ITCoreImageView.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1044,6 +1062,8 @@ 37B7F6760754F87A0089C005 /* ITSplashScreen.m in Sources */, 7CEA43CB07D77F1600CACD9D /* ITLoginItem.m in Sources */, 7C02300C08A8488B00DDBD03 /* ITAboutWindowController.m in Sources */, + 37FA494E094DE28B0078A329 /* ITCoreImageWindowEffect.m in Sources */, + 370C98550995CC7E008C3200 /* ITCoreImageView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1169,6 +1189,7 @@ 0x19000000, ); PRODUCT_NAME = ITKit; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", @@ -1207,6 +1228,7 @@ 0x19000000, ); PRODUCT_NAME = ITKit; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", @@ -1243,6 +1265,7 @@ 0x19000000, ); PRODUCT_NAME = ITKit; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", diff --git a/ITWindowEffect.m b/ITWindowEffect.m index 54a73bf..300819d 100644 --- a/ITWindowEffect.m +++ b/ITWindowEffect.m @@ -15,6 +15,7 @@ NSClassFromString(@"ITZoomWindowEffect"), NSClassFromString(@"ITSpinWindowEffect"), NSClassFromString(@"ITSpinAndZoomWindowEffect"), + NSClassFromString(@"ITCoreImageWindowEffect"), nil]; return classes;