Added a new core image ripple effect.
[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     rippleRect.origin.y = - (NSMaxY(rippleRect) - screenRect.size.height);
196         
197         _effectWindow = [[NSWindow alloc] initWithContentRect:NSInsetRect([_window frame], -200, -200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
198         [_effectWindow setBackgroundColor:[NSColor clearColor]];
199         [_effectWindow setAlphaValue:1.0];
200         [_effectWindow setOpaque:NO];
201         [_effectWindow setHasShadow:NO];
202         [_effectWindow setContentView:[[ITCoreImageView alloc] initWithFrame:[_window frame]]];
203         [_effectWindow setLevel:[_window level]];
204         
205         [_effectWindow orderFrontRegardless];
206     [_window orderWindow:NSWindowAbove relativeTo:[_effectWindow windowNumber]];
207         
208         _effectFilter = [[CIFilter filterWithName:@"CIShapedWaterRipple"] retain];
209     [_effectFilter setDefaults];
210     [_effectFilter setValue:[NSNumber numberWithFloat:50.0] forKey:@"inputCornerRadius"];
211     [_effectFilter setValue:[CIVector vectorWithX:rippleRect.origin.x Y:rippleRect.origin.y] forKey:@"inputPoint0"];
212     [_effectFilter setValue:[CIVector vectorWithX:(rippleRect.origin.x + rippleRect.size.width) Y:(rippleRect.origin.y + rippleRect.size.height)] forKey:@"inputPoint1"];
213     [_effectFilter setValue:[NSNumber numberWithFloat:0.0] forKey:@"inputPhase"];
214         
215         _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain];
216         [_windowFilter addToWindow:(CGSWindowID)[_effectWindow windowNumber] flags:1];
217         
218         [NSThread detachNewThreadSelector:@selector(runFilterAnimation:) toTarget:self withObject:self];
219 }
220
221 - (void)runFilterAnimation:(id)sender
222 {
223         NSAutoreleasePool *pool;
224     CICGSFilter *oldFilter;
225     CFAbsoluteTime startTime, time;
226         CGSWindowID windowNumber = (CGSWindowID)[_effectWindow windowNumber];
227     
228     pool = [[NSAutoreleasePool alloc] init];
229         
230     startTime = CFAbsoluteTimeGetCurrent();
231     time = CFAbsoluteTimeGetCurrent();
232         
233         while (time < (startTime + 2.5) && (time >= startTime)) {
234                 oldFilter = _windowFilter;
235                 [_effectFilter setValue:[NSNumber numberWithFloat:160*(time - startTime)] forKey:@"inputPhase"];
236         _windowFilter = [[CICGSFilter filterWithFilter:_effectFilter connectionID:[NSApp contextID]] retain];
237         [_windowFilter addToWindow:windowNumber flags:1];
238                 [oldFilter removeFromWindow:windowNumber];
239                 [oldFilter release];
240         time = CFAbsoluteTimeGetCurrent();
241         }
242         
243         [_windowFilter removeFromWindow:windowNumber];
244         [_windowFilter release];
245     [_effectFilter release];
246     [_effectWindow orderOut:self];
247         [[_effectWindow contentView] release];
248     [_effectWindow release];
249     [pool release];
250 }
251
252 @end