9fd49aa62b59a47fb6d769d906477b204ca81591
[ITKit.git] / ITCoreImageWindowEffect.m
1 #import "ITCoreImageWindowEffect.h"
2 #import "ITTransientStatusWindow.h"
3 #import "ITCoreGraphicsHacks.h"
4 #import "ITCoreImageView.h"
5
6 @interface ITCoreImageWindowEffect (Private)
7 - (void)performAppearFromProgress:(float)progress effectTime:(float)time;
8 - (void)appearStep;
9 - (void)appearFinish;
10 - (void)performVanishFromProgress:(float)progress effectTime:(float)time;
11 - (void)vanishStep;
12 - (void)vanishFinish;
13
14 - (void)setupEffect;
15 @end
16
17 @implementation ITCoreImageWindowEffect
18
19 + (NSString *)effectName
20 {
21     return @"Core Image - Ripple";
22 }
23
24 + (NSDictionary *)supportedPositions
25 {
26     return [NSDictionary dictionaryWithObjectsAndKeys:
27         [NSDictionary dictionaryWithObjectsAndKeys:
28             [NSNumber numberWithBool:YES], @"Left",
29             [NSNumber numberWithBool:YES], @"Center",
30             [NSNumber numberWithBool:YES], @"Right", nil] , @"Top" ,
31         [NSDictionary dictionaryWithObjectsAndKeys:
32             [NSNumber numberWithBool:YES], @"Left",
33             [NSNumber numberWithBool:YES], @"Center",
34             [NSNumber numberWithBool:YES], @"Right", nil] , @"Middle" ,
35         [NSDictionary dictionaryWithObjectsAndKeys:
36             [NSNumber numberWithBool:YES], @"Left",
37             [NSNumber numberWithBool:YES], @"Center",
38             [NSNumber numberWithBool:YES], @"Right", nil] , @"Bottom" , nil];
39 }
40
41 + (unsigned int)listOrder
42 {
43     return 800;
44 }
45
46 /*************************************************************************/
47 #pragma mark -
48 #pragma mark APPEAR METHODS
49 /*************************************************************************/
50
51 - (void)performAppear
52 {
53     __idle = NO;
54         
55     [self setWindowVisibility:ITWindowAppearingState];
56     [self performAppearFromProgress:0.0 effectTime:_effectTime];
57 }
58
59 - (void)performAppearFromProgress:(float)progress effectTime:(float)time
60 {
61     [_window setEffectProgress:progress];
62     _effectSpeed = (1.0 / (EFFECT_FPS * time));
63
64     if ( progress == 0.0 ) {
65         [_window setAlphaValue:0.0];
66     }
67         
68         [_window orderFront:self];
69         
70     _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
71                                                     target:self
72                                                   selector:@selector(appearStep)
73                                                   userInfo:nil
74                                                    repeats:YES];
75         [self setupEffect];
76 }
77
78 - (void)appearStep
79 {
80     float interFade = 0.0;
81     [_window setEffectProgress:([_window effectProgress] + _effectSpeed)];
82     [_window setEffectProgress:( ([_window effectProgress] < 1.0) ? [_window effectProgress] : 1.0)];
83     interFade = (( sin(([_window effectProgress] * pi) - (pi / 2)) + 1 ) / 2);
84     [_window setAlphaValue:interFade];
85
86     if ( [_window effectProgress] >= 1.0 ) {
87         [self appearFinish];
88     }
89 }
90
91 - (void)appearFinish
92 {
93     [_effectTimer invalidate];
94     _effectTimer = nil;
95
96     [self setWindowVisibility:ITWindowVisibleState];
97
98     __idle = YES;
99     if ( __shouldReleaseWhenIdle ) {
100         [self release];
101     }
102 }
103
104 - (void)cancelAppear
105 {
106     [self setWindowVisibility:ITWindowVanishingState];
107
108     [_effectTimer invalidate];
109     _effectTimer = nil;
110
111     [self performVanishFromProgress:[_window effectProgress] effectTime:(_effectTime / 3.5)];
112 }
113
114
115 /*************************************************************************/
116 #pragma mark -
117 #pragma mark VANISH METHODS
118 /*************************************************************************/
119
120 - (void)performVanish
121 {
122     __idle = NO;
123         
124     [self setWindowVisibility:ITWindowVanishingState];
125     [self performVanishFromProgress:1.0 effectTime:_effectTime];
126 }
127
128 - (void)performVanishFromProgress:(float)progress effectTime:(float)time
129 {
130     [_window setEffectProgress:progress];
131     _effectSpeed = (1.0 / (EFFECT_FPS * time));
132     if ( progress == 1.0 ) {
133         [_window setAlphaValue:1.0];
134     }
135
136     [_window orderFront:self];
137         
138     _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
139                                                     target:self
140                                                   selector:@selector(vanishStep)
141                                                   userInfo:nil
142                                                    repeats:YES];
143         [self setupEffect];
144 }
145
146 - (void)vanishStep
147 {
148     float interFade = 1.0;
149     [_window setEffectProgress:([_window effectProgress] - _effectSpeed)];
150     [_window setEffectProgress:( ([_window effectProgress] > 0.0) ? [_window effectProgress] : 0.0)];
151     interFade = (( sin(([_window effectProgress] * pi) - (pi / 2)) + 1 ) / 2);
152     [_window setAlphaValue:interFade];
153
154     if ( [_window effectProgress] <= 0.0 ) {
155         [self vanishFinish];
156     }
157 }
158
159 - (void)vanishFinish
160 {
161     [_effectTimer invalidate];
162     _effectTimer = nil;
163     [_window orderOut:self];
164     [_window setAlphaValue:1.0];
165         
166     [self setWindowVisibility:ITWindowHiddenState];
167
168     __idle = YES;
169     
170     if ( __shouldReleaseWhenIdle ) {
171         [self release];
172     }
173 }
174
175 - (void)cancelVanish
176 {
177     [self setWindowVisibility:ITWindowVanishingState];
178
179     [_effectTimer invalidate];
180     _effectTimer = nil;
181
182     [self performAppearFromProgress:[_window effectProgress] effectTime:(_effectTime / 3.5)];
183 }
184
185 /*************************************************************************/
186 #pragma mark -
187 #pragma mark CORE IMAGE METHODS
188 /*************************************************************************/
189
190 - (void)setupEffect
191 {
192         NSRect rippleRect = [_window frame];
193         NSRect screenRect = [[_window screen] frame];
194         
195         _ripple = YES;
196         
197     rippleRect.origin.y = - (NSMaxY(rippleRect) - screenRect.size.height);
198         
199         _effectWindow = [[NSWindow alloc] initWithContentRect:_ripple ? NSInsetRect([_window frame], -200, -200) : [_window frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
200         [_effectWindow setBackgroundColor:[NSColor clearColor]];
201         [_effectWindow setAlphaValue:1.0];
202         [_effectWindow setOpaque:NO];
203         [_effectWindow setHasShadow:NO];
204         [_effectWindow setContentView:[[ITCoreImageView alloc] initWithFrame:[_window frame]]];
205         [_effectWindow setLevel:[_window level]];
206         
207         [_effectWindow orderFrontRegardless];
208     [_window orderWindow:NSWindowAbove relativeTo:[_effectWindow windowNumber]];
209         
210         if (_ripple) {
211                 _effectFilter = [[CIFilter filterWithName:@"CIShapedWaterRipple"] retain];
212                 [_effectFilter setDefaults];
213                 [_effectFilter setValue:[NSNumber numberWithFloat:50.0] forKey:@"inputCornerRadius"];
214                 [_effectFilter setValue:[CIVector vectorWithX:rippleRect.origin.x Y:rippleRect.origin.y] forKey:@"inputPoint0"];
215                 [_effectFilter setValue:[CIVector vectorWithX:(rippleRect.origin.x + rippleRect.size.width) Y:(rippleRect.origin.y + rippleRect.size.height)] forKey:@"inputPoint1"];
216                 [_effectFilter setValue:[NSNumber numberWithFloat:0.0] forKey:@"inputPhase"];
217         } else {
218                 _effectFilter = [[CIFilter filterWithName:@"CIZoomBlur"] retain];
219                 [_effectFilter setDefaults];
220                 [_effectFilter setValue:[CIVector vectorWithX:(rippleRect.origin.x + rippleRect.size.width / 2) Y:(rippleRect.origin.y + rippleRect.size.height / 2)] forKey:@"inputCenter"];
221         }
222         
223         _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain];
224         [_windowFilter addToWindow:(CGSWindowID)[_effectWindow windowNumber] flags:1];
225         
226         [NSThread detachNewThreadSelector:@selector(runFilterAnimation:) toTarget:self withObject:self];
227 }
228
229 - (void)runFilterAnimation:(id)sender
230 {
231         NSAutoreleasePool *pool;
232     CICGSFilter *oldFilter;
233     CFAbsoluteTime startTime, time;
234         CGSWindowID windowNumber = (CGSWindowID)[_effectWindow windowNumber];
235     
236     pool = [[NSAutoreleasePool alloc] init];
237         
238     startTime = CFAbsoluteTimeGetCurrent();
239     time = CFAbsoluteTimeGetCurrent();
240         
241         while (time < (startTime + 2.5) && (time >= startTime)) {
242                 oldFilter = _windowFilter;
243                 if (_ripple) {
244                         [_effectFilter setValue:[NSNumber numberWithFloat:160*(time - startTime)] forKey:@"inputPhase"];
245                 } else {
246                         [_effectFilter setValue:[NSNumber numberWithFloat:5 * (time - startTime)] forKey:@"inputAmount"];
247                 }
248         _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain];
249         [_windowFilter addToWindow:windowNumber flags:1];
250                 [oldFilter removeFromWindow:windowNumber];
251                 [oldFilter release];
252         time = CFAbsoluteTimeGetCurrent();
253         }
254         
255         [_windowFilter removeFromWindow:windowNumber];
256         [_windowFilter release];
257     [_effectFilter release];
258     [_effectWindow orderOut:self];
259         [[_effectWindow contentView] release];
260     [_effectWindow release];
261     [pool release];
262 }
263
264 @end