The Pivot effect is now a part of ITTransientStatusWindow, and includes both EIEO...
[ITKit.git] / ITTransientStatusWindow.m
1 #import "ITTransientStatusWindow.h"
2 #import <CoreGraphics/CoreGraphics.h>
3 #import "ITCoreGraphicsHacks.h"
4 #import "ITTextField.h"
5 #import "ITGrayRoundedView.h"
6
7
8 #define EFFECT_FPS 30.0
9
10
11 /*************************************************************************/
12 #pragma mark -
13 #pragma mark EVIL HACKERY
14 /*************************************************************************/
15
16 @interface NSApplication (HACKHACKHACKHACK)
17 - (CGSConnectionID)contextID;
18 @end
19
20
21 /*************************************************************************/
22 #pragma mark -
23 #pragma mark PRIVATE METHOD DECLARATIONS
24 /*************************************************************************/
25
26 @interface ITTransientStatusWindow (Private)
27 - (id)initWithContentView:(NSView *)contentView
28                  exitMode:(ITTransientStatusWindowExitMode)exitMode
29            backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType;
30 - (void)rebuildWindow;
31 - (void)performEffect;
32 - (void)dissolveEffect;
33 - (void)slideVerticalEffect;
34 - (void)slideHorizontalEffect;
35 - (void)pivotEffect;
36 - (void)pivotStep;
37 - (void)pivotFinish;
38 - (void)setPivot:(float)angle;
39 @end
40
41
42 /*************************************************************************/
43 #pragma mark -
44 #pragma mark IMPLEMENTATION
45 /*************************************************************************/
46
47 @implementation ITTransientStatusWindow
48
49
50 /*************************************************************************/
51 #pragma mark -
52 #pragma mark SHARED STATIC OBJECTS
53 /*************************************************************************/
54
55 static ITTransientStatusWindow *staticWindow = nil;
56
57
58 /*************************************************************************/
59 #pragma mark -
60 #pragma mark INITIALIZATION METHODS
61 /*************************************************************************/
62
63 + (ITTransientStatusWindow *)sharedWindow
64 {
65     if ( ! (staticWindow) ) {
66         staticWindow = [[self alloc] initWithContentView:nil
67                                                 exitMode:ITTransientStatusWindowExitAfterDelay
68                                           backgroundType:ITTransientStatusWindowRounded];
69     }
70     return staticWindow;
71 }
72
73 - (id)initWithContentView:(NSView *)contentView
74                  exitMode:(ITTransientStatusWindowExitMode)exitMode
75            backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
76 {
77     NSRect contentRect;
78     
79     // If no Content View was provided, use a generic NSView with the app icon.
80     if ( ! (contentView) ) {
81         contentView = [[[NSView alloc] initWithFrame:
82             NSMakeRect(100.0, 100.0, 200.0, 200.0)] autorelease];
83     }
84     
85     // Set the content rect to the frame of the content view, now guaranteed to exist.
86     contentRect = [contentView frame];
87     
88     if ( ( self = [super initWithContentRect:contentRect
89                                    styleMask:NSBorderlessWindowMask
90                                      backing:NSBackingStoreBuffered
91                                        defer:NO] ) ) {
92                                     
93         _visibilityState     = ITTransientStatusWindowHiddenState;
94         _exitMode            = exitMode;
95         _exitDelay           = DEFAULT_EXIT_DELAY;
96         _backgroundType      = backgroundType;
97         _verticalPosition    = ITTransientStatusWindowPositionBottom;
98         _horizontalPosition  = ITTransientStatusWindowPositionLeft;
99 //      _entryEffect         = ITTransientStatusWindowEffectNone;
100         _entryEffect         = ITTransientStatusWindowEffectPivot;
101         _exitEffect          = ITTransientStatusWindowEffectDissolve;
102         _effectTime          = DEFAULT_EFFECT_TIME;
103         _effectProgress      = 0.00;
104         _reallyIgnoresEvents = YES;
105         _delayTimer          = nil;
106         _effectTimer         = nil;
107
108 //        if ( _backgroundType == ITTransientStatusWindowRounded ) {
109 //            _contentSubView = contentView;
110 //        } else {
111 //            [self setContentView:contentView];
112 //        }
113
114         [self setIgnoresMouseEvents:YES];
115         [self setLevel:NSScreenSaverWindowLevel];
116         [self setContentView:contentView];
117         [self rebuildWindow];
118     }
119     return self;
120 }
121
122
123 /*************************************************************************/
124 #pragma mark -
125 #pragma mark INSTANCE METHODS
126 /*************************************************************************/
127
128 - (BOOL)ignoresMouseEvents
129 {
130     return _reallyIgnoresEvents;
131 }
132
133 - (void)setIgnoresMouseEvents:(BOOL)flag
134 {
135     CGSValueObj          key;
136     CGSValueObj          ignore;
137
138     key = CGSCreateCString("IgnoreForEvents");
139     ignore = CGSCreateBoolean( (flag ? kCGSTrue : kCGSFalse) );
140     CGSSetWindowProperty([NSApp contextID], (CGSWindowID)[self windowNumber], key, ignore);
141     CGSReleaseObj(key);
142     CGSReleaseObj(ignore);
143
144     _reallyIgnoresEvents = flag;
145 }
146
147 - (void)orderFront:(id)sender
148 {
149     if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
150         // set the timer, and orderOut: when it lapses.
151     }
152
153     if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
154         [super orderFront:sender];
155         _visibilityState = ITTransientStatusWindowVisibleState;
156     } else {
157         [self performEffect];
158     }
159 }
160
161 - (void)makeKeyAndOrderFront:(id)sender
162 {
163     if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
164         // set the timer, and orderOut: when it lapses.
165     }
166
167     if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
168         [super makeKeyAndOrderFront:sender];
169         _visibilityState = ITTransientStatusWindowVisibleState;
170     } else {
171         [self performEffect];
172         [self makeKeyWindow];
173     }
174 }
175
176 - (void)orderOut:(id)sender
177 {
178     if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
179         [super orderOut:sender];
180         _visibilityState = ITTransientStatusWindowHiddenState;
181     } else {
182         [self performEffect];
183     }
184 }
185
186 - (NSTimeInterval)animationResizeTime:(NSRect)newFrame
187 {
188     return _effectTime;
189 }
190
191 /*
192
193 - (id)contentView
194 {
195     if ( _backgroundType == ITTransientStatusWindowRounded ) {
196         return _contentSubView;
197     } else {
198         return [super contentView];
199     }
200 }
201
202 - (void)setContentView:(NSView *)aView
203 {
204     if ( _backgroundType == ITTransientStatusWindowRounded ) {
205        [_contentSubView removeFromSuperview];
206         _contentSubView = aView;
207         [_contentSubView setFrame:[[super contentView] frame]];
208         [[super contentView] addSubview:_contentSubView];
209         [_contentSubView setNextResponder:self];
210     } else {
211         [super setContentView:aView];
212     }
213 }
214
215 */
216
217 - (ITTransientStatusWindowVisibilityState)visibilityState
218 {
219     return _visibilityState;
220 }
221
222 - (ITTransientStatusWindowExitMode)exitMode
223 {
224     return _exitMode;
225 }
226
227 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
228 {
229     _exitMode = newMode;
230 }
231
232 - (float)exitDelay
233 {
234     return _exitDelay;
235 }
236
237 - (void)setExitDelay:(float)seconds
238 {
239     _exitDelay = seconds;
240 }
241
242 - (ITTransientStatusWindowBackgroundType)backgroundType
243 {
244 //  return _backgroundType;
245     return ITTransientStatusWindowRounded;
246 }
247
248 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
249 {
250 //  setBackgroundType: is currently ignored.  Defaults to ITTransientStatusWindowRounded.
251 //  _backgroundType = newType;
252     _backgroundType = ITTransientStatusWindowRounded;
253 }
254
255 - (ITTransientStatusWindowPosition)verticalPosition;
256 {
257     return _verticalPosition;
258 }
259
260 - (void)setVerticalPosition:(ITTransientStatusWindowPosition)newPosition;
261 {
262     _verticalPosition = newPosition;
263 }
264
265 - (ITTransientStatusWindowPosition)horizontalPosition;
266 {
267     return _horizontalPosition;
268 }
269
270 - (void)setHorizontalPosition:(ITTransientStatusWindowPosition)newPosition;
271 {
272     _horizontalPosition = newPosition;
273 }
274
275 - (ITTransientStatusWindowEffect)entryEffect
276 {
277     return _entryEffect;
278 }
279
280 - (void)setEntryEffect:(ITTransientStatusWindowEffect)newEffect;
281 {
282     _entryEffect = newEffect;
283 }
284
285 - (ITTransientStatusWindowEffect)exitEffect;
286 {
287     return _exitEffect;
288 }
289
290 - (void)setExitEffect:(ITTransientStatusWindowEffect)newEffect;
291 {
292     _exitEffect = newEffect;
293 }
294
295
296 /*************************************************************************/
297 #pragma mark -
298 #pragma mark PRIVATE METHODS
299 /*************************************************************************/
300
301 - (void)rebuildWindow;
302 {
303     if ( _backgroundType == ITTransientStatusWindowRounded ) {
304         ITGrayRoundedView *roundedView = [[[ITGrayRoundedView alloc] initWithFrame:[self frame]] autorelease];
305
306         [self setBackgroundColor:[NSColor clearColor]];
307         [self setHasShadow:NO];
308         [self setOpaque:NO];
309         
310         [self setContentView:roundedView];
311 //      [super setContentView:roundedView];
312 //      [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
313 //      [self setContentView:_contentSubView];
314     } else {
315         // YUO == CLWONBAOT
316     }
317 }
318
319 - (void)performEffect
320 {
321     if ( _visibilityState == ITTransientStatusWindowHiddenState ) {
322         _visibilityState = ITTransientStatusWindowEnteringState;
323     } else if ( _visibilityState == ITTransientStatusWindowVisibleState ) {
324         _visibilityState = ITTransientStatusWindowExitingState;
325     } else {
326         return;
327     }
328         
329     if ( _entryEffect == ITTransientStatusWindowEffectDissolve ) {
330         [self dissolveEffect];
331     } else if ( _entryEffect == ITTransientStatusWindowEffectSlideVertically ) {
332         [self slideVerticalEffect];
333     } else if ( _entryEffect == ITTransientStatusWindowEffectSlideHorizontally ) {
334         [self slideHorizontalEffect];
335     } else if ( _entryEffect == ITTransientStatusWindowEffectPivot ) {
336         [self pivotEffect];
337     }
338 }
339
340 - (void)dissolveEffect
341 {
342     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
343         [super orderFront:self];
344         _visibilityState = ITTransientStatusWindowVisibleState;
345     } else {
346         [super orderOut:self];
347         _visibilityState = ITTransientStatusWindowHiddenState;
348     }
349 }
350
351 - (void)slideVerticalEffect
352 {
353     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
354         [super orderFront:self];
355         _visibilityState = ITTransientStatusWindowVisibleState;
356     } else {
357         [super orderOut:self];
358         _visibilityState = ITTransientStatusWindowHiddenState;
359     }
360 }
361
362 - (void)slideHorizontalEffect
363 {
364     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
365         [super orderFront:self];
366         _visibilityState = ITTransientStatusWindowVisibleState;
367     } else {
368         [super orderOut:self];
369         _visibilityState = ITTransientStatusWindowHiddenState;
370     }
371 }
372
373 - (void)pivotEffect
374 {
375     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
376         [self setPivot:315.0];
377         _effectProgress = 0.0;
378         [self setAlphaValue:0.0];
379         [super orderFront:self];
380         _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
381                                                         target:self
382                                                       selector:@selector(pivotStep)
383                                                       userInfo:nil
384                                                        repeats:YES];
385     } else {
386         [super orderOut:self];
387         _visibilityState = ITTransientStatusWindowHiddenState;
388     }
389 }
390
391 - (void)pivotStep
392 {
393     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
394         float interPivot = 0.0;
395         _effectProgress += (1.0 / (EFFECT_FPS * _effectTime));
396         _effectProgress = (_effectProgress < 1.0 ? _effectProgress : 1.0);
397         interPivot = (( sin((_effectProgress * pi) - (pi / 2)) + 1 ) / 2);
398         [self setPivot:((interPivot * 45) + 315)];
399         [self setAlphaValue:interPivot];
400         if ( _effectProgress >= 1.0 ) {
401             [self pivotFinish];
402         }
403     } else {
404         //backwards
405     }
406 }
407
408 - (void)pivotFinish
409 {
410     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
411         [_effectTimer invalidate];
412         _effectTimer = nil;
413         _effectProgress = 0.0;
414         _visibilityState = ITTransientStatusWindowVisibleState;
415     } else {
416         //backwards
417     }
418 }
419
420
421 - (void)setPivot:(float)angle
422 {
423     float degAngle = (angle * (pi / 180));
424     CGAffineTransform transform = CGAffineTransformMakeRotation(degAngle);
425     transform.tx = -32.0;
426     transform.ty = [self frame].size.height + 32.0;
427     CGSSetWindowTransform([NSApp contextID],
428                           (CGSWindowID)[self windowNumber],
429                           CGAffineTransformTranslate(transform,
430                                                      (([self frame].origin.x - 32.0) * -1),
431                                                      (([[self screen] frame].size.height - ([self frame].origin.y) + 32.0) * -1) ));
432 }
433
434 @end