Intermediary checkin, just to mark my place and back up, in case Panther decides...
[MenuTunes.git] / StatusWindow.m
1 //
2 //  StatusWindow.m
3 //  MenuTunes
4 //
5 //  Created by Matt L. Judy on Sat Feb 22 2003.
6 //  Copyright (c) 2003 NibFile.com. All rights reserved.
7 //
8
9 #import "StatusWindow.h"
10
11
12 #define SW_PAD            24.00
13 #define SW_SPACE          24.00
14 #define SW_MINW          211.00
15 #define SW_BORDER         32.00
16 #define SW_METER_PAD       4.00
17 #define SW_BUTTON_PAD_R   30.00
18 #define SW_BUTTON_PAD_B   24.00
19 #define SW_BUTTON_DIV     12.00
20 #define SW_BUTTON_EXTRA_W  8.00
21 #define SW_SHADOW_SAT      1.25
22 #define SMALL_DIVISOR      1.33333
23 #define MINI_DIVISOR       1.66667
24
25 @interface StatusWindow (Private)
26 - (NSRect)setupWindowWithDataSize:(NSSize)dataSize;
27 @end
28
29
30 @implementation StatusWindow
31
32
33 /*************************************************************************/
34 #pragma mark -
35 #pragma mark INITIALIZATION / DEALLOCATION METHODS
36 /*************************************************************************/
37
38 - (id)initWithContentView:(NSView *)contentView
39                  exitMode:(ITTransientStatusWindowExitMode)exitMode
40            backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
41 {
42     if ( ( self = [super initWithContentView:contentView
43                                exitMode:exitMode
44                          backgroundType:backgroundType] ) ) {
45      // Set default values.
46         _image  = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
47         _locked = NO;
48         _sizing = StatusWindowRegular;
49     }
50     
51     return self;
52 }
53
54 - (void)dealloc
55 {
56     [_image     release];
57     [super dealloc];
58 }
59
60
61 /*************************************************************************/
62 #pragma mark -
63 #pragma mark ACCESSOR METHODS
64 /*************************************************************************/
65
66 - (void)setImage:(NSImage *)newImage
67 {
68     [_image autorelease];
69     _image = [newImage copy];
70 }
71
72 - (void)setLocked:(BOOL)flag
73 {
74     _locked = flag;
75     [self setExitMode:(flag ? ITTransientStatusWindowExitOnCommand : ITTransientStatusWindowExitAfterDelay)];
76 }
77
78 - (void)setSizing:(StatusWindowSizing)newSizing
79 {
80     _sizing = newSizing;
81 }
82
83
84 /*************************************************************************/
85 #pragma mark -
86 #pragma mark INSTANCE METHODS
87 /*************************************************************************/
88
89 - (void)appear:(id)sender
90 {
91     if ( ! _locked ) {
92         [super appear:sender];
93     }
94 }
95
96 - (void)vanish:(id)sender
97 {
98     if ( ! _locked ) {
99         [super vanish:sender];
100     }
101 }
102
103 - (NSRect)setupWindowWithDataSize:(NSSize)dataSize
104 {
105     float        divisor       = 1.0;
106     NSRect       imageRect;
107     float        imageWidth    = 0.0;
108     float        imageHeight   = 0.0;
109     float        dataWidth     = dataSize.width;
110     float        dataHeight    = dataSize.height;
111     float        contentHeight = 0.0;
112     float        windowWidth   = 0.0;
113     float        windowHeight  = 0.0;
114     ITImageView *imageView;
115
116     if ( _sizing == StatusWindowSmall ) {
117         divisor = SMALL_DIVISOR;
118     } else if ( _sizing == StatusWindowMini ) {
119         divisor = MINI_DIVISOR;
120     }
121
122     //  Get image width and height.
123     imageWidth  = ( [_image size].width  / divisor );
124     imageHeight = ( [_image size].height / divisor );
125     
126 //  Set the content height to the greater of the text and image heights.
127     contentHeight = ( ( imageHeight > dataHeight ) ? imageHeight : dataHeight );
128
129 //  Setup the Window, and remove all its contentview's subviews.
130     windowWidth  = ( (SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor) + dataWidth + (SW_PAD / divisor) );
131     windowHeight = ( (SW_PAD / divisor) + contentHeight + (SW_PAD / divisor) );
132     
133 #warning Adjust frame for positioning here.
134     
135     [self setFrame:NSMakeRect( (SW_BORDER + [[self screen] visibleFrame].origin.x),
136                                (SW_BORDER + [[self screen] visibleFrame].origin.y),
137                                windowWidth,
138                                windowHeight) display:YES animate:YES];
139     [[[self contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
140
141 //  Setup, position, fill, and add the image view to the content view.
142     imageRect = NSMakeRect( (SW_PAD / divisor),
143                             ((SW_PAD / divisor) + ((contentHeight - imageHeight) / 2)),
144                             imageWidth,
145                             imageHeight );
146     imageView = [[[NSImageView alloc] initWithFrame:imageRect] autorelease];
147     [imageView setImage:_image];
148     [[self contentView] addSubview:imageView];
149
150     return NSMakeRect( ((SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor)),
151                        ((SW_PAD / divisor) + ((contentHeight - dataHeight) / 2)),
152                        dataWidth,
153                        dataHeight);
154 }
155
156 - (void)buildTextWindowWithString:(NSString *)text
157 {
158     if ( ! _locked ) {
159
160         float         divisor       = 1.0;
161         float         dataWidth     = 0.0;
162         float         dataHeight    = 0.0;
163         NSRect        dataRect;
164         NSArray      *lines         = [text componentsSeparatedByString:@"\n"];
165         id                        oneLine       = nil;
166         NSEnumerator *lineEnum      = [lines objectEnumerator];
167         float         baseFontSize  = 18.0;
168         ITTextField  *textField;
169         NSFont       *font;
170         NSDictionary *attr;
171
172         if ( _sizing == StatusWindowSmall ) {
173             divisor = SMALL_DIVISOR;
174         } else if ( _sizing == StatusWindowMini ) {
175             divisor = MINI_DIVISOR;
176         }
177
178         font = [NSFont fontWithName:@"Lucida Grande Bold" size:(baseFontSize / divisor)];
179         attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
180         
181 //      Iterate over each line to get text width and height
182         while ( (oneLine = [lineEnum nextObject]) ) {
183 //          Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
184             float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
185 //          Add the height of this line to the total text height
186             dataHeight += [oneLine sizeWithAttributes:attr].height;
187 //          If this line wider than the last one, set it as the text width.
188             dataWidth = ( ( dataWidth > oneLineWidth ) ? dataWidth : oneLineWidth );
189         }
190         
191 //      Add 4.0 to the final dataHeight to accomodate the shadow.
192         dataHeight += 4.0;
193
194         dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
195         
196 //      Create, position, setup, fill, and add the text view to the content view.
197         textField = [[[ITTextField alloc] initWithFrame:dataRect] autorelease];
198         [textField setEditable:NO];
199         [textField setSelectable:NO];
200         [textField setBordered:NO];
201         [textField setDrawsBackground:NO];
202         [textField setFont:font];
203         [textField setTextColor:[NSColor whiteColor]];
204         [textField setCastsShadow:YES];
205         [textField setStringValue:text];
206         [textField setShadowSaturation:SW_SHADOW_SAT];
207         [[self contentView] addSubview:textField];
208         
209 //      Display the window.
210         [[self contentView] setNeedsDisplay:YES];
211
212     }
213 }
214
215 - (void)buildMeterWindowWithCharacter:(NSString *)character
216                                  size:(float)size
217                                 count:(int)count
218                                active:(int)active
219 {
220     if ( ! _locked ) {
221
222         float         divisor     = 1.0;
223         NSFont       *font;
224         NSDictionary *attr;
225         NSSize        charSize;
226         float         cellHeight;
227         float         cellWidth;
228         float         dataWidth;
229         NSRect        dataRect;
230         NSEnumerator *cellEnum    = nil;
231         id            aCell       = nil;
232         int           activeCount = 0;
233         NSColor      *onColor     = [NSColor whiteColor];
234         NSColor      *offColor    = [NSColor colorWithCalibratedWhite:0.15 alpha:0.50];
235         NSMatrix     *volMatrix;
236         
237         if ( _sizing == StatusWindowSmall ) {
238             divisor = SMALL_DIVISOR;
239         } else if ( _sizing == StatusWindowMini ) {
240             divisor = MINI_DIVISOR;
241         }
242         
243         font        = [NSFont fontWithName:@"Lucida Grande Bold" size:( size / divisor )];
244         attr        = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
245         charSize    = [character sizeWithAttributes:attr];
246         cellHeight  = ( charSize.height + 4.0 );  // Add 4.0 for shadow
247         cellWidth   = ( (charSize.width) + (SW_METER_PAD / divisor) );
248         dataWidth   = ( cellWidth * count );
249         dataRect    = [self setupWindowWithDataSize:NSMakeSize(dataWidth, cellHeight)];
250         volMatrix   = [[[NSMatrix alloc] initWithFrame:dataRect
251                                                   mode:NSHighlightModeMatrix
252                                              cellClass:NSClassFromString(@"ITTextFieldCell")
253                                           numberOfRows:1
254                                        numberOfColumns:count] autorelease];
255         
256         [volMatrix setCellSize:NSMakeSize(cellWidth, cellHeight)];
257         [volMatrix setIntercellSpacing:NSMakeSize(0, 0)];
258
259         cellEnum = [[volMatrix cells] objectEnumerator];
260
261         while ( (aCell = [cellEnum nextObject]) ) {
262             [aCell setEditable:NO];
263             [aCell setSelectable:NO];
264             [aCell setBordered:NO];
265             [aCell setDrawsBackground:NO];
266             [aCell setAlignment:NSCenterTextAlignment];
267             [aCell setFont:font];
268             [aCell setStringValue:character];
269             [aCell setShadowSaturation:SW_SHADOW_SAT];
270
271             activeCount ++;
272
273             if ( active >= activeCount ) {
274                 [aCell setCastsShadow:YES];
275                 [aCell setTextColor:onColor];
276             } else {
277                 [aCell setCastsShadow:NO];
278                 [aCell setTextColor:offColor];
279             }
280
281         }
282
283         [[self contentView] addSubview:volMatrix];
284         [[self contentView] setNeedsDisplay:YES];
285         
286     }
287 }
288
289 - (void)buildDialogWindowWithMessage:(NSString *)message
290                        defaultButton:(NSString *)defaultTitle
291                      alternateButton:(NSString *)alternateTitle
292                               target:(id)target
293                        defaultAction:(SEL)okAction
294                      alternateAction:(SEL)alternateAction
295 {
296     if ( ! _locked ) {
297
298         float         textWidth     = 0.0;
299         float         textHeight    = 0.0;
300         float         okWidth       = 0.0;
301         float         cancelWidth   = 0.0;
302         float         wideButtonW   = 0.0;
303         float         buttonWidth   = 0.0;
304         float         dataHeight    = 0.0;
305         float         dataWidth     = 0.0;
306         NSRect        dataRect;
307         float         textY         = 0.0;
308         NSRect        textRect;
309         float         textAddBelow  = 32.0;
310         float         dataMinH      = 92.0;
311         float         textMinH      = 48.0;
312         NSArray      *lines         = [message componentsSeparatedByString:@"\n"];
313         id                        oneLine       = nil;
314         NSEnumerator *lineEnum      = [lines objectEnumerator];
315         ITTextField  *textField;
316         ITButton     *okButton;
317         ITButton     *cancelButton;
318         NSColor      *textColor     = [NSColor whiteColor];
319         NSFont       *font          = [NSFont fontWithName:@"Lucida Grande Bold" size:18];
320         NSDictionary *attr          = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
321         NSFont       *buttonFont    = [NSFont fontWithName:@"Lucida Grande Bold" size:14];
322         NSDictionary *buttonAttr    = [NSDictionary dictionaryWithObjectsAndKeys:
323             buttonFont , NSFontAttributeName,
324             textColor  , NSForegroundColorAttributeName, 
325             nil];
326         
327 //      Iterate over each line to get text width and height
328         while ( (oneLine = [lineEnum nextObject]) ) {
329 //          Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
330             float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
331 //          Add the height of this line to the total text height
332             textHeight += [oneLine sizeWithAttributes:attr].height;
333 //          If this line wider than the last one, set it as the text width.
334             textWidth = ( ( textWidth > oneLineWidth ) ? textWidth : oneLineWidth );
335         }
336         
337 //      Add 4.0 to the final dataHeight to accomodate the shadow.
338         textHeight += 4.0;
339         
340 //      Add extra padding below the text
341         dataHeight = (textHeight + textAddBelow);
342         
343 //      Test to see if data height is tall enough
344         if ( dataHeight < dataMinH ) {
345             dataHeight = dataMinH;
346         }
347         
348 //      Make the buttons, set the titles, and size them to fit their titles
349         okButton     = [[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
350         cancelButton = [[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
351         [okButton     setTarget:target];
352         [cancelButton setTarget:target];
353         [okButton     setAction:okAction];
354         [cancelButton setAction:alternateAction];
355         [okButton     setBezelStyle:ITGrayRoundedBezelStyle];
356         [cancelButton setBezelStyle:ITGrayRoundedBezelStyle];
357         [okButton     setAlignment:NSRightTextAlignment];
358         [cancelButton setAlignment:NSCenterTextAlignment];
359         [okButton     setImagePosition:NSNoImage];
360         [cancelButton setImagePosition:NSNoImage];
361         [okButton     setAttributedTitle:[[[NSAttributedString alloc] initWithString:defaultTitle
362                                                                           attributes:buttonAttr] autorelease]];
363         [cancelButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:alternateTitle
364                                                                           attributes:buttonAttr] autorelease]];
365         [okButton     sizeToFit];
366         [cancelButton sizeToFit];
367         
368 //      Get the button widths.  Add any extra width here.
369         okWidth     = ([okButton     frame].size.width + SW_BUTTON_EXTRA_W);
370         cancelWidth = ([cancelButton frame].size.width + SW_BUTTON_EXTRA_W);
371         
372 //      Figure out which button is wider.
373         wideButtonW = ( (okWidth > cancelWidth) ? okWidth : cancelWidth );
374
375 //      Get the total width of the buttons. Add the divider space.
376         buttonWidth = ( (wideButtonW * 2) + SW_BUTTON_DIV );
377
378 //      Set the dataWidth to whichever is greater: text width or button width.
379         dataWidth = ( (textWidth > buttonWidth) ? textWidth : buttonWidth);
380         
381 //      Setup the window
382         dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
383         
384 //      Set an initial vertical point for the textRect's origin.
385         textY = dataRect.origin.y + textAddBelow;
386         
387 //      Move that point up if the minimimum height of the text area is not occupied.
388         if ( textHeight < textMinH ) {
389             textY += ( (textMinH - textHeight) / 2 );
390         }
391         
392 //      Build the text rect.
393         textRect = NSMakeRect(dataRect.origin.x,
394                               textY,
395                               textWidth,
396                               textHeight);
397         
398 //      Create, position, setup, fill, and add the text view to the content view.
399         textField = [[[ITTextField alloc] initWithFrame:textRect] autorelease];
400         [textField setEditable:NO];
401         [textField setSelectable:NO];
402         [textField setBordered:NO];
403         [textField setDrawsBackground:NO];
404         [textField setFont:font];
405         [textField setTextColor:textColor];
406         [textField setCastsShadow:YES];
407         [textField setStringValue:message];
408         [textField setShadowSaturation:SW_SHADOW_SAT];
409         [[self contentView] addSubview:textField];
410         
411 //      Set the button frames, and add them to the content view.
412         [okButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - (wideButtonW + SW_BUTTON_PAD_R) ),
413                                        SW_BUTTON_PAD_B,
414                                        wideButtonW,
415                                        24.0)];
416         [cancelButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - ((wideButtonW * 2) + SW_BUTTON_DIV + SW_BUTTON_PAD_R) ),
417                                            SW_BUTTON_PAD_B,
418                                            wideButtonW,
419                                            24.0)];
420         [[self contentView] addSubview:okButton];
421         [[self contentView] addSubview:cancelButton];
422
423         [self setIgnoresMouseEvents:NO];
424   
425 //      Display the window.
426         [[self contentView] setNeedsDisplay:YES];
427     }
428 }
429
430
431 @end