X-Git-Url: http://git.ithinksw.org/MenuTunes.git/blobdiff_plain/ef4f5a3e753596396e93ba33b7e2ab5e8b53c5d8..4ceec63fa54ca0281b26107bcfc78617c9854d4c:/StatusWindow.m diff --git a/StatusWindow.m b/StatusWindow.m index a2a223a..94ca616 100755 --- a/StatusWindow.m +++ b/StatusWindow.m @@ -1,122 +1,517 @@ -// -// StatusWindow.m -// MenuTunes -// -// Created by Matt L. Judy on Sat Feb 22 2003. -// Copyright (c) 2003 NibFile.com. All rights reserved. -// - #import "StatusWindow.h" +#define SW_PAD 24.00 +#define SW_SPACE 24.00 +#define SW_MINW 211.00 +#define SW_BORDER 32.00 +#define SW_METER_PAD 4.00 +#define SW_BUTTON_PAD_R 30.00 +#define SW_BUTTON_PAD_B 24.00 +#define SW_BUTTON_DIV 12.00 +#define SW_BUTTON_EXTRA_W 8.00 +#define SW_SHADOW_SAT 1.25 + @interface StatusWindow (Private) -- (void)buildStatusWindow; +- (NSRect)setupWindowWithDataSize:(NSSize)dataSize; @end @implementation StatusWindow + +/*************************************************************************/ +#pragma mark - +#pragma mark INITIALIZATION / DEALLOCATION METHODS +/*************************************************************************/ + - (id)initWithContentView:(NSView *)contentView exitMode:(ITTransientStatusWindowExitMode)exitMode backgroundType:(ITTransientStatusWindowBackgroundType)backgroundType { if ( ( self = [super initWithContentView:contentView exitMode:exitMode - backgroundType:backgroundType]) ) { - // Default images and text. - image = [NSImage imageNamed:@"NSApplicationIcon"]; - text = @"No string set yet."; - [self buildStatusWindow]; + backgroundType:backgroundType] ) ) { + // Set default values. + _image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + _locked = NO; + _sizing = ITTransientStatusWindowRegular; } + return self; } -- (void)buildStatusWindow +- (void)dealloc +{ + [_image release]; + [super dealloc]; +} + + +/*************************************************************************/ +#pragma mark - +#pragma mark ACCESSOR METHODS +/*************************************************************************/ + +- (void)setImage:(NSImage *)newImage +{ + [_image autorelease]; + _image = [newImage copy]; +} + +- (void)setLocked:(BOOL)flag { - NSRect imageRect; - NSRect textRect; - float imageWidth = 0.0; - float imageHeight = 0.0; - float textWidth = 0.0; - float textHeight = 0.0; - float contentHeight = 0.0; - float windowWidth = 0.0; - float windowHeight = 0.0; - NSArray *lines = [text componentsSeparatedByString:@"\n"]; - id oneLine = nil; - NSEnumerator *lineEnum = [lines objectEnumerator]; - NSFont *font = [NSFont fontWithName:@"Lucida Grande Bold" size:18]; - NSDictionary *attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; + _locked = flag; + [self setExitMode:(flag ? ITTransientStatusWindowExitOnCommand : ITTransientStatusWindowExitAfterDelay)]; +} + +- (void)setSizing:(ITTransientStatusWindowSizing)newSizing +{ + _sizing = newSizing; +} + +/*************************************************************************/ +#pragma mark - +#pragma mark INSTANCE METHODS +/*************************************************************************/ + +- (void)appear:(id)sender +{ + if ( ! _locked ) { + [super appear:sender]; + } +} + +- (void)vanish:(id)sender +{ + if ( ! _locked ) { + [super vanish:sender]; + } +} + +- (NSRect)setupWindowWithDataSize:(NSSize)dataSize +{ + float divisor = 1.0; + NSRect imageRect; + float imageWidth = 0.0; + float imageHeight = 0.0; + float dataWidth = dataSize.width; + float dataHeight = dataSize.height; + float contentHeight = 0.0; + float windowWidth = 0.0; + float windowHeight = 0.0; + NSRect visibleFrame = [[self screen] visibleFrame]; + NSPoint screenOrigin = visibleFrame.origin; + float screenWidth = visibleFrame.size.width; + float screenHeight = visibleFrame.size.height; + float maxWidth = ( screenWidth - (SW_BORDER * 2) ); + float maxHeight = ( screenHeight - (SW_BORDER * 2) ); + float excessWidth = 0.0; + float excessHeight = 0.0; + NSPoint windowOrigin = NSZeroPoint; + ITImageView *imageView; + BOOL shouldAnimate = ( ! (([self visibilityState] == ITWindowAppearingState) || + ([self visibilityState] == ITWindowVanishingState)) ); + + if ( _sizing == ITTransientStatusWindowSmall ) { + divisor = SMALL_DIVISOR; + } else if ( _sizing == ITTransientStatusWindowMini ) { + divisor = MINI_DIVISOR; + } + +// Get image width and height. + imageWidth = ( [_image size].width / divisor ); + imageHeight = ( [_image size].height / divisor ); - // Get image width and height. - imageWidth = [image size].width; - imageHeight = [image size].height; +// Set the content height to the greater of the text and image heights. + contentHeight = ( ( imageHeight > dataHeight ) ? imageHeight : dataHeight ); + +// Setup the Window, and remove all its contentview's subviews. + windowWidth = ( (SW_PAD / divisor) + imageWidth + ((dataWidth > 0) ? (SW_SPACE / divisor) + dataWidth : 0) + (SW_PAD / divisor) ); + windowHeight = ( (SW_PAD / divisor) + contentHeight + (SW_PAD / divisor) ); - // Iterate over each line to get text width and height - while ( (oneLine = [lineEnum nextObject]) ) { - // Get the width of one line, adding 8.0 because Apple sucks donkey rectum. - float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 ); - // Add the height of this line to the total text height - textHeight += [oneLine sizeWithAttributes:attr].height; - // If this line wider than the last one, set it as the text width. - textWidth = ( ( textWidth > oneLineWidth ) ? textWidth : oneLineWidth ); +// Constrain size to max limits. Adjust data sizes accordingly. + excessWidth = (windowWidth - maxWidth ); + excessHeight = (windowHeight - maxHeight); + + if ( excessWidth > 0.0 ) { + windowWidth = maxWidth; + dataWidth -= excessWidth; } - // Add 4.0 to the final textHeight to accomodate the shadow. - textHeight += 4.0; + if ( excessHeight > 0.0 ) { + windowHeight = maxHeight; + dataHeight -= excessHeight; + } - // Set the content height to the greater of the text and image heights. - contentHeight = ( ( imageHeight > textHeight ) ? imageHeight : textHeight ); + if ( [self horizontalPosition] == ITWindowPositionLeft ) { + windowOrigin.x = ( SW_BORDER + screenOrigin.x ); + } else if ( [self horizontalPosition] == ITWindowPositionCenter ) { + windowOrigin.x = ( screenOrigin.x + (screenWidth / 2) - (windowWidth / 2) ); + } else if ( [self horizontalPosition] == ITWindowPositionRight ) { + windowOrigin.x = ( screenOrigin.x + screenWidth - (windowWidth + SW_BORDER) ); + } - // Setup the Window, and remove all its contentview's subviews. - windowWidth = ( SW_PAD + imageWidth + SW_SPACE + textWidth + SW_PAD ); - windowHeight = ( SW_PAD + contentHeight + SW_PAD ); - [self setFrame:NSMakeRect(SW_BORDER, SW_BORDER, windowWidth, windowHeight) display:YES]; + if ( [self verticalPosition] == ITWindowPositionTop ) { + windowOrigin.y = ( screenOrigin.y + screenHeight - (windowHeight + SW_BORDER) ); + } else if ( [self verticalPosition] == ITWindowPositionMiddle ) { +// Middle-oriented windows should be slightly proud of the screen's middle. + windowOrigin.y = ( (screenOrigin.y + (screenHeight / 2) - (windowHeight / 2)) + (screenHeight / 8) ); + } else if ( [self verticalPosition] == ITWindowPositionBottom ) { + windowOrigin.y = ( SW_BORDER + screenOrigin.y ); + } + + [self setFrame:NSMakeRect( windowOrigin.x, + windowOrigin.y, + windowWidth, + windowHeight) display:YES animate:shouldAnimate]; + [[[self contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; - // Setup, position, fill, and add the image view to the content view. - imageRect = NSMakeRect( SW_PAD, - (SW_PAD + ((contentHeight - imageHeight) / 2)), +// Setup, position, fill, and add the image view to the content view. + imageRect = NSMakeRect( (SW_PAD / divisor) + ((dataWidth > 0) ? 4 : 0), + ((SW_PAD / divisor) + ((contentHeight - imageHeight) / 2)), imageWidth, imageHeight ); - imageView = [[[NSImageView alloc] initWithFrame:imageRect] autorelease]; - [imageView setImage:image]; + imageView = [[[ITImageView alloc] initWithFrame:imageRect] autorelease]; + [imageView setAutoresizingMask:(NSViewMinYMargin | NSViewMaxYMargin)]; + [imageView setImage:_image]; + [imageView setCastsShadow:YES]; [[self contentView] addSubview:imageView]; - - // Setup, position, fill, and add the text view to the content view. - textRect = NSMakeRect( (SW_PAD + imageWidth + SW_SPACE), - (SW_PAD + ((contentHeight - textHeight) / 2)), - textWidth, - textHeight); - textField = [[[ITTextField alloc] initWithFrame:textRect] autorelease]; - [textField setEditable:NO]; - [textField setSelectable:NO]; - [textField setBordered:NO]; - [textField setDrawsBackground:NO]; - [textField setFont:[NSFont fontWithName:@"Lucida Grande Bold" size:18]]; - [textField setTextColor:[NSColor whiteColor]]; - [textField setCastsShadow:YES]; - [textField setStringValue:text]; - [[self contentView] addSubview:textField]; - - [[self contentView] setNeedsDisplay:YES]; - + + return NSMakeRect( ((SW_PAD / divisor) + imageWidth + (SW_SPACE / divisor)), + ((SW_PAD / divisor) + ((contentHeight - dataHeight) / 2)), + dataWidth, + dataHeight); } -- (void)setImage:(NSImage *)newImage +- (void)buildImageWindowWithImage:(NSImage *)image +{ + if (!_locked) { + float divisor = 1.0; + NSRect dataRect; + + if (_sizing == ITTransientStatusWindowSmall) { + divisor = SMALL_DIVISOR; + } else if (_sizing == ITTransientStatusWindowMini) { + divisor = MINI_DIVISOR; + } + + [self setImage:image]; + dataRect = [self setupWindowWithDataSize:NSMakeSize(0, 0)]; //We have no text, so there is no data + [[self contentView] setNeedsDisplay:YES]; + } +} + +- (void)buildTextWindowWithString:(id)text +{ + if ( ! _locked ) { + + float divisor = 1.0; + float dataWidth = 0.0; + float dataHeight = 0.0; + NSRect dataRect; + NSArray *lines = [(([text isKindOfClass:[NSString class]]) ? text : [text mutableString]) componentsSeparatedByString:@"\n"]; + id oneLine = nil; + NSEnumerator *lineEnum = [lines objectEnumerator]; + float baseFontSize = 18.0; + ITTextField *textField; + NSFont *font; + NSDictionary *attr; + + if ( _sizing == ITTransientStatusWindowSmall ) { + divisor = SMALL_DIVISOR; + } else if ( _sizing == ITTransientStatusWindowMini ) { + divisor = MINI_DIVISOR; + } + + font = [NSFont fontWithName:@"LucidaGrande-Bold" size:(baseFontSize / divisor)]; + attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; + +// Iterate over each line to get text width and height + while ( (oneLine = [lineEnum nextObject]) ) { +// Get the width of one line, adding 8.0 because Apple sucks donkey rectum. + float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 ); +// Add the height of this line to the total text height + dataHeight += [oneLine sizeWithAttributes:attr].height; +// If this line wider than the last one, set it as the text width. + dataWidth = ( ( dataWidth > oneLineWidth ) ? dataWidth : oneLineWidth ); + } + +// Add 4.0 to the final dataHeight to accomodate the shadow. + dataHeight += 4.0; + + dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)]; + +// Create, position, setup, fill, and add the text view to the content view. + textField = [[[ITTextField alloc] initWithFrame:dataRect] autorelease]; + [textField setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; + [textField setEditable:NO]; + [textField setSelectable:NO]; + [textField setBordered:NO]; + [textField setDrawsBackground:NO]; + [textField setFont:font]; + [textField setTextColor:[NSColor whiteColor]]; + [textField setCastsShadow:YES]; + [[textField cell] setWraps:NO]; + + if ([text isKindOfClass:[NSString class]]) { + [textField setStringValue:text]; + } else { + [textField setAttributedStringValue:text]; + } + + [textField setShadowSaturation:SW_SHADOW_SAT]; + [[self contentView] addSubview:textField]; + +// Display the window. + [[self contentView] setNeedsDisplay:YES]; + _textField = textField; + } +} + +- (void)buildMeterWindowWithCharacter:(NSString *)character + size:(float)size + count:(int)count + active:(int)active { - [image autorelease]; - image = [newImage copy]; - [self buildStatusWindow]; + if ( ! _locked ) { + + float divisor = 1.0; + NSFont *font; + NSDictionary *attr; + NSSize charSize; + float cellHeight; + float cellWidth; + float dataWidth; + NSRect dataRect; + NSEnumerator *cellEnum = nil; + id aCell = nil; + int activeCount = 0; + NSColor *onColor = [NSColor whiteColor]; + NSColor *offColor = [NSColor colorWithCalibratedWhite:0.15 alpha:0.50]; + NSMatrix *volMatrix; + + if ( _sizing == ITTransientStatusWindowSmall ) { + divisor = SMALL_DIVISOR; + } else if ( _sizing == ITTransientStatusWindowMini ) { + divisor = MINI_DIVISOR; + } + + font = [NSFont fontWithName:@"AppleGothic" size:( size / divisor )]; + attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; + charSize = [character sizeWithAttributes:attr]; + cellHeight = ( charSize.height + 4.0 ); // Add 4.0 for shadow + cellWidth = ( (charSize.width) + (SW_METER_PAD / divisor) ); + dataWidth = ( cellWidth * count ); + dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, cellHeight)]; + volMatrix = [[[NSMatrix alloc] initWithFrame:dataRect + mode:NSHighlightModeMatrix + cellClass:NSClassFromString(@"ITTextFieldCell") + numberOfRows:1 + numberOfColumns:count] autorelease]; + + [volMatrix setCellSize:NSMakeSize(cellWidth, cellHeight)]; + [volMatrix setIntercellSpacing:NSMakeSize(0, 0)]; + [volMatrix setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; + + cellEnum = [[volMatrix cells] objectEnumerator]; + + while ( (aCell = [cellEnum nextObject]) ) { + [aCell setEditable:NO]; + [aCell setSelectable:NO]; + [aCell setBordered:NO]; + [aCell setDrawsBackground:NO]; + [aCell setAlignment:NSCenterTextAlignment]; + [aCell setFont:font]; + [aCell setStringValue:character]; + [aCell setShadowSaturation:SW_SHADOW_SAT]; + + activeCount ++; + + if ( active >= activeCount ) { + [aCell setCastsShadow:YES]; + [aCell setTextColor:onColor]; + } else { + [aCell setCastsShadow:NO]; + [aCell setTextColor:offColor]; + } + + } + + [[self contentView] addSubview:volMatrix]; + [[self contentView] setNeedsDisplay:YES]; + + } } -- (void)setText:(NSString *)newText +- (void)buildDialogWindowWithMessage:(NSString *)message + defaultButton:(NSString *)defaultTitle + alternateButton:(NSString *)alternateTitle + target:(id)target + defaultAction:(SEL)okAction + alternateAction:(SEL)alternateAction { - [text autorelease]; - text = [newText copy]; - [self buildStatusWindow]; + if ( ! _locked ) { + + float divisor = 1.0; + float textWidth = 0.0; + float textHeight = 0.0; + float okWidth = 0.0; + float cancelWidth = 0.0; + float wideButtonW = 0.0; + float buttonWidth = 0.0; + float dataHeight = 0.0; + float dataWidth = 0.0; + NSRect dataRect; + float textY = 0.0; + NSRect textRect; + float textAddBelow = 32.0; + float dataMinH = 92.0; + float textMinH = 48.0; + NSArray *lines = [message componentsSeparatedByString:@"\n"]; + id oneLine = nil; + NSEnumerator *lineEnum = [lines objectEnumerator]; + float baseFontSize = 18.0; + ITTextField *textField; + ITButton *okButton; + ITButton *cancelButton; + NSColor *textColor = [NSColor whiteColor]; + NSFont *font; + NSDictionary *attr; + NSFont *buttonFont; + NSDictionary *buttonAttr; + + if ( _sizing == ITTransientStatusWindowSmall ) { + divisor = SMALL_DIVISOR; + } else if ( _sizing == ITTransientStatusWindowMini ) { + divisor = MINI_DIVISOR; + } + + font = [NSFont fontWithName:@"LucidaGrande-Bold" size:(baseFontSize / divisor)]; + attr = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; + buttonFont = [NSFont fontWithName:@"LucidaGrande-Bold" size:(14 / divisor)]; + buttonAttr = [NSDictionary dictionaryWithObjectsAndKeys: + buttonFont , NSFontAttributeName, + textColor , NSForegroundColorAttributeName, + nil]; + +// Iterate over each line to get text width and height + while ( (oneLine = [lineEnum nextObject]) ) { +// Get the width of one line, adding 8.0 because Apple sucks donkey rectum. + float oneLineWidth = ( [oneLine sizeWithAttributes:attr].width + 8.0 ); +// Add the height of this line to the total text height + textHeight += [oneLine sizeWithAttributes:attr].height; +// If this line wider than the last one, set it as the text width. + textWidth = ( ( textWidth > oneLineWidth ) ? textWidth : oneLineWidth ); + } + +// Add 4.0 to the final dataHeight to accomodate the shadow. + textHeight += 4.0; + +// Add extra padding below the text + dataHeight = (textHeight + textAddBelow); + +// Test to see if data height is tall enough + if ( dataHeight < dataMinH ) { + dataHeight = dataMinH; + } + +// Make the buttons, set the titles, and size them to fit their titles + okButton = [[[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)] autorelease]; + cancelButton = [[[ITButton alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)] autorelease]; + [okButton setTarget:target]; + [cancelButton setTarget:target]; + [okButton setAction:okAction]; + [cancelButton setAction:alternateAction]; + [okButton setBezelStyle:ITGrayRoundedBezelStyle]; + [cancelButton setBezelStyle:ITGrayRoundedBezelStyle]; + [okButton setAlignment:NSRightTextAlignment]; + [cancelButton setAlignment:NSCenterTextAlignment]; + [okButton setImagePosition:NSNoImage]; + [cancelButton setImagePosition:NSNoImage]; + [okButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:defaultTitle + attributes:buttonAttr] autorelease]]; + [cancelButton setAttributedTitle:[[[NSAttributedString alloc] initWithString:alternateTitle + attributes:buttonAttr] autorelease]]; + [okButton sizeToFit]; + [cancelButton sizeToFit]; + +// Get the button widths. Add any extra width here. + okWidth = ([okButton frame].size.width + SW_BUTTON_EXTRA_W); + cancelWidth = ([cancelButton frame].size.width + SW_BUTTON_EXTRA_W); + +// Figure out which button is wider. + wideButtonW = ( (okWidth > cancelWidth) ? okWidth : cancelWidth ); + +// Get the total width of the buttons. Add the divider space. + buttonWidth = ( (wideButtonW * 2) + SW_BUTTON_DIV ); + +// Set the dataWidth to whichever is greater: text width or button width. + dataWidth = ( (textWidth > buttonWidth) ? textWidth : buttonWidth); + +// Setup the window + dataRect = [self setupWindowWithDataSize:NSMakeSize(dataWidth, dataHeight)]; + +// Set an initial vertical point for the textRect's origin. + textY = dataRect.origin.y + textAddBelow; + +// Move that point up if the minimimum height of the text area is not occupied. + if ( textHeight < textMinH ) { + textY += ( (textMinH - textHeight) / 2 ); + } + +// Build the text rect. + textRect = NSMakeRect(dataRect.origin.x, + textY, + textWidth, + textHeight); + +// Create, position, setup, fill, and add the text view to the content view. + textField = [[[ITTextField alloc] initWithFrame:textRect] autorelease]; + [textField setEditable:NO]; + [textField setSelectable:NO]; + [textField setBordered:NO]; + [textField setDrawsBackground:NO]; + [textField setFont:font]; + [textField setTextColor:textColor]; + [textField setCastsShadow:YES]; + [textField setStringValue:message]; + [textField setShadowSaturation:SW_SHADOW_SAT]; + [[self contentView] addSubview:textField]; + +// Set the button frames, and add them to the content view. + [okButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - (wideButtonW + SW_BUTTON_PAD_R) ), + SW_BUTTON_PAD_B, + wideButtonW, + 24.0)]; + [cancelButton setFrame:NSMakeRect( ([[self contentView] frame].size.width - ((wideButtonW * 2) + SW_BUTTON_DIV + SW_BUTTON_PAD_R) ), + SW_BUTTON_PAD_B, + wideButtonW, + 24.0)]; + [[self contentView] addSubview:okButton]; + if (alternateTitle) { + [[self contentView] addSubview:cancelButton]; + } + + [self setIgnoresMouseEvents:NO]; + +// Display the window. + [[self contentView] setNeedsDisplay:YES]; + } } +- (void)updateTime:(NSString *)time range:(NSRange)range +{ + NSMutableAttributedString *string = [[_textField attributedStringValue] mutableCopy]; + [string replaceCharactersInRange:range withString:time]; + [_textField setAttributedStringValue:[string autorelease]]; + [[self contentView] setNeedsDisplay:YES]; +} +- (NSTimeInterval)animationResizeTime:(NSRect)newFrame +{ + return (NSTimeInterval)0.25; +} @end