1 #import "StatusWindow.h"
7 #define SW_BORDER 32.00
8 #define SW_METER_PAD 4.00
9 #define SW_BUTTON_PAD_R 30.00
10 #define SW_BUTTON_PAD_B 24.00
11 #define SW_BUTTON_DIV 12.00
12 #define SW_BUTTON_EXTRA_W 8.00
13 #define SW_SHADOW_SAT 1.25
15 @interface StatusWindow (Private)
16 - (NSRect)setupWindowWithDataSize:(NSSize)dataSize;
20 @implementation StatusWindow
23 /*************************************************************************/
25 #pragma mark INITIALIZATION / DEALLOCATION METHODS
26 /*************************************************************************/
28 - (id)initWithContentView:(NSView *)contentView
29 exitMode:(ITTransientStatusWindowExitMode)exitMode
30 backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType
32 if ( ( self = [super initWithContentView:contentView
34 backgroundType:backgroundType] ) ) {
35 // Set default values.
36 _image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
38 _sizing = ITTransientStatusWindowRegular;
51 /*************************************************************************/
53 #pragma mark ACCESSOR METHODS
54 /*************************************************************************/
56 - (void)setImage:(NSImage *)newImage
59 _image = [newImage copy];
62 - (void)setLocked:(BOOL)flag
65 [self setExitMode:(flag ? ITTransientStatusWindowExitOnCommand : ITTransientStatusWindowExitAfterDelay)];
68 - (void)setSizing:(ITTransientStatusWindowSizing)newSizing
73 /*************************************************************************/
75 #pragma mark INSTANCE METHODS
76 /*************************************************************************/
78 - (void)appear:(id)sender
81 [super appear:sender];
85 - (void)vanish:(id)sender
88 [super vanish:sender];
92 - (NSRect)setupWindowWithDataSize:(NSSize)dataSize
96 float imageWidth = 0.0;
97 float imageHeight = 0.0;
98 float dataWidth = dataSize.width;
99 float dataHeight = dataSize.height;
100 float contentHeight = 0.0;
101 float windowWidth = 0.0;
102 float windowHeight = 0.0;
103 NSRect visibleFrame = [[self screen] visibleFrame];
104 NSPoint screenOrigin = visibleFrame.origin;
105 float screenWidth = visibleFrame.size.width;
106 float screenHeight = visibleFrame.size.height;
107 float maxWidth = ( screenWidth - (SW_BORDER * 2) );
108 float maxHeight = ( screenHeight - (SW_BORDER * 2) );
109 float excessWidth = 0.0;
110 float excessHeight = 0.0;
111 NSPoint windowOrigin = NSZeroPoint;
112 ITImageView *imageView;
113 BOOL shouldAnimate = ( ! (([self visibilityState] == ITWindowAppearingState) ||
114 ([self visibilityState] == ITWindowVanishingState)) );
116 if ( _sizing == ITTransientStatusWindowSmall ) {
117 divisor = SMALL_DIVISOR;
118 } else if ( _sizing == ITTransientStatusWindowMini ) {
119 divisor = MINI_DIVISOR;
122 // Get image width and height.
123 imageWidth = ( [_image size].width / divisor );
124 imageHeight = ( [_image size].height / divisor );
126 // Set the content height to the greater of the text and image heights.
127 contentHeight = ( ( imageHeight > dataHeight ) ? imageHeight : dataHeight );
129 // Setup the Window, and remove all its contentview's subviews.
130 windowWidth = ( (SW_PAD / divisor) + imageWidth + ((dataWidth > 0) ? (SW_SPACE / divisor) + dataWidth : 0) + (SW_PAD / divisor) );
131 windowHeight = ( (SW_PAD / divisor) + contentHeight + (SW_PAD / divisor) );
133 // Constrain size to max limits. Adjust data sizes accordingly.
134 excessWidth = (windowWidth - maxWidth );
135 excessHeight = (windowHeight - maxHeight);
137 if ( excessWidth > 0.0 ) {
138 windowWidth = maxWidth;
139 dataWidth -= excessWidth;
142 if ( excessHeight > 0.0 ) {
143 windowHeight = maxHeight;
144 dataHeight -= excessHeight;
147 if ( [self horizontalPosition] == ITWindowPositionLeft ) {
148 windowOrigin.x = ( SW_BORDER + screenOrigin.x );
149 } else if ( [self horizontalPosition] == ITWindowPositionCenter ) {
150 windowOrigin.x = ( screenOrigin.x + (screenWidth / 2) - (windowWidth / 2) );
151 } else if ( [self horizontalPosition] == ITWindowPositionRight ) {
152 windowOrigin.x = ( screenOrigin.x + screenWidth - (windowWidth + SW_BORDER) );
155 if ( [self verticalPosition] == ITWindowPositionTop ) {
156 windowOrigin.y = ( screenOrigin.y + screenHeight - (windowHeight + SW_BORDER) );
157 } else if ( [self verticalPosition] == ITWindowPositionMiddle ) {
158 // Middle-oriented windows should be slightly proud of the screen's middle.
159 windowOrigin.y = ( (screenOrigin.y + (screenHeight / 2) - (windowHeight / 2)) + (screenHeight / 8) );
160 } else if ( [self verticalPosition] == ITWindowPositionBottom ) {
161 windowOrigin.y = ( SW_BORDER + screenOrigin.y );
164 [self setFrame:NSMakeRect( windowOrigin.x,
167 windowHeight) display:YES animate:shouldAnimate];
169 [[[self contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
171 // Setup, position, fill, and add the image view to the content view.
172 imageRect = NSMakeRect( (SW_PAD / divisor) + ((dataWidth > 0) ? 4 : 0),
173 ((SW_PAD / divisor) + ((contentHeight - imageHeight) / 2)),
176 imageView = [[[ITImageView alloc] initWithFrame:imageRect] autorelease];
177 [imageView setAutoresizingMask:(NSViewMinYMargin | NSViewMaxYMargin)];
178 [imageView setImage:_image];
179 [imageView setCastsShadow:YES];
180 [[self contentView] addSubview:imageView];
182 return NSMakeRect( ((SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor)),
183 ((SW_PAD / divisor) + ((contentHeight - dataHeight) / 2)),
188 - (void)buildImageWindowWithImage:(NSImage *)image
194 if (_sizing == ITTransientStatusWindowSmall) {
195 divisor = SMALL_DIVISOR;
196 } else if (_sizing == ITTransientStatusWindowMini) {
197 divisor = MINI_DIVISOR;
200 [self setImage:image];
201 dataRect = [self setupWindowWithDataSize:NSMakeSize(0, 0)]; //We have no text, so there is no data
202 [[self contentView] setNeedsDisplay:YES];
206 - (void)buildTextWindowWithString:(id)text
211 float dataWidth = 0.0;
212 float dataHeight = 0.0;
214 NSArray *lines = [(([text isKindOfClass:[NSString class]]) ? text : [text mutableString]) componentsSeparatedByString:@"\n"];
216 NSEnumerator *lineEnum = [lines objectEnumerator];
217 float baseFontSize = 18.0;
218 ITTextField *textField;
222 if ( _sizing == ITTransientStatusWindowSmall ) {
223 divisor = SMALL_DIVISOR;
224 } else if ( _sizing == ITTransientStatusWindowMini ) {
225 divisor = MINI_DIVISOR;
228 font = [NSFont fontWithName:@"LucidaGrande-Bold" size:(baseFontSize / divisor)];
229 attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
231 // Iterate over each line to get text width and height
232 while ( (oneLine = [lineEnum nextObject]) ) {
233 // Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
234 float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
235 // Add the height of this line to the total text height
236 dataHeight += [oneLine sizeWithAttributes:attr].height;
237 // If this line wider than the last one, set it as the text width.
238 dataWidth = ( ( dataWidth > oneLineWidth ) ? dataWidth : oneLineWidth );
241 // Add 4.0 to the final dataHeight to accomodate the shadow.
244 dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
246 // Create, position, setup, fill, and add the text view to the content view.
247 textField = [[[ITTextField alloc] initWithFrame:dataRect] autorelease];
248 [textField setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)];
249 [textField setEditable:NO];
250 [textField setSelectable:NO];
251 [textField setBordered:NO];
252 [textField setDrawsBackground:NO];
253 [textField setFont:font];
254 [textField setTextColor:[NSColor whiteColor]];
255 [textField setCastsShadow:YES];
256 [[textField cell] setWraps:NO];
258 if ([text isKindOfClass:[NSString class]]) {
259 [textField setStringValue:text];
261 [textField setAttributedStringValue:text];
264 [textField setShadowSaturation:SW_SHADOW_SAT];
265 [[self contentView] addSubview:textField];
267 // Display the window.
268 [[self contentView] setNeedsDisplay:YES];
269 _textField = textField;
273 - (void)buildMeterWindowWithCharacter:(NSString *)character
288 NSEnumerator *cellEnum = nil;
291 NSColor *onColor = [NSColor whiteColor];
292 NSColor *offColor = [NSColor colorWithCalibratedWhite:0.15 alpha:0.50];
295 if ( _sizing == ITTransientStatusWindowSmall ) {
296 divisor = SMALL_DIVISOR;
297 } else if ( _sizing == ITTransientStatusWindowMini ) {
298 divisor = MINI_DIVISOR;
301 font = [NSFont fontWithName:@"AppleGothic" size:( size / divisor )];
302 attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
303 charSize = [character sizeWithAttributes:attr];
304 cellHeight = ( charSize.height + 4.0 ); // Add 4.0 for shadow
305 cellWidth = ( (charSize.width) + (SW_METER_PAD / divisor) );
306 dataWidth = ( cellWidth * count );
307 dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, cellHeight)];
308 volMatrix = [[[NSMatrix alloc] initWithFrame:dataRect
309 mode:NSHighlightModeMatrix
310 cellClass:NSClassFromString(@"ITTextFieldCell")
312 numberOfColumns:count] autorelease];
314 [volMatrix setCellSize:NSMakeSize(cellWidth, cellHeight)];
315 [volMatrix setIntercellSpacing:NSMakeSize(0, 0)];
316 [volMatrix setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)];
318 cellEnum = [[volMatrix cells] objectEnumerator];
320 while ( (aCell = [cellEnum nextObject]) ) {
321 [aCell setEditable:NO];
322 [aCell setSelectable:NO];
323 [aCell setBordered:NO];
324 [aCell setDrawsBackground:NO];
325 [aCell setAlignment:NSCenterTextAlignment];
326 [aCell setFont:font];
327 [aCell setStringValue:character];
328 [aCell setShadowSaturation:SW_SHADOW_SAT];
332 if ( active >= activeCount ) {
333 [aCell setCastsShadow:YES];
334 [aCell setTextColor:onColor];
336 [aCell setCastsShadow:NO];
337 [aCell setTextColor:offColor];
342 [[self contentView] addSubview:volMatrix];
343 [[self contentView] setNeedsDisplay:YES];
348 - (void)buildDialogWindowWithMessage:(NSString *)message
349 defaultButton:(NSString *)defaultTitle
350 alternateButton:(NSString *)alternateTitle
352 defaultAction:(SEL)okAction
353 alternateAction:(SEL)alternateAction
358 float textWidth = 0.0;
359 float textHeight = 0.0;
361 float cancelWidth = 0.0;
362 float wideButtonW = 0.0;
363 float buttonWidth = 0.0;
364 float dataHeight = 0.0;
365 float dataWidth = 0.0;
369 float textAddBelow = 32.0;
370 float dataMinH = 92.0;
371 float textMinH = 48.0;
372 NSArray *lines = [message componentsSeparatedByString:@"\n"];
374 NSEnumerator *lineEnum = [lines objectEnumerator];
375 float baseFontSize = 18.0;
376 ITTextField *textField;
378 ITButton *cancelButton;
379 NSColor *textColor = [NSColor whiteColor];
383 NSDictionary *buttonAttr;
385 if ( _sizing == ITTransientStatusWindowSmall ) {
386 divisor = SMALL_DIVISOR;
387 } else if ( _sizing == ITTransientStatusWindowMini ) {
388 divisor = MINI_DIVISOR;
391 font = [NSFont fontWithName:@"LucidaGrande-Bold" size:(baseFontSize / divisor)];
392 attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
393 buttonFont = [NSFont fontWithName:@"LucidaGrande-Bold" size:(14 / divisor)];
394 buttonAttr = [NSDictionary dictionaryWithObjectsAndKeys:
395 buttonFont , NSFontAttributeName,
396 textColor , NSForegroundColorAttributeName,
399 // Iterate over each line to get text width and height
400 while ( (oneLine = [lineEnum nextObject]) ) {
401 // Get the width of one line, adding 8.0 because Apple sucks donkey rectum.
402 float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 );
403 // Add the height of this line to the total text height
404 textHeight += [oneLine sizeWithAttributes:attr].height;
405 // If this line wider than the last one, set it as the text width.
406 textWidth = ( ( textWidth > oneLineWidth ) ? textWidth : oneLineWidth );
409 // Add 4.0 to the final dataHeight to accomodate the shadow.
412 // Add extra padding below the text
413 dataHeight = (textHeight + textAddBelow);
415 // Test to see if data height is tall enough
416 if ( dataHeight < dataMinH ) {
417 dataHeight = dataMinH;
420 // Make the buttons, set the titles, and size them to fit their titles
421 okButton = [[[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)] autorelease];
422 cancelButton = [[[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)] autorelease];
423 [okButton setTarget:target];
424 [cancelButton setTarget:target];
425 [okButton setAction:okAction];
426 [cancelButton setAction:alternateAction];
427 [okButton setBezelStyle:ITGrayRoundedBezelStyle];
428 [cancelButton setBezelStyle:ITGrayRoundedBezelStyle];
429 [okButton setAlignment:NSRightTextAlignment];
430 [cancelButton setAlignment:NSCenterTextAlignment];
431 [okButton setImagePosition:NSNoImage];
432 [cancelButton setImagePosition:NSNoImage];
433 [okButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:defaultTitle
434 attributes:buttonAttr] autorelease]];
435 [cancelButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:alternateTitle
436 attributes:buttonAttr] autorelease]];
437 [okButton sizeToFit];
438 [cancelButton sizeToFit];
440 // Get the button widths. Add any extra width here.
441 okWidth = ([okButton frame].size.width + SW_BUTTON_EXTRA_W);
442 cancelWidth = ([cancelButton frame].size.width + SW_BUTTON_EXTRA_W);
444 // Figure out which button is wider.
445 wideButtonW = ( (okWidth > cancelWidth) ? okWidth : cancelWidth );
447 // Get the total width of the buttons. Add the divider space.
448 buttonWidth = ( (wideButtonW * 2) + SW_BUTTON_DIV );
450 // Set the dataWidth to whichever is greater: text width or button width.
451 dataWidth = ( (textWidth > buttonWidth) ? textWidth : buttonWidth);
454 dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)];
456 // Set an initial vertical point for the textRect's origin.
457 textY = dataRect.origin.y + textAddBelow;
459 // Move that point up if the minimimum height of the text area is not occupied.
460 if ( textHeight < textMinH ) {
461 textY += ( (textMinH - textHeight) / 2 );
464 // Build the text rect.
465 textRect = NSMakeRect(dataRect.origin.x,
470 // Create, position, setup, fill, and add the text view to the content view.
471 textField = [[[ITTextField alloc] initWithFrame:textRect] autorelease];
472 [textField setEditable:NO];
473 [textField setSelectable:NO];
474 [textField setBordered:NO];
475 [textField setDrawsBackground:NO];
476 [textField setFont:font];
477 [textField setTextColor:textColor];
478 [textField setCastsShadow:YES];
479 [textField setStringValue:message];
480 [textField setShadowSaturation:SW_SHADOW_SAT];
481 [[self contentView] addSubview:textField];
483 // Set the button frames, and add them to the content view.
484 [okButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - (wideButtonW + SW_BUTTON_PAD_R) ),
488 [cancelButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - ((wideButtonW * 2) + SW_BUTTON_DIV + SW_BUTTON_PAD_R) ),
492 [[self contentView] addSubview:okButton];
493 if (alternateTitle) {
494 [[self contentView] addSubview:cancelButton];
497 [self setIgnoresMouseEvents:NO];
499 // Display the window.
500 [[self contentView] setNeedsDisplay:YES];
504 - (void)updateTime:(NSString *)time range:(NSRange)range
506 NSMutableAttributedString *string = [[_textField attributedStringValue] mutableCopy];
507 [string replaceCharactersInRange:range withString:time];
508 [_textField setAttributedStringValue:[string autorelease]];
509 [[self contentView] setNeedsDisplay:YES];
512 - (NSTimeInterval)animationResizeTime:(NSRect)newFrame
514 return (NSTimeInterval)0.25;