// // PSMOverflowPopUpButton.m // PSMTabBarControl // // Created by John Pannell on 11/4/05. // Copyright 2005 Positive Spin Media. All rights reserved. // #import "PSMOverflowPopUpButton.h" #import "PSMTabBarControl.h" #define TIMER_INTERVAL 1.0 / 15.0 #define ANIMATION_STEP 0.033f @implementation PSMOverflowPopUpButton - (id)initWithFrame:(NSRect)frameRect pullsDown:(BOOL)flag { if ((self = [super initWithFrame:frameRect pullsDown:YES]) != nil) { [self setBezelStyle:NSRegularSquareBezelStyle]; [self setBordered:NO]; [self setTitle:@""]; [self setPreferredEdge:NSMaxXEdge]; _PSMTabBarOverflowPopUpImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"overflowImage"]]; _PSMTabBarOverflowDownPopUpImage = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"overflowImagePressed"]]; _animatingAlternateImage = NO; } return self; } - (void)dealloc { [_PSMTabBarOverflowPopUpImage release]; [_PSMTabBarOverflowDownPopUpImage release]; [super dealloc]; } - (void)drawRect:(NSRect)rect { if(_PSMTabBarOverflowPopUpImage == nil) { [super drawRect:rect]; return; } NSImage *image = (_down) ? _PSMTabBarOverflowDownPopUpImage : _PSMTabBarOverflowPopUpImage; NSSize imageSize = [image size]; NSRect bounds = [self bounds]; NSPoint drawPoint = NSMakePoint(NSMidX(bounds) - (imageSize.width * 0.5f), NSMidY(bounds) - (imageSize.height * 0.5f)); if([self isFlipped]) { drawPoint.y += imageSize.height; } [image compositeToPoint:drawPoint operation:NSCompositeSourceOver fraction:(_animatingAlternateImage ? 0.7f : 1.0f)]; if(_animatingAlternateImage) { NSImage *alternateImage = [self alternateImage]; NSSize altImageSize = [alternateImage size]; drawPoint = NSMakePoint(NSMidX(bounds) - (altImageSize.width * 0.5f), NSMidY(bounds) - (altImageSize.height * 0.5f)); if([self isFlipped]) { drawPoint.y += altImageSize.height; } [[self alternateImage] compositeToPoint:drawPoint operation:NSCompositeSourceOver fraction:sin(_animationValue * M_PI)]; } } - (void)mouseDown:(NSEvent *)event { _down = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationReceived:) name:NSMenuDidEndTrackingNotification object:[self menu]]; [self setNeedsDisplay:YES]; [super mouseDown:event]; } - (void)setHidden:(BOOL)value { if([self isHidden] != value) { if(value) { // Stop any animating alternate image if we hide [_animationTimer invalidate], _animationTimer = nil; } else if(_animatingAlternateImage) { // Restart any animating alternate image if we unhide _animationValue = ANIMATION_STEP; _animationTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(animateStep:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode]; } } [super setHidden:value]; } - (void)notificationReceived:(NSNotification *)notification { _down = NO; [self setNeedsDisplay:YES]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)setAnimatingAlternateImage:(BOOL)flag { if(_animatingAlternateImage != flag) { _animatingAlternateImage = flag; if(![self isHidden]) { if(flag) { _animationValue = ANIMATION_STEP; _animationTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(animateStep:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode]; } else { [_animationTimer invalidate], _animationTimer = nil; } [self setNeedsDisplay:YES]; } } } - (BOOL)animatingAlternateImage; { return _animatingAlternateImage; } - (void)animateStep:(NSTimer *)timer { _animationValue += ANIMATION_STEP; if(_animationValue >= 1) { _animationValue = ANIMATION_STEP; } [self setNeedsDisplay:YES]; } #pragma mark - #pragma mark Archiving - (void)encodeWithCoder:(NSCoder *)aCoder { [super encodeWithCoder:aCoder]; if([aCoder allowsKeyedCoding]) { [aCoder encodeObject:_PSMTabBarOverflowPopUpImage forKey:@"PSMTabBarOverflowPopUpImage"]; [aCoder encodeObject:_PSMTabBarOverflowDownPopUpImage forKey:@"PSMTabBarOverflowDownPopUpImage"]; [aCoder encodeBool:_animatingAlternateImage forKey:@"PSMTabBarOverflowAnimatingAlternateImage"]; } } - (id)initWithCoder:(NSCoder *)aDecoder { if((self = [super initWithCoder:aDecoder])) { if([aDecoder allowsKeyedCoding]) { _PSMTabBarOverflowPopUpImage = [[aDecoder decodeObjectForKey:@"PSMTabBarOverflowPopUpImage"] retain]; _PSMTabBarOverflowDownPopUpImage = [[aDecoder decodeObjectForKey:@"PSMTabBarOverflowDownPopUpImage"] retain]; [self setAnimatingAlternateImage:[aDecoder decodeBoolForKey:@"PSMTabBarOverflowAnimatingAlternateImage"]]; } } return self; } @end