diff options
Diffstat (limited to 'frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m')
-rw-r--r-- | frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m | 1995 |
1 files changed, 0 insertions, 1995 deletions
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m b/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m deleted file mode 100644 index cb0e0342c..000000000 --- a/frontends/cocoa/PSMTabBarControl/PSMTabBarControl.m +++ /dev/null @@ -1,1995 +0,0 @@ -// -// PSMTabBarControl.m -// PSMTabBarControl -// -// Created by John Pannell on 10/13/05. -// Copyright 2005 Positive Spin Media. All rights reserved. -// - -#import <objc/runtime.h> - -#import "PSMTabBarControl.h" -#import "PSMTabBarCell.h" -#import "PSMOverflowPopUpButton.h" -#import "PSMRolloverButton.h" -#import "PSMTabStyle.h" -#import "PSMUnifiedTabStyle.h" -#import "PSMTabDragAssistant.h" -#import "PSMTabBarController.h" - -@interface PSMTabBarControl (Private) - -// constructor/destructor -- (void)initAddedProperties; - -// accessors -- (NSEvent *)lastMouseDownEvent; -- (void)setLastMouseDownEvent:(NSEvent *)event; - -// contents -- (void)addTabViewItem:(NSTabViewItem *)item; -- (void)removeTabForCell:(PSMTabBarCell *)cell; - -// draw -- (void)update; -- (void)update:(BOOL)animate; -- (void)_setupTrackingRectsForCell:(PSMTabBarCell *)cell; -- (void)_positionOverflowMenu; -- (void)_checkWindowFrame; - -// actions -- (void)overflowMenuAction:(id)sender; -- (void)closeTabClick:(id)sender; -- (void)tabClick:(id)sender; -- (void)tabNothing:(id)sender; - -// notification handlers -- (void)frameDidChange:(NSNotification *)notification; -- (void)windowDidMove:(NSNotification *)aNotification; -- (void)windowDidUpdate:(NSNotification *)notification; - -// NSTabView delegate -- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem; -- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem; -- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem; -- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)tabView; - -// archiving -- (void)encodeWithCoder:(NSCoder *)aCoder; -- (id)initWithCoder:(NSCoder *)aDecoder; - -// convenience -- (void)_bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item; -- (id)cellForPoint:(NSPoint)point cellFrame:(NSRectPointer)outFrame; - -- (void)_animateCells:(NSTimer *)timer; -@end - -@implementation PSMTabBarControl - -#pragma mark - -#pragma mark Characteristics - -+ (NSBundle *)bundle -{ - static NSBundle *bundle = nil; - if(!bundle) { - bundle = [NSBundle bundleForClass:[PSMTabBarControl class]]; - } - return bundle; -} - -/*! - @method availableCellWidth - @abstract The number of pixels available for cells - @discussion Calculates the number of pixels available for cells based on margins and the window resize badge. - @returns Returns the amount of space for cells. - */ - -- (CGFloat)availableCellWidth { - return [self frame].size.width - [style leftMarginForTabBarControl] - [style rightMarginForTabBarControl] - _resizeAreaCompensation; -} - -/*! - @method genericCellRect - @abstract The basic rect for a tab cell. - @discussion Creates a generic frame for a tab cell based on the current control state. - @returns Returns a basic rect for a tab cell. - */ - -- (NSRect)genericCellRect { - NSRect aRect = [self frame]; - aRect.origin.x = [style leftMarginForTabBarControl]; - aRect.origin.y = 0.0; - aRect.size.width = [self availableCellWidth]; - aRect.size.height = [style tabCellHeight]; - return aRect; -} - -#pragma mark - -#pragma mark Constructor/destructor - -- (void)initAddedProperties { - _cells = [[NSMutableArray alloc] initWithCapacity:10]; - _controller = [[PSMTabBarController alloc] initWithTabBarControl:self]; - _animationTimer = nil; - - // default config - _currentStep = kPSMIsNotBeingResized; - _orientation = PSMTabBarHorizontalOrientation; - _canCloseOnlyTab = NO; - _disableTabClose = NO; - _showAddTabButton = NO; - _hideForSingleTab = NO; - _sizeCellsToFit = NO; - _isHidden = NO; - _awakenedFromNib = NO; - _automaticallyAnimates = NO; - _useOverflowMenu = YES; - _allowsBackgroundTabClosing = YES; - _allowsResizing = NO; - _selectsTabsOnMouseDown = NO; - _alwaysShowActiveTab = NO; - _allowsScrubbing = NO; - _cellMinWidth = 100; - _cellMaxWidth = 280; - _cellOptimumWidth = 130; - _tearOffStyle = PSMTabBarTearOffAlphaWindow; - style = [[[[self class] defaultStyleClass] alloc] init]; - - // the overflow button/menu - NSRect overflowButtonRect = NSMakeRect([self frame].size.width - [style rightMarginForTabBarControl] + 1, 0, [style rightMarginForTabBarControl] - 1, [self frame].size.height); - _overflowPopUpButton = [[PSMOverflowPopUpButton alloc] initWithFrame:overflowButtonRect pullsDown:YES]; - [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin]; - [_overflowPopUpButton setHidden:YES]; - [self addSubview:_overflowPopUpButton]; - [self _positionOverflowMenu]; - - // new tab button - NSRect addTabButtonRect = NSMakeRect([self frame].size.width - [style rightMarginForTabBarControl] + 1, 3.0, 16.0, 16.0); - _addTabButton = [[PSMRolloverButton alloc] initWithFrame:addTabButtonRect]; - if(_addTabButton) { - NSImage *newButtonImage = [style addTabButtonImage]; - if(newButtonImage) { - [_addTabButton setUsualImage:newButtonImage]; - } - newButtonImage = [style addTabButtonPressedImage]; - if(newButtonImage) { - [_addTabButton setAlternateImage:newButtonImage]; - } - newButtonImage = [style addTabButtonRolloverImage]; - if(newButtonImage) { - [_addTabButton setRolloverImage:newButtonImage]; - } - [_addTabButton setTitle:@""]; - [_addTabButton setImagePosition:NSImageOnly]; - [_addTabButton setButtonType:NSMomentaryChangeButton]; - [_addTabButton setBordered:NO]; - [_addTabButton setBezelStyle:NSShadowlessSquareBezelStyle]; - [self addSubview:_addTabButton]; - - if(_showAddTabButton) { - [_addTabButton setHidden:NO]; - } else { - [_addTabButton setHidden:YES]; - } - [_addTabButton setNeedsDisplay:YES]; - } -} - -+ (Class) defaultStyleClass -{ - return [PSMUnifiedTabStyle class]; -} - -- (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; - if(self) { - // Initialization - [self initAddedProperties]; - [self registerForDraggedTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil]]; - - // resize - [self setPostsFrameChangedNotifications:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frameDidChange:) name:NSViewFrameDidChangeNotification object:self]; - } - [self setTarget:self]; - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - //stop any animations that may be running - [_animationTimer invalidate]; - [_animationTimer release]; _animationTimer = nil; - - [_showHideAnimationTimer invalidate]; - [_showHideAnimationTimer release]; _showHideAnimationTimer = nil; - - //Also unwind the spring, if it's wound. - [_springTimer invalidate]; - [_springTimer release]; _springTimer = nil; - - //unbind all the items to prevent crashing - //not sure if this is necessary or not - // http://code.google.com/p/maccode/issues/detail?id=35 - NSEnumerator *enumerator = [[[_cells copy] autorelease] objectEnumerator]; - PSMTabBarCell *nextCell; - while((nextCell = [enumerator nextObject])) { - [self removeTabForCell:nextCell]; - } - - [_overflowPopUpButton release]; - [_cells release]; - [_controller release]; - [tabView release]; - [_addTabButton release]; - [partnerView release]; - [_lastMouseDownEvent release]; - [style release]; - - [self unregisterDraggedTypes]; - - [super dealloc]; -} - -- (void)awakeFromNib { - // build cells from existing tab view items - NSArray *existingItems = [tabView tabViewItems]; - NSEnumerator *e = [existingItems objectEnumerator]; - NSTabViewItem *item; - while((item = [e nextObject])) { - if(![[self representedTabViewItems] containsObject:item]) { - [self addTabViewItem:item]; - } - } -} - -- (void)viewWillMoveToWindow:(NSWindow *)aWindow { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; - [center removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; - [center removeObserver:self name:NSWindowDidUpdateNotification object:nil]; - [center removeObserver:self name:NSWindowDidMoveNotification object:nil]; - - if(_showHideAnimationTimer) { - [_showHideAnimationTimer invalidate]; - [_showHideAnimationTimer release]; _showHideAnimationTimer = nil; - } - - if(aWindow) { - [center addObserver:self selector:@selector(windowStatusDidChange:) name:NSWindowDidBecomeKeyNotification object:aWindow]; - [center addObserver:self selector:@selector(windowStatusDidChange:) name:NSWindowDidResignKeyNotification object:aWindow]; - [center addObserver:self selector:@selector(windowDidUpdate:) name:NSWindowDidUpdateNotification object:aWindow]; - [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:aWindow]; - } -} - -- (void)windowStatusDidChange:(NSNotification *)notification { - [self setNeedsDisplay:YES]; -} - -#pragma mark - -#pragma mark Accessors - -- (NSMutableArray *)cells { - return _cells; -} - -- (NSEvent *)lastMouseDownEvent { - return _lastMouseDownEvent; -} - -- (void)setLastMouseDownEvent:(NSEvent *)event { - [event retain]; - [_lastMouseDownEvent release]; - _lastMouseDownEvent = event; -} - -- (id)delegate { - return delegate; -} - -- (void)setDelegate:(id)object { - delegate = object; - - NSMutableArray *types = [NSMutableArray arrayWithObject:@"PSMTabBarControlItemPBType"]; - - //Update the allowed drag types - if([self delegate] && [[self delegate] respondsToSelector:@selector(allowedDraggedTypesForTabView:)]) { - [types addObjectsFromArray:[[self delegate] allowedDraggedTypesForTabView:tabView]]; - } - [self unregisterDraggedTypes]; - [self registerForDraggedTypes:types]; -} - -- (NSTabView *)tabView { - return tabView; -} - -- (void)setTabView:(NSTabView *)view { - [view retain]; - [tabView release]; - tabView = view; -} - -- (id<PSMTabStyle>)style { - return style; -} - -- (NSString *)styleName { - return [style name]; -} - -- (void)setStyle:(id <PSMTabStyle>)newStyle { - if(style != newStyle) { - [style autorelease]; - style = [newStyle retain]; - - // restyle add tab button - if(_addTabButton) { - NSImage *newButtonImage = [style addTabButtonImage]; - if(newButtonImage) { - [_addTabButton setUsualImage:newButtonImage]; - } - - newButtonImage = [style addTabButtonPressedImage]; - if(newButtonImage) { - [_addTabButton setAlternateImage:newButtonImage]; - } - - newButtonImage = [style addTabButtonRolloverImage]; - if(newButtonImage) { - [_addTabButton setRolloverImage:newButtonImage]; - } - } - - [self update]; - } -} - -- (void)setStyleNamed:(NSString *)name { - - Class styleClass = NSClassFromString( [NSString stringWithFormat: @"PSM%@TabStyle", [name capitalizedString]] ); - if (styleClass == Nil) { - styleClass = object_getClass([PSMTabBarControl defaultStyleClass]); - } - - id <PSMTabStyle> newStyle = [[styleClass alloc] init]; - [self setStyle:newStyle]; - [newStyle release]; -} - -- (PSMTabBarOrientation)orientation { - return _orientation; -} - -- (void)setOrientation:(PSMTabBarOrientation)value { - PSMTabBarOrientation lastOrientation = _orientation; - _orientation = value; - - if(_tabBarWidth < 10) { - _tabBarWidth = 120; - } - - if (lastOrientation != _orientation) { - [[self style] setOrientation:_orientation]; - - [self _positionOverflowMenu]; //move the overflow popup button to the right place - [self update:NO]; - } -} - -- (BOOL)canCloseOnlyTab { - return _canCloseOnlyTab; -} - -- (void)setCanCloseOnlyTab:(BOOL)value { - _canCloseOnlyTab = value; - if([_cells count] == 1) { - [self update]; - } -} - -- (BOOL)disableTabClose { - return _disableTabClose; -} - -- (void)setDisableTabClose:(BOOL)value { - _disableTabClose = value; - [self update]; -} - -- (BOOL)hideForSingleTab { - return _hideForSingleTab; -} - -- (void)setHideForSingleTab:(BOOL)value { - _hideForSingleTab = value; - [self update]; -} - -- (BOOL)showAddTabButton { - return _showAddTabButton; -} - -- (void)setShowAddTabButton:(BOOL)value { - _showAddTabButton = value; - if(!NSIsEmptyRect([_controller addButtonRect])) { - [_addTabButton setFrame:[_controller addButtonRect]]; - } - - [_addTabButton setHidden:!_showAddTabButton]; - [_addTabButton setNeedsDisplay:YES]; - - [self update]; -} - -- (NSInteger)cellMinWidth { - return _cellMinWidth; -} - -- (void)setCellMinWidth:(NSInteger)value { - _cellMinWidth = value; - [self update]; -} - -- (NSInteger)cellMaxWidth { - return _cellMaxWidth; -} - -- (void)setCellMaxWidth:(NSInteger)value { - _cellMaxWidth = value; - [self update]; -} - -- (NSInteger)cellOptimumWidth { - return _cellOptimumWidth; -} - -- (void)setCellOptimumWidth:(NSInteger)value { - _cellOptimumWidth = value; - [self update]; -} - -- (BOOL)sizeCellsToFit { - return _sizeCellsToFit; -} - -- (void)setSizeCellsToFit:(BOOL)value { - _sizeCellsToFit = value; - [self update]; -} - -- (BOOL)useOverflowMenu { - return _useOverflowMenu; -} - -- (void)setUseOverflowMenu:(BOOL)value { - _useOverflowMenu = value; - [self update]; -} - -- (PSMRolloverButton *)addTabButton { - return _addTabButton; -} - -- (PSMOverflowPopUpButton *)overflowPopUpButton { - return _overflowPopUpButton; -} - -- (BOOL)allowsBackgroundTabClosing { - return _allowsBackgroundTabClosing; -} - -- (void)setAllowsBackgroundTabClosing:(BOOL)value { - _allowsBackgroundTabClosing = value; -} - -- (BOOL)allowsResizing { - return _allowsResizing; -} - -- (void)setAllowsResizing:(BOOL)value { - _allowsResizing = value; -} - -- (BOOL)selectsTabsOnMouseDown { - return _selectsTabsOnMouseDown; -} - -- (void)setSelectsTabsOnMouseDown:(BOOL)value { - _selectsTabsOnMouseDown = value; -} - -- (BOOL)automaticallyAnimates { - return _automaticallyAnimates; -} - -- (void)setAutomaticallyAnimates:(BOOL)value { - _automaticallyAnimates = value; -} - -- (BOOL)alwaysShowActiveTab { - return _alwaysShowActiveTab; -} - -- (void)setAlwaysShowActiveTab:(BOOL)value { - _alwaysShowActiveTab = value; -} - -- (BOOL)allowsScrubbing { - return _allowsScrubbing; -} - -- (void)setAllowsScrubbing:(BOOL)value { - _allowsScrubbing = value; -} - -- (PSMTabBarTearOffStyle)tearOffStyle { - return _tearOffStyle; -} - -- (void)setTearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle { - _tearOffStyle = tearOffStyle; -} - -#pragma mark - -#pragma mark Functionality - -- (void)addTabViewItem:(NSTabViewItem *)item { - // create cell - PSMTabBarCell *cell = [[PSMTabBarCell alloc] initWithControlView:self]; - NSRect cellRect, lastCellFrame; - if([_cells lastObject] != nil) { - cellRect = lastCellFrame = [[_cells lastObject] frame]; - } else { - cellRect = lastCellFrame = NSZeroRect; - } - - if([self orientation] == PSMTabBarHorizontalOrientation) { - cellRect = [self genericCellRect]; - cellRect.size.width = 30; - cellRect.origin.x = lastCellFrame.origin.x + lastCellFrame.size.width; - } else { - cellRect = /*lastCellFrame*/ [self genericCellRect]; - cellRect.size.width = lastCellFrame.size.width; - cellRect.size.height = 0; - cellRect.origin.y = lastCellFrame.origin.y + lastCellFrame.size.height; - } - - [cell setRepresentedObject:item]; - [cell setFrame:cellRect]; - - // bind it up - [self bindPropertiesForCell:cell andTabViewItem:item]; - - // add to collection - [_cells addObject:cell]; - [cell release]; - if([_cells count] == (NSUInteger)[tabView numberOfTabViewItems]) { - [self update]; // don't update unless all are accounted for! - } -} - -- (void)removeTabForCell:(PSMTabBarCell *)cell { - NSTabViewItem *item = [cell representedObject]; - - // unbind - [[cell indicator] unbind:@"animate"]; - [[cell indicator] unbind:@"hidden"]; - [cell unbind:@"hasIcon"]; - [cell unbind:@"hasLargeImage"]; - [cell unbind:@"title"]; - [cell unbind:@"count"]; - [cell unbind:@"countColor"]; - [cell unbind:@"isEdited"]; - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(isProcessing)]) { - [[item identifier] removeObserver:cell forKeyPath:@"isProcessing"]; - } - } - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(icon)]) { - [[item identifier] removeObserver:cell forKeyPath:@"icon"]; - } - } - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(objectCount)]) { - [[item identifier] removeObserver:cell forKeyPath:@"objectCount"]; - } - } - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(countColor)]) { - [[item identifier] removeObserver:cell forKeyPath:@"countColor"]; - } - } - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(largeImage)]) { - [[item identifier] removeObserver:cell forKeyPath:@"largeImage"]; - } - } - - if([item identifier] != nil) { - if([[item identifier] respondsToSelector:@selector(isEdited)]) { - [[item identifier] removeObserver:cell forKeyPath:@"isEdited"]; - } - } - - // stop watching identifier - [item removeObserver:self forKeyPath:@"identifier"]; - - // remove indicator - if([[self subviews] containsObject:[cell indicator]]) { - [[cell indicator] removeFromSuperview]; - } - // remove tracking - [[NSNotificationCenter defaultCenter] removeObserver:cell]; - - if([cell closeButtonTrackingTag] != 0) { - [self removeTrackingRect:[cell closeButtonTrackingTag]]; - [cell setCloseButtonTrackingTag:0]; - } - if([cell cellTrackingTag] != 0) { - [self removeTrackingRect:[cell cellTrackingTag]]; - [cell setCellTrackingTag:0]; - } - - // pull from collection - [_cells removeObject:cell]; - - [self update]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - // did the tab's identifier change? - if([keyPath isEqualToString:@"identifier"]) { - NSEnumerator *e = [_cells objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - if([cell representedObject] == object) { - [self _bindPropertiesForCell:cell andTabViewItem:object]; - } - } - } -} - -#pragma mark - -#pragma mark Hide/Show - -- (void)hideTabBar:(BOOL)hide animate:(BOOL)animate { - if(!_awakenedFromNib || (_isHidden && hide) || (!_isHidden && !hide) || (_currentStep != kPSMIsNotBeingResized)) { - return; - } - - [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; - - _isHidden = hide; - _currentStep = 0; - if(!animate) { - _currentStep = (NSInteger)kPSMHideAnimationSteps; - } - - if(hide) { - [_overflowPopUpButton removeFromSuperview]; - [_addTabButton removeFromSuperview]; - } else if(!animate) { - [self addSubview:_overflowPopUpButton]; - [self addSubview:_addTabButton]; - } - - CGFloat partnerOriginalSize, partnerOriginalOrigin, myOriginalSize, myOriginalOrigin, partnerTargetSize, partnerTargetOrigin, myTargetSize, myTargetOrigin; - - // target values for partner - if([self orientation] == PSMTabBarHorizontalOrientation) { - // current (original) values - myOriginalSize = [self frame].size.height; - myOriginalOrigin = [self frame].origin.y; - if(partnerView) { - partnerOriginalSize = [partnerView frame].size.height; - partnerOriginalOrigin = [partnerView frame].origin.y; - } else { - partnerOriginalSize = [[self window] frame].size.height; - partnerOriginalOrigin = [[self window] frame].origin.y; - } - - if(partnerView) { - // above or below me? - if((myOriginalOrigin - 22) > partnerOriginalOrigin) { - // partner is below me - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin + 21; - myTargetSize = myOriginalSize - 21; - partnerTargetOrigin = partnerOriginalOrigin; - partnerTargetSize = partnerOriginalSize + 21; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin - 21; - myTargetSize = myOriginalSize + 21; - partnerTargetOrigin = partnerOriginalOrigin; - partnerTargetSize = partnerOriginalSize - 21; - } - } else { - // partner is above me - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin; - myTargetSize = myOriginalSize - 21; - partnerTargetOrigin = partnerOriginalOrigin - 21; - partnerTargetSize = partnerOriginalSize + 21; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin; - myTargetSize = myOriginalSize + 21; - partnerTargetOrigin = partnerOriginalOrigin + 21; - partnerTargetSize = partnerOriginalSize - 21; - } - } - } else { - // for window movement - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin; - myTargetSize = myOriginalSize - 21; - partnerTargetOrigin = partnerOriginalOrigin + 21; - partnerTargetSize = partnerOriginalSize - 21; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin; - myTargetSize = myOriginalSize + 21; - partnerTargetOrigin = partnerOriginalOrigin - 21; - partnerTargetSize = partnerOriginalSize + 21; - } - } - } else { /* vertical */ - // current (original) values - myOriginalSize = [self frame].size.width; - myOriginalOrigin = [self frame].origin.x; - if(partnerView) { - partnerOriginalSize = [partnerView frame].size.width; - partnerOriginalOrigin = [partnerView frame].origin.x; - } else { - partnerOriginalSize = [[self window] frame].size.width; - partnerOriginalOrigin = [[self window] frame].origin.x; - } - - if(partnerView) { - //to the left or right? - if(myOriginalOrigin < partnerOriginalOrigin + partnerOriginalSize) { - // partner is to the left - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin; - myTargetSize = 1; - partnerTargetOrigin = partnerOriginalOrigin - myOriginalSize + 1; - partnerTargetSize = partnerOriginalSize + myOriginalSize - 1; - _tabBarWidth = myOriginalSize; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin; - myTargetSize = myOriginalSize + _tabBarWidth; - partnerTargetOrigin = partnerOriginalOrigin + _tabBarWidth; - partnerTargetSize = partnerOriginalSize - _tabBarWidth; - } - } else { - // partner is to the right - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin + myOriginalSize; - myTargetSize = 1; - partnerTargetOrigin = partnerOriginalOrigin; - partnerTargetSize = partnerOriginalSize + myOriginalSize; - _tabBarWidth = myOriginalSize; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin - _tabBarWidth; - myTargetSize = myOriginalSize + _tabBarWidth; - partnerTargetOrigin = partnerOriginalOrigin; - partnerTargetSize = partnerOriginalSize - _tabBarWidth; - } - } - } else { - // for window movement - if(_isHidden) { - // I'm shrinking - myTargetOrigin = myOriginalOrigin; - myTargetSize = 1; - partnerTargetOrigin = partnerOriginalOrigin + myOriginalSize - 1; - partnerTargetSize = partnerOriginalSize - myOriginalSize + 1; - _tabBarWidth = myOriginalSize; - } else { - // I'm growing - myTargetOrigin = myOriginalOrigin; - myTargetSize = _tabBarWidth; - partnerTargetOrigin = partnerOriginalOrigin - _tabBarWidth + 1; - partnerTargetSize = partnerOriginalSize + _tabBarWidth - 1; - } - } - - if(!_isHidden && [[self delegate] respondsToSelector:@selector(desiredWidthForVerticalTabBar:)]) { - myTargetSize = [[self delegate] desiredWidthForVerticalTabBar:self]; - } - } - - NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:myOriginalOrigin], @"myOriginalOrigin", [NSNumber numberWithDouble:partnerOriginalOrigin], @"partnerOriginalOrigin", [NSNumber numberWithDouble:myOriginalSize], @"myOriginalSize", [NSNumber numberWithDouble:partnerOriginalSize], @"partnerOriginalSize", [NSNumber numberWithDouble:myTargetOrigin], @"myTargetOrigin", [NSNumber numberWithDouble:partnerTargetOrigin], @"partnerTargetOrigin", [NSNumber numberWithDouble:myTargetSize], @"myTargetSize", [NSNumber numberWithDouble:partnerTargetSize], @"partnerTargetSize", nil]; - if(_showHideAnimationTimer) { - [_showHideAnimationTimer invalidate]; - [_showHideAnimationTimer release]; - } - _showHideAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(animateShowHide:) userInfo:userInfo repeats:YES] retain]; -} - -- (void)animateShowHide:(NSTimer *)timer { - // moves the frame of the tab bar and window (or partner view) linearly to hide or show the tab bar - NSRect myFrame = [self frame]; - NSDictionary *userInfo = [timer userInfo]; - CGFloat myCurrentOrigin = ([[userInfo objectForKey:@"myOriginalOrigin"] doubleValue] + (([[userInfo objectForKey:@"myTargetOrigin"] doubleValue] - [[userInfo objectForKey:@"myOriginalOrigin"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps))); - CGFloat myCurrentSize = ([[userInfo objectForKey:@"myOriginalSize"] doubleValue] + (([[userInfo objectForKey:@"myTargetSize"] doubleValue] - [[userInfo objectForKey:@"myOriginalSize"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps))); - CGFloat partnerCurrentOrigin = ([[userInfo objectForKey:@"partnerOriginalOrigin"] doubleValue] + (([[userInfo objectForKey:@"partnerTargetOrigin"] doubleValue] - [[userInfo objectForKey:@"partnerOriginalOrigin"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps))); - CGFloat partnerCurrentSize = ([[userInfo objectForKey:@"partnerOriginalSize"] doubleValue] + (([[userInfo objectForKey:@"partnerTargetSize"] doubleValue] - [[userInfo objectForKey:@"partnerOriginalSize"] doubleValue]) * (_currentStep / kPSMHideAnimationSteps))); - - NSRect myNewFrame; - if([self orientation] == PSMTabBarHorizontalOrientation) { - myNewFrame = NSMakeRect(myFrame.origin.x, myCurrentOrigin, myFrame.size.width, myCurrentSize); - } else { - myNewFrame = NSMakeRect(myCurrentOrigin, myFrame.origin.y, myCurrentSize, myFrame.size.height); - } - - if(partnerView) { - // resize self and view - NSRect resizeRect; - if([self orientation] == PSMTabBarHorizontalOrientation) { - resizeRect = NSMakeRect([partnerView frame].origin.x, partnerCurrentOrigin, [partnerView frame].size.width, partnerCurrentSize); - } else { - resizeRect = NSMakeRect(partnerCurrentOrigin, [partnerView frame].origin.y, partnerCurrentSize, [partnerView frame].size.height); - } - [partnerView setFrame:resizeRect]; - [partnerView setNeedsDisplay:YES]; - [self setFrame:myNewFrame]; - } else { - // resize self and window - NSRect resizeRect; - if([self orientation] == PSMTabBarHorizontalOrientation) { - resizeRect = NSMakeRect([[self window] frame].origin.x, partnerCurrentOrigin, [[self window] frame].size.width, partnerCurrentSize); - } else { - resizeRect = NSMakeRect(partnerCurrentOrigin, [[self window] frame].origin.y, partnerCurrentSize, [[self window] frame].size.height); - } - [[self window] setFrame:resizeRect display:YES]; - [self setFrame:myNewFrame]; - } - - // next - _currentStep++; - if(_currentStep == kPSMHideAnimationSteps + 1) { - _currentStep = kPSMIsNotBeingResized; - [self viewDidEndLiveResize]; - [self update:NO]; - - //send the delegate messages - if(_isHidden) { - if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidHide:)]) { - [[self delegate] tabView:[self tabView] tabBarDidHide:self]; - } - } else { - [self addSubview:_overflowPopUpButton]; - [self addSubview:_addTabButton]; - - if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidUnhide:)]) { - [[self delegate] tabView:[self tabView] tabBarDidUnhide:self]; - } - } - - [_showHideAnimationTimer invalidate]; - [_showHideAnimationTimer release]; _showHideAnimationTimer = nil; - } - [[self window] display]; -} - -- (BOOL)isTabBarHidden { - return _isHidden; -} - -- (BOOL)isAnimating { - return _animationTimer != nil; -} - -- (id)partnerView { - return partnerView; -} - -- (void)setPartnerView:(id)view { - [partnerView release]; - [view retain]; - partnerView = view; -} - -#pragma mark - -#pragma mark Drawing - -- (BOOL)isFlipped { - return YES; -} - -- (void)drawRect:(NSRect)rect { - [style drawTabBar:self inRect:rect]; -} - -- (void)update { - [self update:_automaticallyAnimates]; -} - -- (void)update:(BOOL)animate { - // make sure all of our tabs are accounted for before updating - if((NSUInteger)[[self tabView] numberOfTabViewItems] != [_cells count]) { - return; - } - - // hide/show? (these return if already in desired state) - if((_hideForSingleTab) && ([_cells count] <= 1)) { - [self hideTabBar:YES animate:YES]; - return; - } else { - [self hideTabBar:NO animate:YES]; - } - - [self removeAllToolTips]; - [_controller layoutCells]; //eventually we should only have to call this when we know something has changed - - PSMTabBarCell *currentCell; - - NSMenu *overflowMenu = [_controller overflowMenu]; - [_overflowPopUpButton setHidden:(overflowMenu == nil)]; - [_overflowPopUpButton setMenu:overflowMenu]; - - if(_animationTimer) { - [_animationTimer invalidate]; - [_animationTimer release]; _animationTimer = nil; - } - - if(animate) { - NSMutableArray *targetFrames = [NSMutableArray arrayWithCapacity:[_cells count]]; - - for(NSUInteger i = 0; i < [_cells count]; i++) { - currentCell = [_cells objectAtIndex:i]; - - //we're going from NSRect -> NSValue -> NSRect -> NSValue here - oh well - [targetFrames addObject:[NSValue valueWithRect:[_controller cellFrameAtIndex:i]]]; - } - - [_addTabButton setHidden:!_showAddTabButton]; - - NSAnimation *animation = [[NSAnimation alloc] initWithDuration:0.50 animationCurve:NSAnimationEaseInOut]; - [animation setAnimationBlockingMode:NSAnimationNonblocking]; - [animation startAnimation]; - _animationTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 - target:self - selector:@selector(_animateCells:) - userInfo:[NSArray arrayWithObjects:targetFrames, animation, nil] - repeats:YES] retain]; - [animation release]; - [[NSRunLoop currentRunLoop] addTimer:_animationTimer forMode:NSEventTrackingRunLoopMode]; - [self _animateCells:_animationTimer]; - } else { - for(NSUInteger i = 0; i < [_cells count]; i++) { - currentCell = [_cells objectAtIndex:i]; - [currentCell setFrame:[_controller cellFrameAtIndex:i]]; - - if(![currentCell isInOverflowMenu]) { - [self _setupTrackingRectsForCell:currentCell]; - } - } - - [_addTabButton setFrame:[_controller addButtonRect]]; - [_addTabButton setHidden:!_showAddTabButton]; - [self setNeedsDisplay:YES]; - } -} - -- (void)_animateCells:(NSTimer *)timer { - NSAnimation *animation = [[timer userInfo] objectAtIndex:1]; - NSArray *targetFrames = [[timer userInfo] objectAtIndex:0]; - PSMTabBarCell *currentCell; - NSUInteger cellCount = [_cells count]; - - if((cellCount > 0) && [animation isAnimating]) { - //compare our target position with the current position and move towards the target - for(NSUInteger i = 0; i < [targetFrames count] && i < cellCount; i++) { - currentCell = [_cells objectAtIndex:i]; - NSRect cellFrame = [currentCell frame], targetFrame = [[targetFrames objectAtIndex:i] rectValue]; - CGFloat sizeChange; - CGFloat originChange; - - if([self orientation] == PSMTabBarHorizontalOrientation) { - sizeChange = (targetFrame.size.width - cellFrame.size.width) * [animation currentProgress]; - originChange = (targetFrame.origin.x - cellFrame.origin.x) * [animation currentProgress]; - cellFrame.size.width += sizeChange; - cellFrame.origin.x += originChange; - } else { - sizeChange = (targetFrame.size.height - cellFrame.size.height) * [animation currentProgress]; - originChange = (targetFrame.origin.y - cellFrame.origin.y) * [animation currentProgress]; - cellFrame.size.height += sizeChange; - cellFrame.origin.y += originChange; - } - - [currentCell setFrame:cellFrame]; - - //highlight the cell if the mouse is over it - NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil]; - NSRect closeRect = [currentCell closeButtonRectForFrame:cellFrame]; - [currentCell setHighlighted:NSMouseInRect(mousePoint, cellFrame, [self isFlipped])]; - [currentCell setCloseButtonOver:NSMouseInRect(mousePoint, closeRect, [self isFlipped])]; - } - - if(_showAddTabButton) { - //animate the add tab button - NSRect target = [_controller addButtonRect], frame = [_addTabButton frame]; - frame.origin.x += (target.origin.x - frame.origin.x) * [animation currentProgress]; - [_addTabButton setFrame:frame]; - } - } else { - //put all the cells where they should be in their final position - if(cellCount > 0) { - for(NSUInteger i = 0; i < [targetFrames count] && i < cellCount; i++) { - PSMTabBarCell *currentCell = [_cells objectAtIndex:i]; - NSRect cellFrame = [currentCell frame], targetFrame = [[targetFrames objectAtIndex:i] rectValue]; - - if([self orientation] == PSMTabBarHorizontalOrientation) { - cellFrame.size.width = targetFrame.size.width; - cellFrame.origin.x = targetFrame.origin.x; - } else { - cellFrame.size.height = targetFrame.size.height; - cellFrame.origin.y = targetFrame.origin.y; - } - - [currentCell setFrame:cellFrame]; - - //highlight the cell if the mouse is over it - NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil]; - NSRect closeRect = [currentCell closeButtonRectForFrame:cellFrame]; - [currentCell setHighlighted:NSMouseInRect(mousePoint, cellFrame, [self isFlipped])]; - [currentCell setCloseButtonOver:NSMouseInRect(mousePoint, closeRect, [self isFlipped])]; - } - } - - //set the frame for the add tab button - if(_showAddTabButton) { - NSRect frame = [_addTabButton frame]; - frame.origin.x = [_controller addButtonRect].origin.x; - [_addTabButton setFrame:frame]; - } - - [_animationTimer invalidate]; - [_animationTimer release]; _animationTimer = nil; - - for(NSUInteger i = 0; i < cellCount; i++) { - currentCell = [_cells objectAtIndex:i]; - - //we've hit the cells that are in overflow, stop setting up tracking rects - if([currentCell isInOverflowMenu]) { - break; - } - - [self _setupTrackingRectsForCell:currentCell]; - } - } - - [self setNeedsDisplay:YES]; -} - -- (void)_setupTrackingRectsForCell:(PSMTabBarCell *)cell { - NSInteger tag, index = [_cells indexOfObject:cell]; - NSRect cellTrackingRect = [_controller cellTrackingRectAtIndex:index]; - NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil]; - BOOL mouseInCell = NSMouseInRect(mousePoint, cellTrackingRect, [self isFlipped]); - - //set the cell tracking rect - [self removeTrackingRect:[cell cellTrackingTag]]; - tag = [self addTrackingRect:cellTrackingRect owner:cell userData:nil assumeInside:mouseInCell]; - [cell setCellTrackingTag:tag]; - [cell setHighlighted:mouseInCell]; - - if([cell hasCloseButton] && ![cell isCloseButtonSuppressed]) { - NSRect closeRect = [_controller closeButtonTrackingRectAtIndex:index]; - BOOL mouseInCloseRect = NSMouseInRect(mousePoint, closeRect, [self isFlipped]); - - //set the close button tracking rect - [self removeTrackingRect:[cell closeButtonTrackingTag]]; - tag = [self addTrackingRect:closeRect owner:cell userData:nil assumeInside:mouseInCloseRect]; - [cell setCloseButtonTrackingTag:tag]; - - [cell setCloseButtonOver:mouseInCloseRect]; - } - - //set the tooltip tracking rect - [self addToolTipRect:[cell frame] owner:self userData:nil]; -} - -- (void)_positionOverflowMenu { - NSRect cellRect, frame = [self frame]; - cellRect.size.height = [style tabCellHeight]; - cellRect.size.width = [style rightMarginForTabBarControl]; - - if([self orientation] == PSMTabBarHorizontalOrientation) { - cellRect.origin.y = 0; - cellRect.origin.x = frame.size.width - [style rightMarginForTabBarControl] + (_resizeAreaCompensation ? -(_resizeAreaCompensation - 1) : 1); - [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin]; - } else { - cellRect.origin.x = 0; - cellRect.origin.y = frame.size.height - [style tabCellHeight]; - cellRect.size.width = frame.size.width; - [_overflowPopUpButton setAutoresizingMask:NSViewNotSizable | NSViewMinXMargin | NSViewMinYMargin]; - } - - [_overflowPopUpButton setFrame:cellRect]; -} - -- (void)_checkWindowFrame { - //figure out if the new frame puts the control in the way of the resize widget - NSWindow *window = [self window]; - - if(window) { - NSRect resizeWidgetFrame = [[window contentView] frame]; - resizeWidgetFrame.origin.x += resizeWidgetFrame.size.width - 22; - resizeWidgetFrame.size.width = 22; - resizeWidgetFrame.size.height = 22; - - if([window showsResizeIndicator] && NSIntersectsRect([self frame], resizeWidgetFrame)) { - //the resize widgets are larger on metal windows - _resizeAreaCompensation = [window styleMask] & NSTexturedBackgroundWindowMask ? 20 : 8; - } else { - _resizeAreaCompensation = 0; - } - - [self _positionOverflowMenu]; - } -} - -#pragma mark - -#pragma mark Mouse Tracking - -- (BOOL)mouseDownCanMoveWindow { - return NO; -} - -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { - return YES; -} - -- (void)mouseDown:(NSEvent *)theEvent { - _didDrag = NO; - - // keep for dragging - [self setLastMouseDownEvent:theEvent]; - // what cell? - NSPoint mousePt = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - NSRect frame = [self frame]; - - if([self orientation] == PSMTabBarVerticalOrientation && [self allowsResizing] && partnerView && (mousePt.x > frame.size.width - 3)) { - _resizing = YES; - } - - NSRect cellFrame; - PSMTabBarCell *cell = [self cellForPoint:mousePt cellFrame:&cellFrame]; - if(cell) { - BOOL overClose = NSMouseInRect(mousePt, [cell closeButtonRectForFrame:cellFrame], [self isFlipped]); - if(overClose && - ![self disableTabClose] && - ![cell isCloseButtonSuppressed] && - ([self allowsBackgroundTabClosing] || [[cell representedObject] isEqualTo:[tabView selectedTabViewItem]] || [theEvent modifierFlags] & NSCommandKeyMask)) { - [cell setCloseButtonOver:NO]; - [cell setCloseButtonPressed:YES]; - _closeClicked = YES; - } else { - [cell setCloseButtonPressed:NO]; - if(_selectsTabsOnMouseDown) { - [self performSelector:@selector(tabClick:) withObject:cell]; - } - } - [self setNeedsDisplay:YES]; - } -} - -- (void)mouseDragged:(NSEvent *)theEvent { - if([self lastMouseDownEvent] == nil) { - return; - } - - NSPoint currentPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - - if(_resizing) { - NSRect frame = [self frame]; - CGFloat resizeAmount = [theEvent deltaX]; - if((currentPoint.x > frame.size.width && resizeAmount > 0) || (currentPoint.x < frame.size.width && resizeAmount < 0)) { - [[NSCursor resizeLeftRightCursor] push]; - - NSRect partnerFrame = [partnerView frame]; - - //do some bounds checking - if((frame.size.width + resizeAmount > [self cellMinWidth]) && (frame.size.width + resizeAmount < [self cellMaxWidth])) { - frame.size.width += resizeAmount; - partnerFrame.size.width -= resizeAmount; - partnerFrame.origin.x += resizeAmount; - - [self setFrame:frame]; - [partnerView setFrame:partnerFrame]; - [[self superview] setNeedsDisplay:YES]; - } - } - return; - } - - NSRect cellFrame; - NSPoint trackingStartPoint = [self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil]; - PSMTabBarCell *cell = [self cellForPoint:trackingStartPoint cellFrame:&cellFrame]; - if(cell) { - //check to see if the close button was the target in the clicked cell - //highlight/unhighlight the close button as necessary - NSRect iconRect = [cell closeButtonRectForFrame:cellFrame]; - - if(_closeClicked && NSMouseInRect(trackingStartPoint, iconRect, [self isFlipped]) && - ([self allowsBackgroundTabClosing] || [[cell representedObject] isEqualTo:[tabView selectedTabViewItem]])) { - [cell setCloseButtonPressed:NSMouseInRect(currentPoint, iconRect, [self isFlipped])]; - [self setNeedsDisplay:YES]; - return; - } - - CGFloat dx = fabs(currentPoint.x - trackingStartPoint.x); - CGFloat dy = fabs(currentPoint.y - trackingStartPoint.y); - CGFloat distance = sqrt(dx * dx + dy * dy); - - if(distance >= 10 && !_didDrag && ![[PSMTabDragAssistant sharedDragAssistant] isDragging] && - [self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDragTabViewItem:fromTabBar:)] && - [[self delegate] tabView:tabView shouldDragTabViewItem:[cell representedObject] fromTabBar:self]) { - _didDrag = YES; - [[PSMTabDragAssistant sharedDragAssistant] startDraggingCell:cell fromTabBar:self withMouseDownEvent:[self lastMouseDownEvent]]; - } - } -} - -- (void)mouseUp:(NSEvent *)theEvent { - if(_resizing) { - _resizing = NO; - [[NSCursor arrowCursor] set]; - } else { - // what cell? - NSPoint mousePt = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - NSRect cellFrame, mouseDownCellFrame; - PSMTabBarCell *cell = [self cellForPoint:mousePt cellFrame:&cellFrame]; - PSMTabBarCell *mouseDownCell = [self cellForPoint:[self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil] cellFrame:&mouseDownCellFrame]; - if(cell) { - NSPoint trackingStartPoint = [self convertPoint:[[self lastMouseDownEvent] locationInWindow] fromView:nil]; - NSRect iconRect = [mouseDownCell closeButtonRectForFrame:mouseDownCellFrame]; - - if((NSMouseInRect(mousePt, iconRect, [self isFlipped])) && ![self disableTabClose] && ![cell isCloseButtonSuppressed] && [mouseDownCell closeButtonPressed]) { - if(([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0) { - //If the user is holding Option, close all other tabs - NSEnumerator *enumerator = [[[[self cells] copy] autorelease] objectEnumerator]; - PSMTabBarCell *otherCell; - - while((otherCell = [enumerator nextObject])) { - if(otherCell != cell) { - [self performSelector:@selector(closeTabClick:) withObject:otherCell]; - } - } - - //Fix the close button for the clicked tab not to be pressed - [cell setCloseButtonPressed:NO]; - } else { - //Otherwise, close this tab - [self performSelector:@selector(closeTabClick:) withObject:cell]; - } - } else if(NSMouseInRect(mousePt, mouseDownCellFrame, [self isFlipped]) && - (!NSMouseInRect(trackingStartPoint, [cell closeButtonRectForFrame:cellFrame], [self isFlipped]) || ![self allowsBackgroundTabClosing] || [self disableTabClose])) { - [mouseDownCell setCloseButtonPressed:NO]; - // If -[self selectsTabsOnMouseDown] is TRUE, we already performed tabClick: on mouseDown. - if(![self selectsTabsOnMouseDown]) { - [self performSelector:@selector(tabClick:) withObject:cell]; - } - } else { - [mouseDownCell setCloseButtonPressed:NO]; - [self performSelector:@selector(tabNothing:) withObject:cell]; - } - } - - _closeClicked = NO; - } -} - -- (NSMenu *)menuForEvent:(NSEvent *)event { - NSMenu *menu = nil; - NSTabViewItem *item = [[self cellForPoint:[self convertPoint:[event locationInWindow] fromView:nil] cellFrame:nil] representedObject]; - - if(item && [[self delegate] respondsToSelector:@selector(tabView:menuForTabViewItem:)]) { - menu = [[self delegate] tabView:tabView menuForTabViewItem:item]; - } - return menu; -} - -#pragma mark - -#pragma mark Drag and Drop - -- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent { - return YES; -} - -// NSDraggingSource -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { - return(isLocal ? NSDragOperationMove : NSDragOperationNone); -} - -- (BOOL)ignoreModifierKeysWhileDragging { - return YES; -} - -- (void)draggedImage:(NSImage *)anImage beganAt:(NSPoint)screenPoint { - [[PSMTabDragAssistant sharedDragAssistant] draggingBeganAt:screenPoint]; -} - -- (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint { - [[PSMTabDragAssistant sharedDragAssistant] draggingMovedTo:screenPoint]; -} - -// NSDraggingDestination -- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { - if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) { - if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && - ![[self delegate] tabView:[[sender draggingSource] tabView] shouldDropTabViewItem:[[[PSMTabDragAssistant sharedDragAssistant] draggedCell] representedObject] inTabBar:self]) { - return NSDragOperationNone; - } - - [[PSMTabDragAssistant sharedDragAssistant] draggingEnteredTabBar:self atPoint:[self convertPoint:[sender draggingLocation] fromView:nil]]; - return NSDragOperationMove; - } - - return NSDragOperationNone; -} - -- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender { - PSMTabBarCell *cell = [self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil]; - - if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) { - if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && - ![[self delegate] tabView:[[sender draggingSource] tabView] shouldDropTabViewItem:[[[PSMTabDragAssistant sharedDragAssistant] draggedCell] representedObject] inTabBar:self]) { - return NSDragOperationNone; - } - - [[PSMTabDragAssistant sharedDragAssistant] draggingUpdatedInTabBar:self atPoint:[self convertPoint:[sender draggingLocation] fromView:nil]]; - return NSDragOperationMove; - } else if(cell) { - //something that was accepted by the delegate was dragged on - - //Test for the space bar (the skip-the-delay key). - /*enum { virtualKeycodeForSpace = 49 }; //Source: IM:Tx (Fig. C-2) - union { - KeyMap keymap; - char bits[16]; - } keymap; - GetKeys(keymap.keymap); - if ((GetCurrentEventKeyModifiers() == 0) && bit_test(keymap.bits, virtualKeycodeForSpace)) { - //The user pressed the space bar. This skips the delay; the user wants to pop the spring on this tab *now*. - - //For some reason, it crashes if I call -fire here. I don't know why. It doesn't crash if I simply set the fire date to now. - [_springTimer setFireDate:[NSDate date]]; - } else {*/ - //Wind the spring for a spring-loaded drop. - //The delay time comes from Finder's defaults, which specifies it in milliseconds. - //If the delegate can't handle our spring-loaded drop, we'll abort it when the timer fires. See fireSpring:. This is simpler than constantly (checking for spring-loaded awareness and tearing down/rebuilding the timer) at every delegate change. - - //If the user has dragged to a different tab, reset the timer. - if(_tabViewItemWithSpring != [cell representedObject]) { - [_springTimer invalidate]; - [_springTimer release]; _springTimer = nil; - _tabViewItemWithSpring = [cell representedObject]; - } - if(!_springTimer) { - //Finder's default delay time, as of Tiger, is 668 ms. If the user has never changed it, there's no setting in its defaults, so we default to that amount. - NSNumber *delayNumber = [(NSNumber *)CFPreferencesCopyAppValue((CFStringRef)@"SpringingDelayMilliseconds", (CFStringRef)@"com.apple.finder") autorelease]; - NSTimeInterval delaySeconds = delayNumber ?[delayNumber doubleValue] / 1000.0 : 0.668; - _springTimer = [[NSTimer scheduledTimerWithTimeInterval:delaySeconds - target:self - selector:@selector(fireSpring:) - userInfo:sender - repeats:NO] retain]; - } - return NSDragOperationCopy; - } - - return NSDragOperationNone; -} - -- (void)draggingExited:(id <NSDraggingInfo>)sender { - [_springTimer invalidate]; - [_springTimer release]; _springTimer = nil; - - [[PSMTabDragAssistant sharedDragAssistant] draggingExitedTabBar:self]; -} - -- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender { - //validate the drag operation only if there's a valid tab bar to drop into - return [[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] == NSNotFound || - [[PSMTabDragAssistant sharedDragAssistant] destinationTabBar] != nil; -} - -- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { - if([[[sender draggingPasteboard] types] indexOfObject:@"PSMTabBarControlItemPBType"] != NSNotFound) { - [[PSMTabDragAssistant sharedDragAssistant] performDragOperation]; - } else if([self delegate] && [[self delegate] respondsToSelector:@selector(tabView:acceptedDraggingInfo:onTabViewItem:)]) { - //forward the drop to the delegate - [[self delegate] tabView:tabView acceptedDraggingInfo:sender onTabViewItem:[[self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil] representedObject]]; - } - return YES; -} - -- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation { - [[PSMTabDragAssistant sharedDragAssistant] draggedImageEndedAt:aPoint operation:operation]; -} - -- (void)concludeDragOperation:(id <NSDraggingInfo>)sender { -} - -#pragma mark - -#pragma mark Spring-loading - -- (void)fireSpring:(NSTimer *)timer { - NSAssert1(timer == _springTimer, @"Spring fired by unrecognized timer %@", timer); - - id <NSDraggingInfo> sender = [timer userInfo]; - PSMTabBarCell *cell = [self cellForPoint:[self convertPoint:[sender draggingLocation] fromView:nil] cellFrame:nil]; - [tabView selectTabViewItem:[cell representedObject]]; - - _tabViewItemWithSpring = nil; - [_springTimer invalidate]; - [_springTimer release]; _springTimer = nil; -} - -#pragma mark - -#pragma mark Actions - -- (void)overflowMenuAction:(id)sender { - NSTabViewItem *tabViewItem = (NSTabViewItem *)[sender representedObject]; - [tabView selectTabViewItem:tabViewItem]; -} - -- (void)closeTabClick:(id)sender { - NSTabViewItem *item = [sender representedObject]; - [sender retain]; - if(([_cells count] == 1) && (![self canCloseOnlyTab])) { - return; - } - - if([[self delegate] respondsToSelector:@selector(tabView:shouldCloseTabViewItem:)]) { - if(![[self delegate] tabView:tabView shouldCloseTabViewItem:item]) { - // fix mouse downed close button - [sender setCloseButtonPressed:NO]; - return; - } - } - - [item retain]; - - [tabView removeTabViewItem:item]; - [item release]; - [sender release]; -} - -- (void)tabClick:(id)sender { - [tabView selectTabViewItem:[sender representedObject]]; -} - -- (void)tabNothing:(id)sender { - //[self update]; // takes care of highlighting based on state -} - -- (void)frameDidChange:(NSNotification *)notification { - [self _checkWindowFrame]; - - // trying to address the drawing artifacts for the progress indicators - hackery follows - // this one fixes the "blanking" effect when the control hides and shows itself - NSEnumerator *e = [_cells objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - [[cell indicator] stopAnimation:self]; - - [[cell indicator] performSelector:@selector(startAnimation:) - withObject:nil - afterDelay:0]; - } - - [self update:NO]; -} - -- (void)viewDidMoveToWindow { - [self _checkWindowFrame]; -} - -- (void)viewWillStartLiveResize { - NSEnumerator *e = [_cells objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - [[cell indicator] stopAnimation:self]; - } - [self setNeedsDisplay:YES]; -} - --(void)viewDidEndLiveResize { - NSEnumerator *e = [_cells objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - [[cell indicator] startAnimation:self]; - } - - [self _checkWindowFrame]; - [self update:NO]; -} - -- (void)resetCursorRects { - [super resetCursorRects]; - if([self orientation] == PSMTabBarVerticalOrientation) { - NSRect frame = [self frame]; - [self addCursorRect:NSMakeRect(frame.size.width - 2, 0, 2, frame.size.height) cursor:[NSCursor resizeLeftRightCursor]]; - } -} - -- (void)windowDidMove:(NSNotification *)aNotification { - [self setNeedsDisplay:YES]; -} - -- (void)windowDidUpdate:(NSNotification *)notification { - // hide? must readjust things if I'm not supposed to be showing - // this block of code only runs when the app launches - if([self hideForSingleTab] && ([_cells count] <= 1) && !_awakenedFromNib) { - // must adjust frames now before display - NSRect myFrame = [self frame]; - if([self orientation] == PSMTabBarHorizontalOrientation) { - if(partnerView) { - NSRect partnerFrame = [partnerView frame]; - // above or below me? - if(myFrame.origin.y - 22 > [partnerView frame].origin.y) { - // partner is below me - [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y + 21, myFrame.size.width, myFrame.size.height - 21)]; - [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y, partnerFrame.size.width, partnerFrame.size.height + 21)]; - } else { - // partner is above me - [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, myFrame.size.width, myFrame.size.height - 21)]; - [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y - 21, partnerFrame.size.width, partnerFrame.size.height + 21)]; - } - [partnerView setNeedsDisplay:YES]; - [self setNeedsDisplay:YES]; - } else { - // for window movement - NSRect windowFrame = [[self window] frame]; - [[self window] setFrame:NSMakeRect(windowFrame.origin.x, windowFrame.origin.y + 21, windowFrame.size.width, windowFrame.size.height - 21) display:YES]; - [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, myFrame.size.width, myFrame.size.height - 21)]; - } - } else { - if(partnerView) { - NSRect partnerFrame = [partnerView frame]; - //to the left or right? - if(myFrame.origin.x < [partnerView frame].origin.x) { - // partner is to the left - [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, 1, myFrame.size.height)]; - [partnerView setFrame:NSMakeRect(partnerFrame.origin.x - myFrame.size.width + 1, partnerFrame.origin.y, partnerFrame.size.width + myFrame.size.width - 1, partnerFrame.size.height)]; - } else { - // partner to the right - [self setFrame:NSMakeRect(myFrame.origin.x + myFrame.size.width, myFrame.origin.y, 1, myFrame.size.height)]; - [partnerView setFrame:NSMakeRect(partnerFrame.origin.x, partnerFrame.origin.y, partnerFrame.size.width + myFrame.size.width, partnerFrame.size.height)]; - } - _tabBarWidth = myFrame.size.width; - [partnerView setNeedsDisplay:YES]; - [self setNeedsDisplay:YES]; - } else { - // for window movement - NSRect windowFrame = [[self window] frame]; - [[self window] setFrame:NSMakeRect(windowFrame.origin.x + myFrame.size.width - 1, windowFrame.origin.y, windowFrame.size.width - myFrame.size.width + 1, windowFrame.size.height) display:YES]; - [self setFrame:NSMakeRect(myFrame.origin.x, myFrame.origin.y, 1, myFrame.size.height)]; - } - } - - _isHidden = YES; - - if([[self delegate] respondsToSelector:@selector(tabView:tabBarDidHide:)]) { - [[self delegate] tabView:[self tabView] tabBarDidHide:self]; - } - } - - _awakenedFromNib = YES; - [self setNeedsDisplay:YES]; - - //we only need to do this once - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidUpdateNotification object:nil]; -} - -#pragma mark - -#pragma mark Menu Validation - -- (BOOL)validateMenuItem:(NSMenuItem *)sender { - [sender setState:([[sender representedObject] isEqualTo:[tabView selectedTabViewItem]]) ? NSOnState : NSOffState]; - - return [[self delegate] respondsToSelector:@selector(tabView:validateOverflowMenuItem:forTabViewItem:)] ? - [[self delegate] tabView:[self tabView] validateOverflowMenuItem:sender forTabViewItem:[sender representedObject]] : YES; -} - -#pragma mark - -#pragma mark NSTabView Delegate - -- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem { - // here's a weird one - this message is sent before the "tabViewDidChangeNumberOfTabViewItems" - // message, thus I can end up updating when there are no cells, if no tabs were (yet) present - NSUInteger tabIndex = [aTabView indexOfTabViewItem:tabViewItem]; - - if([_cells count] > 0 && tabIndex < [_cells count]) { - PSMTabBarCell *thisCell = [_cells objectAtIndex:tabIndex]; - if(_alwaysShowActiveTab && [thisCell isInOverflowMenu]) { - //temporarily disable the delegate in order to move the tab to a different index - id tempDelegate = [aTabView delegate]; - [aTabView setDelegate:nil]; - - // move it all around first - [tabViewItem retain]; - [thisCell retain]; - [aTabView removeTabViewItem:tabViewItem]; - [aTabView insertTabViewItem:tabViewItem atIndex:0]; - [_cells removeObjectAtIndex:tabIndex]; - [_cells insertObject:thisCell atIndex:0]; - [thisCell setIsInOverflowMenu:NO]; //very important else we get a fun recursive loop going - [[_cells objectAtIndex:[_cells count] - 1] setIsInOverflowMenu:YES]; //these 2 lines are pretty uncool and this logic needs to be updated - [thisCell release]; - [tabViewItem release]; - - [aTabView setDelegate:tempDelegate]; - - //reset the selection since removing it changed the selection - [aTabView selectTabViewItem:tabViewItem]; - - [self update]; - } else { - [_controller setSelectedCell:thisCell]; - [self setNeedsDisplay:YES]; - } - } - - if([[self delegate] respondsToSelector:@selector(tabView:didSelectTabViewItem:)]) { - [[self delegate] performSelector:@selector(tabView:didSelectTabViewItem:) withObject:aTabView withObject:tabViewItem]; - } -} - -- (BOOL)tabView:(NSTabView *)aTabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem { - if([[self delegate] respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) { - return [[self delegate] tabView:aTabView shouldSelectTabViewItem:tabViewItem]; - } else { - return YES; - } -} -- (void)tabView:(NSTabView *)aTabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem { - if([[self delegate] respondsToSelector:@selector(tabView:willSelectTabViewItem:)]) { - [[self delegate] performSelector:@selector(tabView:willSelectTabViewItem:) withObject:aTabView withObject:tabViewItem]; - } -} - -- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView { - NSArray *tabItems = [tabView tabViewItems]; - // go through cells, remove any whose representedObjects are not in [tabView tabViewItems] - NSEnumerator *e = [[[_cells copy] autorelease] objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - //remove the observer binding - if([cell representedObject] && ![tabItems containsObject:[cell representedObject]]) { - if([[self delegate] respondsToSelector:@selector(tabView:didCloseTabViewItem:)]) { - [[self delegate] tabView:aTabView didCloseTabViewItem:[cell representedObject]]; - } - - [self removeTabForCell:cell]; - } - } - - // go through tab view items, add cell for any not present - NSMutableArray *cellItems = [self representedTabViewItems]; - NSEnumerator *ex = [tabItems objectEnumerator]; - NSTabViewItem *item; - while((item = [ex nextObject])) { - if(![cellItems containsObject:item]) { - [self addTabViewItem:item]; - } - } - - // pass along for other delegate responses - if([[self delegate] respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)]) { - [[self delegate] performSelector:@selector(tabViewDidChangeNumberOfTabViewItems:) withObject:aTabView]; - } - - // reset cursor tracking for the add tab button if one exists - if([self addTabButton]) { - [[self addTabButton] resetCursorRects]; - } -} - -#pragma mark - -#pragma mark Tooltips - -- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData { - if([[self delegate] respondsToSelector:@selector(tabView:toolTipForTabViewItem:)]) { - return [[self delegate] tabView:[self tabView] toolTipForTabViewItem:[[self cellForPoint:point cellFrame:nil] representedObject]]; - } - return nil; -} - -#pragma mark - -#pragma mark Archiving - -- (void)encodeWithCoder:(NSCoder *)aCoder -{ - [super encodeWithCoder:aCoder]; - if ([aCoder allowsKeyedCoding]) { - [aCoder encodeObject:_cells forKey:@"PSMcells"]; - [aCoder encodeObject:tabView forKey:@"PSMtabView"]; - [aCoder encodeObject:_overflowPopUpButton forKey:@"PSMoverflowPopUpButton"]; - [aCoder encodeObject:_addTabButton forKey:@"PSMaddTabButton"]; - [aCoder encodeObject:style forKey:@"PSMstyle"]; - [aCoder encodeInteger:_orientation forKey:@"PSMorientation"]; - [aCoder encodeBool:_canCloseOnlyTab forKey:@"PSMcanCloseOnlyTab"]; - [aCoder encodeBool:_disableTabClose forKey:@"PSMdisableTabClose"]; - [aCoder encodeBool:_hideForSingleTab forKey:@"PSMhideForSingleTab"]; - [aCoder encodeBool:_allowsBackgroundTabClosing forKey:@"PSMallowsBackgroundTabClosing"]; - [aCoder encodeBool:_allowsResizing forKey:@"PSMallowsResizing"]; - [aCoder encodeBool:_selectsTabsOnMouseDown forKey:@"PSMselectsTabsOnMouseDown"]; - [aCoder encodeBool:_showAddTabButton forKey:@"PSMshowAddTabButton"]; - [aCoder encodeBool:_sizeCellsToFit forKey:@"PSMsizeCellsToFit"]; - [aCoder encodeInteger:_cellMinWidth forKey:@"PSMcellMinWidth"]; - [aCoder encodeInteger:_cellMaxWidth forKey:@"PSMcellMaxWidth"]; - [aCoder encodeInteger:_cellOptimumWidth forKey:@"PSMcellOptimumWidth"]; - [aCoder encodeInteger:_currentStep forKey:@"PSMcurrentStep"]; - [aCoder encodeBool:_isHidden forKey:@"PSMisHidden"]; - [aCoder encodeObject:partnerView forKey:@"PSMpartnerView"]; - [aCoder encodeBool:_awakenedFromNib forKey:@"PSMawakenedFromNib"]; - [aCoder encodeObject:_lastMouseDownEvent forKey:@"PSMlastMouseDownEvent"]; - [aCoder encodeObject:delegate forKey:@"PSMdelegate"]; - [aCoder encodeBool:_useOverflowMenu forKey:@"PSMuseOverflowMenu"]; - [aCoder encodeBool:_automaticallyAnimates forKey:@"PSMautomaticallyAnimates"]; - [aCoder encodeBool:_alwaysShowActiveTab forKey:@"PSMalwaysShowActiveTab"]; - } -} - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if (self) { - // Initialization - [self initAddedProperties]; - [self registerForDraggedTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil]]; - - // resize - [self setPostsFrameChangedNotifications:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(frameDidChange:) name:NSViewFrameDidChangeNotification object:self]; - if ([aDecoder allowsKeyedCoding]) { - _cells = [[aDecoder decodeObjectForKey:@"PSMcells"] retain]; - tabView = [[aDecoder decodeObjectForKey:@"PSMtabView"] retain]; - _overflowPopUpButton = [[aDecoder decodeObjectForKey:@"PSMoverflowPopUpButton"] retain]; - _addTabButton = [[aDecoder decodeObjectForKey:@"PSMaddTabButton"] retain]; - style = [[aDecoder decodeObjectForKey:@"PSMstyle"] retain]; - _orientation = (PSMTabBarOrientation)[aDecoder decodeIntegerForKey:@"PSMorientation"]; - _canCloseOnlyTab = [aDecoder decodeBoolForKey:@"PSMcanCloseOnlyTab"]; - _disableTabClose = [aDecoder decodeBoolForKey:@"PSMdisableTabClose"]; - _hideForSingleTab = [aDecoder decodeBoolForKey:@"PSMhideForSingleTab"]; - _allowsBackgroundTabClosing = [aDecoder decodeBoolForKey:@"PSMallowsBackgroundTabClosing"]; - _allowsResizing = [aDecoder decodeBoolForKey:@"PSMallowsResizing"]; - _selectsTabsOnMouseDown = [aDecoder decodeBoolForKey:@"PSMselectsTabsOnMouseDown"]; - _showAddTabButton = [aDecoder decodeBoolForKey:@"PSMshowAddTabButton"]; - _sizeCellsToFit = [aDecoder decodeBoolForKey:@"PSMsizeCellsToFit"]; - _cellMinWidth = [aDecoder decodeIntegerForKey:@"PSMcellMinWidth"]; - _cellMaxWidth = [aDecoder decodeIntegerForKey:@"PSMcellMaxWidth"]; - _cellOptimumWidth = [aDecoder decodeIntegerForKey:@"PSMcellOptimumWidth"]; - _currentStep = [aDecoder decodeIntegerForKey:@"PSMcurrentStep"]; - _isHidden = [aDecoder decodeBoolForKey:@"PSMisHidden"]; - partnerView = [[aDecoder decodeObjectForKey:@"PSMpartnerView"] retain]; - _awakenedFromNib = [aDecoder decodeBoolForKey:@"PSMawakenedFromNib"]; - _lastMouseDownEvent = [[aDecoder decodeObjectForKey:@"PSMlastMouseDownEvent"] retain]; - _useOverflowMenu = [aDecoder decodeBoolForKey:@"PSMuseOverflowMenu"]; - _automaticallyAnimates = [aDecoder decodeBoolForKey:@"PSMautomaticallyAnimates"]; - _alwaysShowActiveTab = [aDecoder decodeBoolForKey:@"PSMalwaysShowActiveTab"]; - delegate = [[aDecoder decodeObjectForKey:@"PSMdelegate"] retain]; - } - } - [self setTarget:self]; - return self; -} - -#pragma mark - -#pragma mark IB Palette - -- (NSSize)minimumFrameSizeFromKnobPosition:(NSInteger)position { - return NSMakeSize(100.0, 22.0); -} - -- (NSSize)maximumFrameSizeFromKnobPosition:(NSInteger)knobPosition { - return NSMakeSize(10000.0, 22.0); -} - -- (void)placeView:(NSRect)newFrame { - // this is called any time the view is resized in IB - [self setFrame:newFrame]; - [self update:NO]; -} - -#pragma mark - -#pragma mark Convenience - -- (void)bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item { - [self _bindPropertiesForCell:cell andTabViewItem:item]; - - // watch for changes in the identifier - [item addObserver:self forKeyPath:@"identifier" options:0 context:nil]; -} - -- (void)_bindPropertiesForCell:(PSMTabBarCell *)cell andTabViewItem:(NSTabViewItem *)item { - // bind the indicator to the represented object's status (if it exists) - [[cell indicator] setHidden:YES]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(isProcessing)]) { - NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary]; - [bindingOptions setObject:NSNegateBooleanTransformerName forKey:@"NSValueTransformerName"]; - [[cell indicator] bind:@"animate" toObject:[item identifier] withKeyPath:@"isProcessing" options:nil]; - [[cell indicator] bind:@"hidden" toObject:[item identifier] withKeyPath:@"isProcessing" options:bindingOptions]; - [[item identifier] addObserver:cell forKeyPath:@"isProcessing" options:0 context:nil]; - } - } - - // bind for the existence of an icon - [cell setHasIcon:NO]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(icon)]) { - NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary]; - [bindingOptions setObject:NSIsNotNilTransformerName forKey:@"NSValueTransformerName"]; - [cell bind:@"hasIcon" toObject:[item identifier] withKeyPath:@"icon" options:bindingOptions]; - [[item identifier] addObserver:cell forKeyPath:@"icon" options:0 context:nil]; - } - } - - // bind for the existence of a counter - [cell setCount:0]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(objectCount)]) { - [cell bind:@"count" toObject:[item identifier] withKeyPath:@"objectCount" options:nil]; - [[item identifier] addObserver:cell forKeyPath:@"objectCount" options:0 context:nil]; - } - } - - // bind for the color of a counter - [cell setCountColor:nil]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(countColor)]) { - [cell bind:@"countColor" toObject:[item identifier] withKeyPath:@"countColor" options:nil]; - [[item identifier] addObserver:cell forKeyPath:@"countColor" options:0 context:nil]; - } - } - - // bind for a large image - [cell setHasLargeImage:NO]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(largeImage)]) { - NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary]; - [bindingOptions setObject:NSIsNotNilTransformerName forKey:@"NSValueTransformerName"]; - [cell bind:@"hasLargeImage" toObject:[item identifier] withKeyPath:@"largeImage" options:bindingOptions]; - [[item identifier] addObserver:cell forKeyPath:@"largeImage" options:0 context:nil]; - } - } - - [cell setIsEdited:NO]; - if([item identifier] != nil) { - if([[[cell representedObject] identifier] respondsToSelector:@selector(isEdited)]) { - [cell bind:@"isEdited" toObject:[item identifier] withKeyPath:@"isEdited" options:nil]; - [[item identifier] addObserver:cell forKeyPath:@"isEdited" options:0 context:nil]; - } - } - - // bind my string value to the label on the represented tab - [cell bind:@"title" toObject:item withKeyPath:@"label" options:nil]; -} - -- (NSMutableArray *)representedTabViewItems { - NSMutableArray *temp = [NSMutableArray arrayWithCapacity:[_cells count]]; - NSEnumerator *e = [_cells objectEnumerator]; - PSMTabBarCell *cell; - while((cell = [e nextObject])) { - if([cell representedObject]) { - [temp addObject:[cell representedObject]]; - } - } - return temp; -} - -- (id)cellForPoint:(NSPoint)point cellFrame:(NSRectPointer)outFrame { - if([self orientation] == PSMTabBarHorizontalOrientation && !NSPointInRect(point, [self genericCellRect])) { - return nil; - } - - NSInteger i, cnt = [_cells count]; - for(i = 0; i < cnt; i++) { - PSMTabBarCell *cell = [_cells objectAtIndex:i]; - - if(NSPointInRect(point, [cell frame])) { - if(outFrame) { - *outFrame = [cell frame]; - } - return cell; - } - } - return nil; -} - -- (PSMTabBarCell *)lastVisibleTab { - NSInteger i, cellCount = [_cells count]; - for(i = 0; i < cellCount; i++) { - if([[_cells objectAtIndex:i] isInOverflowMenu]) { - return [_cells objectAtIndex:(i - 1)]; - } - } - return [_cells objectAtIndex:(cellCount - 1)]; -} - -- (NSInteger)numberOfVisibleTabs { - NSUInteger i, cellCount = 0; - PSMTabBarCell *nextCell; - - for(i = 0; i < [_cells count]; i++) { - nextCell = [_cells objectAtIndex:i]; - - if([nextCell isInOverflowMenu]) { - break; - } - - if(![nextCell isPlaceholder]) { - cellCount++; - } - } - - return cellCount; -} - -#pragma mark - -#pragma mark Accessibility - --(BOOL)accessibilityIsIgnored { - return NO; -} - -- (id)accessibilityAttributeValue:(NSString *)attribute { - id attributeValue = nil; - if([attribute isEqualToString: NSAccessibilityRoleAttribute]) { - attributeValue = NSAccessibilityGroupRole; - } else if([attribute isEqualToString: NSAccessibilityChildrenAttribute]) { - attributeValue = NSAccessibilityUnignoredChildren(_cells); - } else { - attributeValue = [super accessibilityAttributeValue:attribute]; - } - return attributeValue; -} - -- (id)accessibilityHitTest:(NSPoint)point { - id hitTestResult = self; - - NSEnumerator *enumerator = [_cells objectEnumerator]; - PSMTabBarCell *cell = nil; - PSMTabBarCell *highlightedCell = nil; - - while(!highlightedCell && (cell = [enumerator nextObject])) { - if([cell isHighlighted]) { - highlightedCell = cell; - } - } - - if(highlightedCell) { - hitTestResult = [highlightedCell accessibilityHitTest:point]; - } - - return hitTestResult; -} - -@end |