Checking in new window effect frame, so I can begin moving the guts into it. Also...
[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 view.
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         _screenPadding       = 32.0;
100         _entryEffect         = ITTransientStatusWindowEffectNone;
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 ( _entryEffect == ITTransientStatusWindowEffectNone ) {
150         [super orderFront:sender];
151         _visibilityState = ITTransientStatusWindowVisibleState;
152     } else {
153         [self performEffect];
154     }
155     if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
156         // set the timer, and orderOut: when it lapses.
157     }
158 }
159
160 - (void)makeKeyAndOrderFront:(id)sender
161 {
162     if ( _exitMode == ITTransientStatusWindowExitAfterDelay ) {
163         // set the timer, and orderOut: when it lapses.
164     }
165
166     if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
167         [super makeKeyAndOrderFront:sender];
168         _visibilityState = ITTransientStatusWindowVisibleState;
169     } else {
170         [self performEffect];
171         [self makeKeyWindow];
172     }
173 }
174
175 - (void)orderOut:(id)sender
176 {
177     if ( _entryEffect == ITTransientStatusWindowEffectNone ) {
178         [super orderOut:sender];
179         _visibilityState = ITTransientStatusWindowHiddenState;
180     } else {
181         [self performEffect];
182     }
183 }
184
185 - (NSTimeInterval)animationResizeTime:(NSRect)newFrame
186 {
187     return _effectTime;
188 }
189
190 /*
191
192 - (id)contentView
193 {
194     if ( _backgroundType == ITTransientStatusWindowRounded ) {
195         return _contentSubView;
196     } else {
197         return [super contentView];
198     }
199 }
200
201 - (void)setContentView:(NSView *)aView
202 {
203     if ( _backgroundType == ITTransientStatusWindowRounded ) {
204        [_contentSubView removeFromSuperview];
205         _contentSubView = aView;
206         [_contentSubView setFrame:[[super contentView] frame]];
207         [[super contentView] addSubview:_contentSubView];
208         [_contentSubView setNextResponder:self];
209     } else {
210         [super setContentView:aView];
211     }
212 }
213
214 */
215
216 - (ITTransientStatusWindowVisibilityState)visibilityState
217 {
218     return _visibilityState;
219 }
220
221 - (ITTransientStatusWindowExitMode)exitMode
222 {
223     return _exitMode;
224 }
225
226 - (void)setExitMode:(ITTransientStatusWindowExitMode)newMode
227 {
228     _exitMode = newMode;
229 }
230
231 - (float)exitDelay
232 {
233     return _exitDelay;
234 }
235
236 - (void)setExitDelay:(float)seconds
237 {
238     _exitDelay = seconds;
239 }
240
241 - (ITTransientStatusWindowBackgroundType)backgroundType
242 {
243 //  return _backgroundType;
244     return ITTransientStatusWindowRounded;
245 }
246
247 - (void)setBackgroundType:(ITTransientStatusWindowBackgroundType)newType
248 {
249 //  setBackgroundType: is currently ignored.  Defaults to ITTransientStatusWindowRounded.
250 //  _backgroundType = newType;
251     _backgroundType = ITTransientStatusWindowRounded;
252 }
253
254 - (ITTransientStatusWindowPosition)verticalPosition;
255 {
256     return _verticalPosition;
257 }
258
259 - (void)setVerticalPosition:(ITTransientStatusWindowPosition)newPosition;
260 {
261     _verticalPosition = newPosition;
262 }
263
264 - (ITTransientStatusWindowPosition)horizontalPosition;
265 {
266     return _horizontalPosition;
267 }
268
269 - (void)setHorizontalPosition:(ITTransientStatusWindowPosition)newPosition;
270 {
271     _horizontalPosition = newPosition;
272 }
273
274 - (ITWindowEffect *)entryEffect
275 {
276     return _entryEffect;
277 }
278
279 - (void)setEntryEffect:(ITWindowEffect *)newEffect
280 {
281     [_entryEffect autorelease];
282     _entryEffect = [newEffect retain];
283 }
284
285 - (ITWindowEffect *)exitEffect
286 {
287     return _exitEffect;
288 }
289
290 - (void)setExitEffect:(ITWindowEffect *)newEffect
291 {
292     [_exitEffect autorelease];
293     _exitEffect = [newEffect retain];
294 }
295
296
297 /*************************************************************************/
298 #pragma mark -
299 #pragma mark PRIVATE METHODS
300 /*************************************************************************/
301
302 - (void)rebuildWindow;
303 {
304     if ( _backgroundType == ITTransientStatusWindowRounded ) {
305         ITGrayRoundedView *roundedView = [[[ITGrayRoundedView alloc] initWithFrame:[self frame]] autorelease];
306
307         [self setBackgroundColor:[NSColor clearColor]];
308         [self setHasShadow:NO];
309         [self setOpaque:NO];
310         
311         [self setContentView:roundedView];
312 //      [super setContentView:roundedView];
313 //      [_contentSubView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
314 //      [self setContentView:_contentSubView];
315     } else {
316         // YUO == CLWONBAOT
317     }
318 }
319
320 - (void)performEffect
321 {
322     if ( _visibilityState == ITTransientStatusWindowHiddenState ) {
323         _visibilityState = ITTransientStatusWindowEnteringState;
324     } else if ( _visibilityState == ITTransientStatusWindowVisibleState ) {
325         _visibilityState = ITTransientStatusWindowExitingState;
326     } else {
327         return;
328     }
329         
330     if ( _entryEffect == ITTransientStatusWindowEffectDissolve ) {
331         [self dissolveEffect];
332     } else if ( _entryEffect == ITTransientStatusWindowEffectSlideVertically ) {
333         [self slideVerticalEffect];
334     } else if ( _entryEffect == ITTransientStatusWindowEffectSlideHorizontally ) {
335         [self slideHorizontalEffect];
336     } else if ( _entryEffect == ITTransientStatusWindowEffectPivot ) {
337         [self pivotEffect];
338     }
339 }
340
341 - (void)dissolveEffect
342 {
343     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
344         [super orderFront:self];
345         _visibilityState = ITTransientStatusWindowVisibleState;
346     } else {
347         [super orderOut:self];
348         _visibilityState = ITTransientStatusWindowHiddenState;
349     }
350 }
351
352 - (void)slideVerticalEffect
353 {
354     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
355         [super orderFront:self];
356         _visibilityState = ITTransientStatusWindowVisibleState;
357     } else {
358         [super orderOut:self];
359         _visibilityState = ITTransientStatusWindowHiddenState;
360     }
361 }
362
363 - (void)slideHorizontalEffect
364 {
365     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
366         [super orderFront:self];
367         _visibilityState = ITTransientStatusWindowVisibleState;
368     } else {
369         [super orderOut:self];
370         _visibilityState = ITTransientStatusWindowHiddenState;
371     }
372 }
373
374 - (void)pivotEffect
375 {
376     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
377         [self setPivot:315.0];
378         _effectProgress = 0.0;
379         [self setAlphaValue:0.0];
380         [super orderFront:self];
381         _effectTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / EFFECT_FPS)
382                                                         target:self
383                                                       selector:@selector(pivotStep)
384                                                       userInfo:nil
385                                                        repeats:YES];
386     } else {
387         [super orderOut:self];
388         _visibilityState = ITTransientStatusWindowHiddenState;
389     }
390 }
391
392 - (void)pivotStep
393 {
394     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
395         float interPivot = 0.0;
396         _effectProgress += (1.0 / (EFFECT_FPS * _effectTime));
397         _effectProgress = (_effectProgress < 1.0 ? _effectProgress : 1.0);
398         interPivot = (( sin((_effectProgress * pi) - (pi / 2)) + 1 ) / 2);
399         [self setPivot:((interPivot * 45) + 315)];
400         [self setAlphaValue:interPivot];
401         if ( _effectProgress >= 1.0 ) {
402             [self pivotFinish];
403         }
404     } else {
405         //backwards
406     }
407 }
408
409 - (void)pivotFinish
410 {
411     if ( _visibilityState == ITTransientStatusWindowEnteringState ) {
412         [_effectTimer invalidate];
413         _effectTimer = nil;
414         _effectProgress = 0.0;
415         _visibilityState = ITTransientStatusWindowVisibleState;
416     } else {
417         //backwards
418     }
419 }
420
421
422 - (void)setPivot:(float)angle
423 {
424     float degAngle = (angle * (pi / 180));
425     CGAffineTransform transform = CGAffineTransformMakeRotation(degAngle);
426     
427  // Set pivot point
428     transform.tx = -32.0;
429     transform.ty = [self frame].size.height + 32.0;
430     
431     CGSSetWindowTransform([NSApp contextID],
432                           (CGSWindowID)[self windowNumber],
433                           CGAffineTransformTranslate(transform,
434                                                      (([self frame].origin.x - 32.0) * -1),
435                                                      (([[self screen] frame].size.height - ([self frame].origin.y) + 32.0) * -1) ));
436 }
437
438 @end