Sizing is now in, with appropriate UI. Still working on the last of the positioning...
[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     [self setFrame:NSMakeRect( (SW_BORDER + [[self screen] visibleFrame].origin.x),
133                                (SW_BORDER + [[self screen] visibleFrame].origin.y),
134                                windowWidth,
135                                windowHeight) display:YES animate:YES];
136     [[[self contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
137
138 //  Setup, position, fill, and add the image view to the content view.
139     imageRect = NSMakeRect( (SW_PAD / divisor),
140                             ((SW_PAD / divisor) + ((contentHeight - imageHeight) / 2)),
141                             imageWidth,
142                             imageHeight );
143     imageView = [[[NSImageView alloc] initWithFrame:imageRect] autorelease];
144     [imageView setImage:_image];
145     [[self contentView] addSubview:imageView];
146
147     return NSMakeRect( ((SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor)),
148                        ((SW_PAD / divisor) + ((contentHeight - dataHeight) / 2)),
149                        dataWidth,
150                        dataHeight);
151 }
152
153 - (void)buildTextWindowWithString:(NSString *)text
154 {
155     if ( ! _locked ) {
156
157         float         divisor       = 1.0;
158         float         dataWidth     = 0.0;
159         float         dataHeight    = 0.0;
160         NSRect        dataRect;
161         NSArray      *lines         = [text componentsSeparatedByString:@"\n"];
162         id                        oneLine       = nil;
163         NSEnumerator *lineEnum      = [lines objectEnumerator];
164         float         baseFontSize  = 18.0;
165         ITTextField  *textField;
166         NSFont       *font;
167         NSDictionary *attr;
168
169         if ( _sizing == StatusWindowSmall ) {
170             divisor = SMALL_DIVISOR;
171         } else if ( _sizing == StatusWindowMini ) {
172             divisor = MINI_DIVISOR;
173         }
174
175         font = [NSFont fontWithName:@"Lucida Grande Bold" size:(baseFontSize / divisor)];
176         attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
177         
178 //      Iterate over each line to get text width and height
179         while ( (oneLine = [lineEnum nextObject]) ) {
180 //          Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
181             float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
182 //          Add the height of this line to the total text height
183             dataHeight += [oneLine sizeWithAttributes:attr].height;
184 //          If this line wider than the last one, set it as the text width.
185             dataWidth = ( ( dataWidth > oneLineWidth ) ? dataWidth : oneLineWidth );
186         }
187         
188 //      Add 4.0 to the final dataHeight to accomodate the shadow.
189         dataHeight += 4.0;
190
191         dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
192         
193 //      Create, position, setup, fill, and add the text view to the content view.
194         textField = [[[ITTextField alloc] initWithFrame:dataRect] autorelease];
195         [textField setEditable:NO];
196         [textField setSelectable:NO];
197         [textField setBordered:NO];
198         [textField setDrawsBackground:NO];
199         [textField setFont:font];
200         [textField setTextColor:[NSColor whiteColor]];
201         [textField setCastsShadow:YES];
202         [textField setStringValue:text];
203         [textField setShadowSaturation:SW_SHADOW_SAT];
204         [[self contentView] addSubview:textField];
205         
206 //      Display the window.
207         [[self contentView] setNeedsDisplay:YES];
208
209     }
210 }
211
212 - (void)buildMeterWindowWithCharacter:(NSString *)character
213                                  size:(float)size
214                                 count:(int)count
215                                active:(int)active
216 {
217     if ( ! _locked ) {
218
219         float         divisor     = 1.0;
220         NSFont       *font;
221         NSDictionary *attr;
222         NSSize        charSize;
223         float         cellHeight;
224         float         cellWidth;
225         float         dataWidth;
226         NSRect        dataRect;
227         NSEnumerator *cellEnum    = nil;
228         id            aCell       = nil;
229         int           activeCount = 0;
230         NSColor      *onColor     = [NSColor whiteColor];
231         NSColor      *offColor    = [NSColor colorWithCalibratedWhite:0.15 alpha:0.50];
232         NSMatrix     *volMatrix;
233         
234         if ( _sizing == StatusWindowSmall ) {
235             divisor = SMALL_DIVISOR;
236         } else if ( _sizing == StatusWindowMini ) {
237             divisor = MINI_DIVISOR;
238         }
239         
240         font        = [NSFont fontWithName:@"Lucida Grande Bold" size:( size / divisor )];
241         attr        = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
242         charSize    = [character sizeWithAttributes:attr];
243         cellHeight  = ( charSize.height + 4.0 );  // Add 4.0 for shadow
244         cellWidth   = ( (charSize.width) + (SW_METER_PAD / divisor) );
245         dataWidth   = ( cellWidth * count );
246         dataRect    = [self setupWindowWithDataSize:NSMakeSize(dataWidth, cellHeight)];
247         volMatrix   = [[[NSMatrix alloc] initWithFrame:dataRect
248                                                   mode:NSHighlightModeMatrix
249                                              cellClass:NSClassFromString(@"ITTextFieldCell")
250                                           numberOfRows:1
251                                        numberOfColumns:count] autorelease];
252         
253         [volMatrix setCellSize:NSMakeSize(cellWidth, cellHeight)];
254         [volMatrix setIntercellSpacing:NSMakeSize(0, 0)];
255
256         cellEnum = [[volMatrix cells] objectEnumerator];
257
258         while ( (aCell = [cellEnum nextObject]) ) {
259             [aCell setEditable:NO];
260             [aCell setSelectable:NO];
261             [aCell setBordered:NO];
262             [aCell setDrawsBackground:NO];
263             [aCell setAlignment:NSCenterTextAlignment];
264             [aCell setFont:font];
265             [aCell setStringValue:character];
266             [aCell setShadowSaturation:SW_SHADOW_SAT];
267
268             activeCount ++;
269
270             if ( active >= activeCount ) {
271                 [aCell setCastsShadow:YES];
272                 [aCell setTextColor:onColor];
273             } else {
274                 [aCell setCastsShadow:NO];
275                 [aCell setTextColor:offColor];
276             }
277
278         }
279
280         [[self contentView] addSubview:volMatrix];
281         [[self contentView] setNeedsDisplay:YES];
282         
283     }
284 }
285
286 - (void)buildDialogWindowWithMessage:(NSString *)message
287                        defaultButton:(NSString *)defaultTitle
288                      alternateButton:(NSString *)alternateTitle
289                               target:(id)target
290                        defaultAction:(SEL)okAction
291                      alternateAction:(SEL)alternateAction
292 {
293     if ( ! _locked ) {
294
295         float         textWidth     = 0.0;
296         float         textHeight    = 0.0;
297         float         okWidth       = 0.0;
298         float         cancelWidth   = 0.0;
299         float         wideButtonW   = 0.0;
300         float         buttonWidth   = 0.0;
301         float         dataHeight    = 0.0;
302         float         dataWidth     = 0.0;
303         NSRect        dataRect;
304         float         textY         = 0.0;
305         NSRect        textRect;
306         float         textAddBelow  = 32.0;
307         float         dataMinH      = 92.0;
308         float         textMinH      = 48.0;
309         NSArray      *lines         = [message componentsSeparatedByString:@"\n"];
310         id                        oneLine       = nil;
311         NSEnumerator *lineEnum      = [lines objectEnumerator];
312         ITTextField  *textField;
313         ITButton     *okButton;
314         ITButton     *cancelButton;
315         NSColor      *textColor     = [NSColor whiteColor];
316         NSFont       *font          = [NSFont fontWithName:@"Lucida Grande Bold" size:18];
317         NSDictionary *attr          = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
318         NSFont       *buttonFont    = [NSFont fontWithName:@"Lucida Grande Bold" size:14];
319         NSDictionary *buttonAttr    = [NSDictionary dictionaryWithObjectsAndKeys:
320             buttonFont , NSFontAttributeName,
321             textColor  , NSForegroundColorAttributeName, 
322             nil];
323         
324 //      Iterate over each line to get text width and height
325         while ( (oneLine = [lineEnum nextObject]) ) {
326 //          Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
327             float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
328 //          Add the height of this line to the total text height
329             textHeight += [oneLine sizeWithAttributes:attr].height;
330 //          If this line wider than the last one, set it as the text width.
331             textWidth = ( ( textWidth > oneLineWidth ) ? textWidth : oneLineWidth );
332         }
333         
334 //      Add 4.0 to the final dataHeight to accomodate the shadow.
335         textHeight += 4.0;
336         
337 //      Add extra padding below the text
338         dataHeight = (textHeight + textAddBelow);
339         
340 //      Test to see if data height is tall enough
341         if ( dataHeight < dataMinH ) {
342             dataHeight = dataMinH;
343         }
344         
345 //      Make the buttons, set the titles, and size them to fit their titles
346         okButton     = [[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
347         cancelButton = [[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
348         [okButton     setTarget:target];
349         [cancelButton setTarget:target];
350         [okButton     setAction:okAction];
351         [cancelButton setAction:alternateAction];
352         [okButton     setBezelStyle:ITGrayRoundedBezelStyle];
353         [cancelButton setBezelStyle:ITGrayRoundedBezelStyle];
354         [okButton     setAlignment:NSRightTextAlignment];
355         [cancelButton setAlignment:NSCenterTextAlignment];
356         [okButton     setImagePosition:NSNoImage];
357         [cancelButton setImagePosition:NSNoImage];
358         [okButton     setAttributedTitle:[[[NSAttributedString alloc] initWithString:defaultTitle
359                                                                           attributes:buttonAttr] autorelease]];
360         [cancelButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:alternateTitle
361                                                                           attributes:buttonAttr] autorelease]];
362         [okButton     sizeToFit];
363         [cancelButton sizeToFit];
364         
365 //      Get the button widths.  Add any extra width here.
366         okWidth     = ([okButton     frame].size.width + SW_BUTTON_EXTRA_W);
367         cancelWidth = ([cancelButton frame].size.width + SW_BUTTON_EXTRA_W);
368         
369 //      Figure out which button is wider.
370         wideButtonW = ( (okWidth > cancelWidth) ? okWidth : cancelWidth );
371
372 //      Get the total width of the buttons. Add the divider space.
373         buttonWidth = ( (wideButtonW * 2) + SW_BUTTON_DIV );
374
375 //      Set the dataWidth to whichever is greater: text width or button width.
376         dataWidth = ( (textWidth > buttonWidth) ? textWidth : buttonWidth);
377         
378 //      Setup the window
379         dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
380         
381 //      Set an initial vertical point for the textRect's origin.
382         textY = dataRect.origin.y + textAddBelow;
383         
384 //      Move that point up if the minimimum height of the text area is not occupied.
385         if ( textHeight < textMinH ) {
386             textY += ( (textMinH - textHeight) / 2 );
387         }
388         
389 //      Build the text rect.
390         textRect = NSMakeRect(dataRect.origin.x,
391                               textY,
392                               textWidth,
393                               textHeight);
394         
395 //      Create, position, setup, fill, and add the text view to the content view.
396         textField = [[[ITTextField alloc] initWithFrame:textRect] autorelease];
397         [textField setEditable:NO];
398         [textField setSelectable:NO];
399         [textField setBordered:NO];
400         [textField setDrawsBackground:NO];
401         [textField setFont:font];
402         [textField setTextColor:textColor];
403         [textField setCastsShadow:YES];
404         [textField setStringValue:message];
405         [textField setShadowSaturation:SW_SHADOW_SAT];
406         [[self contentView] addSubview:textField];
407         
408 //      Set the button frames, and add them to the content view.
409         [okButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - (wideButtonW + SW_BUTTON_PAD_R) ),
410                                        SW_BUTTON_PAD_B,
411                                        wideButtonW,
412                                        24.0)];
413         [cancelButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - ((wideButtonW * 2) + SW_BUTTON_DIV + SW_BUTTON_PAD_R) ),
414                                            SW_BUTTON_PAD_B,
415                                            wideButtonW,
416                                            24.0)];
417         [[self contentView] addSubview:okButton];
418         [[self contentView] addSubview:cancelButton];
419
420         [self setIgnoresMouseEvents:NO];
421   
422 //      Display the window.
423         [[self contentView] setNeedsDisplay:YES];
424     }
425 }
426
427
428 @end