diff options
Diffstat (limited to 'frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m')
-rw-r--r-- | frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m | 1424 |
1 files changed, 731 insertions, 693 deletions
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m b/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m index 1e3e3684e..0027f8736 100644 --- a/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m +++ b/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m @@ -32,781 +32,819 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; #pragma mark - #pragma mark Creation/Destruction -+ (PSMTabDragAssistant *)sharedDragAssistant { - if(!sharedDragAssistant) { - sharedDragAssistant = [[PSMTabDragAssistant alloc] init]; - } ++ (PSMTabDragAssistant *)sharedDragAssistant +{ + if (!sharedDragAssistant) { + sharedDragAssistant = [[PSMTabDragAssistant alloc] init]; + } - return sharedDragAssistant; + return sharedDragAssistant; } -- (id)init { - if((self = [super init])) { - _sourceTabBar = nil; - _destinationTabBar = nil; - _participatingTabBars = [[NSMutableSet alloc] init]; - _draggedCell = nil; - _animationTimer = nil; - _sineCurveWidths = [[NSMutableArray alloc] initWithCapacity:kPSMTabDragAnimationSteps]; - _targetCell = nil; - _isDragging = NO; - } +- (id)init +{ + if ((self = [super init])) { + _sourceTabBar = nil; + _destinationTabBar = nil; + _participatingTabBars = [[NSMutableSet alloc] init]; + _draggedCell = nil; + _animationTimer = nil; + _sineCurveWidths = [[NSMutableArray alloc] initWithCapacity:kPSMTabDragAnimationSteps]; + _targetCell = nil; + _isDragging = NO; + } - return self; + return self; } - #pragma mark - #pragma mark Accessors -- (PSMTabBarControl *)sourceTabBar { - return _sourceTabBar; +- (PSMTabBarControl *)sourceTabBar +{ + return _sourceTabBar; } -- (void)setSourceTabBar:(PSMTabBarControl *)tabBar { - _sourceTabBar = tabBar; +- (void)setSourceTabBar:(PSMTabBarControl *)tabBar +{ + _sourceTabBar = tabBar; } -- (PSMTabBarControl *)destinationTabBar { - return _destinationTabBar; +- (PSMTabBarControl *)destinationTabBar +{ + return _destinationTabBar; } -- (void)setDestinationTabBar:(PSMTabBarControl *)tabBar { - _destinationTabBar = tabBar; +- (void)setDestinationTabBar:(PSMTabBarControl *)tabBar +{ + _destinationTabBar = tabBar; } -- (PSMTabBarCell *)draggedCell { - return _draggedCell; +- (PSMTabBarCell *)draggedCell +{ + return _draggedCell; } -- (void)setDraggedCell:(PSMTabBarCell *)cell { - _draggedCell = cell; +- (void)setDraggedCell:(PSMTabBarCell *)cell +{ + _draggedCell = cell; } -- (NSInteger)draggedCellIndex { - return _draggedCellIndex; +- (NSInteger)draggedCellIndex +{ + return _draggedCellIndex; } -- (void)setDraggedCellIndex:(NSInteger)value { - _draggedCellIndex = value; +- (void)setDraggedCellIndex:(NSInteger)value +{ + _draggedCellIndex = value; } -- (BOOL)isDragging { - return _isDragging; +- (BOOL)isDragging +{ + return _isDragging; } -- (void)setIsDragging:(BOOL)value { - _isDragging = value; +- (void)setIsDragging:(BOOL)value +{ + _isDragging = value; } -- (NSPoint)currentMouseLoc { - return _currentMouseLoc; +- (NSPoint)currentMouseLoc +{ + return _currentMouseLoc; } -- (void)setCurrentMouseLoc:(NSPoint)point { - _currentMouseLoc = point; +- (void)setCurrentMouseLoc:(NSPoint)point +{ + _currentMouseLoc = point; } -- (PSMTabBarCell *)targetCell { - return _targetCell; +- (PSMTabBarCell *)targetCell +{ + return _targetCell; } -- (void)setTargetCell:(PSMTabBarCell *)cell { - _targetCell = cell; +- (void)setTargetCell:(PSMTabBarCell *)cell +{ + _targetCell = cell; } #pragma mark - #pragma mark Functionality -- (void)startDraggingCell:(PSMTabBarCell *)cell fromTabBar:(PSMTabBarControl *)control withMouseDownEvent:(NSEvent *)event { - [self setIsDragging:YES]; - [self setSourceTabBar:control]; - [self setDestinationTabBar:control]; - [_participatingTabBars addObject:control]; - [self setDraggedCell:cell]; - [self setDraggedCellIndex:[[control cells] indexOfObject:cell]]; - - NSRect cellFrame = [cell frame]; - // list of widths for animation - NSInteger i; - CGFloat cellStepSize = ([control orientation] == PSMTabBarHorizontalOrientation) ? (cellFrame.size.width + 6) : (cellFrame.size.height + 1); - for(i = 0; i < kPSMTabDragAnimationSteps - 1; i++) { - NSInteger thisWidth = (NSInteger)(cellStepSize - ((cellStepSize / 2.0) + ((sin((PI / 2.0) + ((CGFloat)i / (CGFloat)kPSMTabDragAnimationSteps) * PI) * cellStepSize) / 2.0))); - [_sineCurveWidths addObject:[NSNumber numberWithInteger:thisWidth]]; - } - [_sineCurveWidths addObject:[NSNumber numberWithInteger:([control orientation] == PSMTabBarHorizontalOrientation) ? cellFrame.size.width : cellFrame.size.height]]; - - // hide UI buttons - [[control overflowPopUpButton] setHidden:YES]; - [[control addTabButton] setHidden:YES]; - - [[NSCursor closedHandCursor] set]; - - NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - NSImage *dragImage = [cell dragImage]; - [[cell indicator] removeFromSuperview]; - [self distributePlaceholdersInTabBar:control withDraggedCell:cell]; - - if([control isFlipped]) { - cellFrame.origin.y += cellFrame.size.height; - } - [cell setHighlighted:NO]; - NSSize offset = NSZeroSize; - [pboard declareTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil] owner: nil]; - [pboard setString:[[NSNumber numberWithInteger:[[control cells] indexOfObject:cell]] stringValue] forType:@"PSMTabBarControlItemPBType"]; - _animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(animateDrag:) userInfo:nil repeats:YES]; - - [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidBeginNotification object:nil]; - - //retain the control in case the drag operation causes the control to be released - - if([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && - [[control delegate] tabView:[control tabView] shouldDropTabViewItem:[[self draggedCell] representedObject] inTabBar:nil]) { - _currentTearOffStyle = [control tearOffStyle]; - _draggedTab = [[PSMTabDragWindowController alloc] initWithImage:dragImage styleMask:NSWindowStyleMaskBorderless tearOffStyle:_currentTearOffStyle]; - - cellFrame.origin.y -= cellFrame.size.height; - [control dragImage:[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:NO]; - } else { - [control dragImage:dragImage at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:YES]; - } - -} - -- (void)draggingEnteredTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc { - if(_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![self destinationTabBar]) { - [_draggedTab switchImages]; - } - - [self setDestinationTabBar:control]; - [self setCurrentMouseLoc:mouseLoc]; - // hide UI buttons - [[control overflowPopUpButton] setHidden:YES]; - [[control addTabButton] setHidden:YES]; - if([[control cells] count] == 0 || ![[[control cells] objectAtIndex:0] isPlaceholder]) { - [self distributePlaceholdersInTabBar:control]; - } - [_participatingTabBars addObject:control]; - - //tell the drag window to display only the header if there is one - if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow && _draggedView) { - if(_fadeTimer) { - [_fadeTimer invalidate]; - } - - [[_draggedTab window] orderFront:nil]; - _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeOutDragWindow:) userInfo:nil repeats:YES]; - } -} - -- (void)draggingUpdatedInTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc { - if([self destinationTabBar] != control) { - [self setDestinationTabBar:control]; - } - [self setCurrentMouseLoc:mouseLoc]; -} - -- (void)draggingExitedTabBar:(PSMTabBarControl *)control { - if([[control delegate] respondsToSelector:@selector(tabView:shouldAllowTabViewItem:toLeaveTabBar:)] && - ![[control delegate] tabView:[control tabView] shouldAllowTabViewItem:[[self draggedCell] representedObject] toLeaveTabBar:control]) { - return; - } - - [self setDestinationTabBar:nil]; - [self setCurrentMouseLoc:NSMakePoint(-1.0, -1.0)]; - - if(_fadeTimer) { - [_fadeTimer invalidate]; - _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES]; - } else if(_draggedTab) { - if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) { - //create a new floating drag window - if(!_draggedView) { - NSUInteger styleMask; - NSImage *viewImage = [self _imageForViewOfCell:[self draggedCell] styleMask:&styleMask]; - - _draggedView = [[PSMTabDragWindowController alloc] initWithImage:viewImage styleMask:styleMask tearOffStyle:PSMTabBarTearOffAlphaWindow]; - [[_draggedView window] setAlphaValue:0.0]; - } - - NSPoint windowOrigin = [[control window] frame].origin; - - windowOrigin.x -= _dragWindowOffset.width; - windowOrigin.y += _dragWindowOffset.height; - [[_draggedView window] setFrameOrigin:windowOrigin]; - [[_draggedView window] orderWindow:NSWindowBelow relativeTo:[[_draggedTab window] windowNumber]]; - } else if(_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![_draggedTab alternateImage]) { - NSImage *image; - NSSize imageSize; - NSUInteger mask; //we don't need this but we can't pass nil in for the style mask, as some delegate implementations will crash - - if(!(image = [self _miniwindowImageOfWindow:[control window]])) { - image = [[self _imageForViewOfCell:[self draggedCell] styleMask:&mask] copy]; - } - - imageSize = [image size]; - [image setScalesWhenResized:YES]; - - if(imageSize.width > imageSize.height) { - [image setSize:NSMakeSize(125, 125 * (imageSize.height / imageSize.width))]; - } else { - [image setSize:NSMakeSize(125 * (imageSize.width / imageSize.height), 125)]; - } - - [_draggedTab setAlternateImage:image]; - } - - //set the window's alpha mask to zero if the last tab is being dragged - //don't fade out the old window if the delegate doesn't respond to the new tab bar method, just to be safe - if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1 && [self sourceTabBar] == control && - [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) { - [[[self sourceTabBar] window] setAlphaValue:0.0]; - - if([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) { - [[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha]; - } else { - //#warning fix me - what should we do when the last tab is dragged as a miniwindow? - } - } else { - if([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) { - _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES]; - } else { - [_draggedTab switchImages]; - _centersDragWindows = YES; - } - } - } -} - -- (void)performDragOperation { - // move cell - NSUInteger destinationIndex = [[[self destinationTabBar] cells] indexOfObject:[self targetCell]]; - - //there is the slight possibility of the targetCell now being set properly, so avoid errors - if(destinationIndex >= [[[self destinationTabBar] cells] count]) { - destinationIndex = [[[self destinationTabBar] cells] count] - 1; - } - - [[[self destinationTabBar] cells] replaceObjectAtIndex:destinationIndex withObject:[self draggedCell]]; - [[self draggedCell] setControlView:[self destinationTabBar]]; - - // move actual NSTabViewItem - if([self sourceTabBar] != [self destinationTabBar]) { - //remove the tracking rects and bindings registered on the old tab - [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]]; - [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]]; - [[self sourceTabBar] removeTabForCell:[self draggedCell]]; - - NSUInteger i, insertIndex; - NSArray *cells = [[self destinationTabBar] cells]; - - //find the index of where the dragged cell was just dropped - for(i = 0, insertIndex = 0; (i < [cells count]) && ([cells objectAtIndex:i] != [self draggedCell]); i++, insertIndex++) { - if([[cells objectAtIndex:i] isPlaceholder]) { - insertIndex--; - } - } - - [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]]; - [[[self destinationTabBar] tabView] insertTabViewItem:[[self draggedCell] representedObject] atIndex:insertIndex]; - - //calculate the position for the dragged cell - if([[self destinationTabBar] automaticallyAnimates]) { - if(insertIndex > 0) { - NSRect cellRect = [[cells objectAtIndex:insertIndex - 1] frame]; - cellRect.origin.x += cellRect.size.width; - [[self draggedCell] setFrame:cellRect]; - } - } - - //rebind the cell to the new control - [[self destinationTabBar] bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]]; - - //select the newly moved item in the destination tab view - [[[self destinationTabBar] tabView] selectTabViewItem:[[self draggedCell] representedObject]]; - } else { - //have to do this before checking the index of a cell otherwise placeholders will be counted - [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]]; - - //rearrange the tab view items - NSTabView *tabView = [[self sourceTabBar] tabView]; - NSTabViewItem *item = [[self draggedCell] representedObject]; - BOOL reselect = ([tabView selectedTabViewItem] == item); - NSArray *cells = [[self sourceTabBar] cells]; - NSUInteger index; - //find the index of where the dragged cell was just dropped - for(index = 0; index < [cells count] && [cells objectAtIndex:index] != [self draggedCell]; index++) { - ; - } - - //temporarily disable the delegate in order to move the tab to a different index - id tempDelegate = [tabView delegate]; - [tabView setDelegate:nil]; - [tabView removeTabViewItem:item]; - [tabView insertTabViewItem:item atIndex:index]; - if(reselect) { - [tabView selectTabViewItem:item]; - } - [tabView setDelegate:tempDelegate]; - } - - if(([self sourceTabBar] != [self destinationTabBar] || [[[self sourceTabBar] cells] indexOfObject:[self draggedCell]] != _draggedCellIndex) && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) { - [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:[self destinationTabBar]]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil]; - - [self finishDrag]; -} - -- (void)draggedImageEndedAt:(NSPoint)aPoint operation:(NSDragOperation)operation { - if([self isDragging]) { // means there was not a successful drop (performDragOperation) - id sourceDelegate = [[self sourceTabBar] delegate]; - - //split off the dragged tab into a new window - if([self destinationTabBar] == nil && - sourceDelegate && [sourceDelegate respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && - [sourceDelegate tabView:[[self sourceTabBar] tabView] shouldDropTabViewItem:[[self draggedCell] representedObject] inTabBar:nil] && - [sourceDelegate respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) { - PSMTabBarControl *control = [sourceDelegate tabView:[[self sourceTabBar] tabView] newTabBarForDraggedTabViewItem:[[self draggedCell] representedObject] atPoint:aPoint]; - - if(control) { - //add the dragged tab to the new window - [[control cells] insertObject:[self draggedCell] atIndex:0]; - - //remove the tracking rects and bindings registered on the old tab - [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]]; - [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]]; - [[self sourceTabBar] removeTabForCell:[self draggedCell]]; - - //rebind the cell to the new control - [control bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]]; - - [[self draggedCell] setControlView:control]; - - [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]]; - - [[control tabView] addTabViewItem:[[self draggedCell] representedObject]]; - [control update:NO]; //make sure the new tab is set in the correct position - - if(_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) { - [[control window] makeKeyAndOrderFront:nil]; - } else { - //center the window over where we ended dragging - [self _expandWindow:[control window] atPoint:[NSEvent mouseLocation]]; - } - - if([sourceDelegate respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) { - [sourceDelegate tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:control]; - } - } else { - NSLog(@"Delegate returned no control to add to."); - [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]]; - } - } else { - // put cell back - [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]]; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil]; - - [self finishDrag]; - } -} - -- (void)finishDrag { - if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 0 && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:closeWindowForLastTabViewItem:)]) { - [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] closeWindowForLastTabViewItem:[[self draggedCell] representedObject]]; - } - - if(_draggedTab) { - [[_draggedTab window] orderOut:nil]; - _draggedTab = nil; - } - - if(_draggedView) { - [[_draggedView window] orderOut:nil]; - _draggedView = nil; - } - - _centersDragWindows = NO; - - [self setIsDragging:NO]; - [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]]; - [self setSourceTabBar:nil]; - [self setDestinationTabBar:nil]; - NSEnumerator *e = [_participatingTabBars objectEnumerator]; - PSMTabBarControl *tabBar; - while((tabBar = [e nextObject])) { - [self removeAllPlaceholdersFromTabBar:tabBar]; - } - [_participatingTabBars removeAllObjects]; - [self setDraggedCell:nil]; - [_animationTimer invalidate]; - _animationTimer = nil; - [_sineCurveWidths removeAllObjects]; - [self setTargetCell:nil]; -} - -- (void)draggingBeganAt:(NSPoint)aPoint { - if(_draggedTab) { - [[_draggedTab window] setFrameTopLeftPoint:aPoint]; - [[_draggedTab window] orderFront:nil]; - - if([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1) { - [self draggingExitedTabBar:[self sourceTabBar]]; - [[_draggedTab window] setAlphaValue:0.0]; - } - } -} - -- (void)draggingMovedTo:(NSPoint)aPoint { - if(_draggedTab) { - if(_centersDragWindows) { - if([_draggedTab isAnimating]) { - return; - } - - //Ignore aPoint, as it seems to give wacky values - NSRect frame = [[_draggedTab window] frame]; - frame.origin = [NSEvent mouseLocation]; - frame.origin.x -= frame.size.width / 2; - frame.origin.y -= frame.size.height / 2; - [[_draggedTab window] setFrame:frame display:NO]; - } else { - [[_draggedTab window] setFrameTopLeftPoint:aPoint]; - } - - if(_draggedView) { - //move the view representation with the tab - //the relative position of the dragged view window will be different - //depending on the position of the tab bar relative to the controlled tab view - - aPoint.y -= [[_draggedTab window] frame].size.height; - aPoint.x -= _dragWindowOffset.width; - aPoint.y += _dragWindowOffset.height; - [[_draggedView window] setFrameTopLeftPoint:aPoint]; - } - } -} - -- (void)fadeInDragWindow:(NSTimer *)timer { - CGFloat value = [[_draggedView window] alphaValue]; - if(value >= kPSMTabDragWindowAlpha || _draggedTab == nil) { - [timer invalidate]; - _fadeTimer = nil; - } else { - [[_draggedTab window] setAlphaValue:[[_draggedTab window] alphaValue] - kPSMTabDragAlphaInterval]; - [[_draggedView window] setAlphaValue:value + kPSMTabDragAlphaInterval]; - } -} - -- (void)fadeOutDragWindow:(NSTimer *)timer { - CGFloat value = [[_draggedView window] alphaValue]; - NSWindow *tabWindow = [_draggedTab window], *viewWindow = [_draggedView window]; - - if(value <= 0.0) { - [viewWindow setAlphaValue:0.0]; - [tabWindow setAlphaValue:kPSMTabDragWindowAlpha]; - - [timer invalidate]; - _fadeTimer = nil; - } else { - if([tabWindow alphaValue] < kPSMTabDragWindowAlpha) { - [tabWindow setAlphaValue:[tabWindow alphaValue] + kPSMTabDragAlphaInterval]; - } - [viewWindow setAlphaValue:value - kPSMTabDragAlphaInterval]; - } +- (void)startDraggingCell:(PSMTabBarCell *)cell fromTabBar:(PSMTabBarControl *)control withMouseDownEvent:(NSEvent *)event +{ + [self setIsDragging:YES]; + [self setSourceTabBar:control]; + [self setDestinationTabBar:control]; + [_participatingTabBars addObject:control]; + [self setDraggedCell:cell]; + [self setDraggedCellIndex:[[control cells] indexOfObject:cell]]; + + NSRect cellFrame = [cell frame]; + // list of widths for animation + NSInteger i; + CGFloat cellStepSize = ([control orientation] == PSMTabBarHorizontalOrientation) ? (cellFrame.size.width + 6) : (cellFrame.size.height + 1); + for (i = 0; i < kPSMTabDragAnimationSteps - 1; i++) { + NSInteger thisWidth = (NSInteger)(cellStepSize - ((cellStepSize / 2.0) + ((sin((PI / 2.0) + ((CGFloat)i / (CGFloat)kPSMTabDragAnimationSteps) * PI) * cellStepSize) / 2.0))); + [_sineCurveWidths addObject:[NSNumber numberWithInteger:thisWidth]]; + } + [_sineCurveWidths addObject:[NSNumber numberWithInteger:([control orientation] == PSMTabBarHorizontalOrientation) ? cellFrame.size.width : cellFrame.size.height]]; + + // hide UI buttons + [[control overflowPopUpButton] setHidden:YES]; + [[control addTabButton] setHidden:YES]; + + [[NSCursor closedHandCursor] set]; + + NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + NSImage *dragImage = [cell dragImage]; + [[cell indicator] removeFromSuperview]; + [self distributePlaceholdersInTabBar:control withDraggedCell:cell]; + + if ([control isFlipped]) { + cellFrame.origin.y += cellFrame.size.height; + } + [cell setHighlighted:NO]; + NSSize offset = NSZeroSize; + [pboard declareTypes:[NSArray arrayWithObjects:@"PSMTabBarControlItemPBType", nil] owner:nil]; + [pboard setString:[[NSNumber numberWithInteger:[[control cells] indexOfObject:cell]] stringValue] forType:@"PSMTabBarControlItemPBType"]; + _animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 30.0) target:self selector:@selector(animateDrag:) userInfo:nil repeats:YES]; + + [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidBeginNotification object:nil]; + + //retain the control in case the drag operation causes the control to be released + + if ([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && + [[control delegate] tabView:[control tabView] + shouldDropTabViewItem:[[self draggedCell] representedObject] + inTabBar:nil]) { + _currentTearOffStyle = [control tearOffStyle]; + _draggedTab = [[PSMTabDragWindowController alloc] initWithImage:dragImage styleMask:NSWindowStyleMaskBorderless tearOffStyle:_currentTearOffStyle]; + + cellFrame.origin.y -= cellFrame.size.height; + [control dragImage:[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:NO]; + } else { + [control dragImage:dragImage at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:YES]; + } +} + +- (void)draggingEnteredTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc +{ + if (_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![self destinationTabBar]) { + [_draggedTab switchImages]; + } + + [self setDestinationTabBar:control]; + [self setCurrentMouseLoc:mouseLoc]; + // hide UI buttons + [[control overflowPopUpButton] setHidden:YES]; + [[control addTabButton] setHidden:YES]; + if ([[control cells] count] == 0 || ![[[control cells] objectAtIndex:0] isPlaceholder]) { + [self distributePlaceholdersInTabBar:control]; + } + [_participatingTabBars addObject:control]; + + //tell the drag window to display only the header if there is one + if (_currentTearOffStyle == PSMTabBarTearOffAlphaWindow && _draggedView) { + if (_fadeTimer) { + [_fadeTimer invalidate]; + } + + [[_draggedTab window] orderFront:nil]; + _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeOutDragWindow:) userInfo:nil repeats:YES]; + } +} + +- (void)draggingUpdatedInTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc +{ + if ([self destinationTabBar] != control) { + [self setDestinationTabBar:control]; + } + [self setCurrentMouseLoc:mouseLoc]; +} + +- (void)draggingExitedTabBar:(PSMTabBarControl *)control +{ + if ([[control delegate] respondsToSelector:@selector(tabView:shouldAllowTabViewItem:toLeaveTabBar:)] && ![[control delegate] tabView:[control tabView] shouldAllowTabViewItem:[[self draggedCell] representedObject] toLeaveTabBar:control]) { + return; + } + + [self setDestinationTabBar:nil]; + [self setCurrentMouseLoc:NSMakePoint(-1.0, -1.0)]; + + if (_fadeTimer) { + [_fadeTimer invalidate]; + _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES]; + } else if (_draggedTab) { + if (_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) { + //create a new floating drag window + if (!_draggedView) { + NSUInteger styleMask; + NSImage *viewImage = [self _imageForViewOfCell:[self draggedCell] styleMask:&styleMask]; + + _draggedView = [[PSMTabDragWindowController alloc] initWithImage:viewImage styleMask:styleMask tearOffStyle:PSMTabBarTearOffAlphaWindow]; + [[_draggedView window] setAlphaValue:0.0]; + } + + NSPoint windowOrigin = [[control window] frame].origin; + + windowOrigin.x -= _dragWindowOffset.width; + windowOrigin.y += _dragWindowOffset.height; + [[_draggedView window] setFrameOrigin:windowOrigin]; + [[_draggedView window] orderWindow:NSWindowBelow relativeTo:[[_draggedTab window] windowNumber]]; + } else if (_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![_draggedTab alternateImage]) { + NSImage *image; + NSSize imageSize; + NSUInteger mask; //we don't need this but we can't pass nil in for the style mask, as some delegate implementations will crash + + if (!(image = [self _miniwindowImageOfWindow:[control window]])) { + image = [[self _imageForViewOfCell:[self draggedCell] styleMask:&mask] copy]; + } + + imageSize = [image size]; + [image setScalesWhenResized:YES]; + + if (imageSize.width > imageSize.height) { + [image setSize:NSMakeSize(125, 125 * (imageSize.height / imageSize.width))]; + } else { + [image setSize:NSMakeSize(125 * (imageSize.width / imageSize.height), 125)]; + } + + [_draggedTab setAlternateImage:image]; + } + + //set the window's alpha mask to zero if the last tab is being dragged + //don't fade out the old window if the delegate doesn't respond to the new tab bar method, just to be safe + if ([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1 && [self sourceTabBar] == control && + [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) { + [[[self sourceTabBar] window] setAlphaValue:0.0]; + + if ([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) { + [[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha]; + } else { + //#warning fix me - what should we do when the last tab is dragged as a miniwindow? + } + } else { + if ([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) { + _fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(fadeInDragWindow:) userInfo:nil repeats:YES]; + } else { + [_draggedTab switchImages]; + _centersDragWindows = YES; + } + } + } +} + +- (void)performDragOperation +{ + // move cell + NSUInteger destinationIndex = [[[self destinationTabBar] cells] indexOfObject:[self targetCell]]; + + //there is the slight possibility of the targetCell now being set properly, so avoid errors + if (destinationIndex >= [[[self destinationTabBar] cells] count]) { + destinationIndex = [[[self destinationTabBar] cells] count] - 1; + } + + [[[self destinationTabBar] cells] replaceObjectAtIndex:destinationIndex withObject:[self draggedCell]]; + [[self draggedCell] setControlView:[self destinationTabBar]]; + + // move actual NSTabViewItem + if ([self sourceTabBar] != [self destinationTabBar]) { + //remove the tracking rects and bindings registered on the old tab + [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]]; + [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]]; + [[self sourceTabBar] removeTabForCell:[self draggedCell]]; + + NSUInteger i, insertIndex; + NSArray *cells = [[self destinationTabBar] cells]; + + //find the index of where the dragged cell was just dropped + for (i = 0, insertIndex = 0; (i < [cells count]) && ([cells objectAtIndex:i] != [self draggedCell]); i++, insertIndex++) { + if ([[cells objectAtIndex:i] isPlaceholder]) { + insertIndex--; + } + } + + [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]]; + [[[self destinationTabBar] tabView] insertTabViewItem:[[self draggedCell] representedObject] atIndex:insertIndex]; + + //calculate the position for the dragged cell + if ([[self destinationTabBar] automaticallyAnimates]) { + if (insertIndex > 0) { + NSRect cellRect = [[cells objectAtIndex:insertIndex - 1] frame]; + cellRect.origin.x += cellRect.size.width; + [[self draggedCell] setFrame:cellRect]; + } + } + + //rebind the cell to the new control + [[self destinationTabBar] bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]]; + + //select the newly moved item in the destination tab view + [[[self destinationTabBar] tabView] selectTabViewItem:[[self draggedCell] representedObject]]; + } else { + //have to do this before checking the index of a cell otherwise placeholders will be counted + [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]]; + + //rearrange the tab view items + NSTabView *tabView = [[self sourceTabBar] tabView]; + NSTabViewItem *item = [[self draggedCell] representedObject]; + BOOL reselect = ([tabView selectedTabViewItem] == item); + NSArray *cells = [[self sourceTabBar] cells]; + NSUInteger index; + //find the index of where the dragged cell was just dropped + for (index = 0; index < [cells count] && [cells objectAtIndex:index] != [self draggedCell]; index++) { + ; + } + + //temporarily disable the delegate in order to move the tab to a different index + id tempDelegate = [tabView delegate]; + [tabView setDelegate:nil]; + [tabView removeTabViewItem:item]; + [tabView insertTabViewItem:item atIndex:index]; + if (reselect) { + [tabView selectTabViewItem:item]; + } + [tabView setDelegate:tempDelegate]; + } + + if (([self sourceTabBar] != [self destinationTabBar] || [[[self sourceTabBar] cells] indexOfObject:[self draggedCell]] != _draggedCellIndex) && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) { + [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:[self destinationTabBar]]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil]; + + [self finishDrag]; +} + +- (void)draggedImageEndedAt:(NSPoint)aPoint operation:(NSDragOperation)operation +{ + if ([self isDragging]) { // means there was not a successful drop (performDragOperation) + id sourceDelegate = [[self sourceTabBar] delegate]; + + //split off the dragged tab into a new window + if ([self destinationTabBar] == nil && sourceDelegate && [sourceDelegate respondsToSelector:@selector(tabView:shouldDropTabViewItem:inTabBar:)] && + [sourceDelegate tabView:[[self sourceTabBar] tabView] + shouldDropTabViewItem:[[self draggedCell] representedObject] + inTabBar:nil] + && + [sourceDelegate respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) { + PSMTabBarControl *control = [sourceDelegate tabView:[[self sourceTabBar] tabView] newTabBarForDraggedTabViewItem:[[self draggedCell] representedObject] atPoint:aPoint]; + + if (control) { + //add the dragged tab to the new window + [[control cells] insertObject:[self draggedCell] atIndex:0]; + + //remove the tracking rects and bindings registered on the old tab + [[self sourceTabBar] removeTrackingRect:[[self draggedCell] closeButtonTrackingTag]]; + [[self sourceTabBar] removeTrackingRect:[[self draggedCell] cellTrackingTag]]; + [[self sourceTabBar] removeTabForCell:[self draggedCell]]; + + //rebind the cell to the new control + [control bindPropertiesForCell:[self draggedCell] andTabViewItem:[[self draggedCell] representedObject]]; + + [[self draggedCell] setControlView:control]; + + [[[self sourceTabBar] tabView] removeTabViewItem:[[self draggedCell] representedObject]]; + + [[control tabView] addTabViewItem:[[self draggedCell] representedObject]]; + [control update:NO]; //make sure the new tab is set in the correct position + + if (_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) { + [[control window] makeKeyAndOrderFront:nil]; + } else { + //center the window over where we ended dragging + [self _expandWindow:[control window] atPoint:[NSEvent mouseLocation]]; + } + + if ([sourceDelegate respondsToSelector:@selector(tabView:didDropTabViewItem:inTabBar:)]) { + [sourceDelegate tabView:[[self sourceTabBar] tabView] didDropTabViewItem:[[self draggedCell] representedObject] inTabBar:control]; + } + } else { + NSLog(@"Delegate returned no control to add to."); + [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]]; + } + } else { + // put cell back + [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil]; + + [self finishDrag]; + } +} + +- (void)finishDrag +{ + if ([[[self sourceTabBar] tabView] numberOfTabViewItems] == 0 && [[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:closeWindowForLastTabViewItem:)]) { + [[[self sourceTabBar] delegate] tabView:[[self sourceTabBar] tabView] closeWindowForLastTabViewItem:[[self draggedCell] representedObject]]; + } + + if (_draggedTab) { + [[_draggedTab window] orderOut:nil]; + _draggedTab = nil; + } + + if (_draggedView) { + [[_draggedView window] orderOut:nil]; + _draggedView = nil; + } + + _centersDragWindows = NO; + + [self setIsDragging:NO]; + [self removeAllPlaceholdersFromTabBar:[self sourceTabBar]]; + [self setSourceTabBar:nil]; + [self setDestinationTabBar:nil]; + NSEnumerator *e = [_participatingTabBars objectEnumerator]; + PSMTabBarControl *tabBar; + while ((tabBar = [e nextObject])) { + [self removeAllPlaceholdersFromTabBar:tabBar]; + } + [_participatingTabBars removeAllObjects]; + [self setDraggedCell:nil]; + [_animationTimer invalidate]; + _animationTimer = nil; + [_sineCurveWidths removeAllObjects]; + [self setTargetCell:nil]; +} + +- (void)draggingBeganAt:(NSPoint)aPoint +{ + if (_draggedTab) { + [[_draggedTab window] setFrameTopLeftPoint:aPoint]; + [[_draggedTab window] orderFront:nil]; + + if ([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1) { + [self draggingExitedTabBar:[self sourceTabBar]]; + [[_draggedTab window] setAlphaValue:0.0]; + } + } +} + +- (void)draggingMovedTo:(NSPoint)aPoint +{ + if (_draggedTab) { + if (_centersDragWindows) { + if ([_draggedTab isAnimating]) { + return; + } + + //Ignore aPoint, as it seems to give wacky values + NSRect frame = [[_draggedTab window] frame]; + frame.origin = [NSEvent mouseLocation]; + frame.origin.x -= frame.size.width / 2; + frame.origin.y -= frame.size.height / 2; + [[_draggedTab window] setFrame:frame display:NO]; + } else { + [[_draggedTab window] setFrameTopLeftPoint:aPoint]; + } + + if (_draggedView) { + //move the view representation with the tab + //the relative position of the dragged view window will be different + //depending on the position of the tab bar relative to the controlled tab view + + aPoint.y -= [[_draggedTab window] frame].size.height; + aPoint.x -= _dragWindowOffset.width; + aPoint.y += _dragWindowOffset.height; + [[_draggedView window] setFrameTopLeftPoint:aPoint]; + } + } +} + +- (void)fadeInDragWindow:(NSTimer *)timer +{ + CGFloat value = [[_draggedView window] alphaValue]; + if (value >= kPSMTabDragWindowAlpha || _draggedTab == nil) { + [timer invalidate]; + _fadeTimer = nil; + } else { + [[_draggedTab window] setAlphaValue:[[_draggedTab window] alphaValue] - kPSMTabDragAlphaInterval]; + [[_draggedView window] setAlphaValue:value + kPSMTabDragAlphaInterval]; + } +} + +- (void)fadeOutDragWindow:(NSTimer *)timer +{ + CGFloat value = [[_draggedView window] alphaValue]; + NSWindow *tabWindow = [_draggedTab window], *viewWindow = [_draggedView window]; + + if (value <= 0.0) { + [viewWindow setAlphaValue:0.0]; + [tabWindow setAlphaValue:kPSMTabDragWindowAlpha]; + + [timer invalidate]; + _fadeTimer = nil; + } else { + if ([tabWindow alphaValue] < kPSMTabDragWindowAlpha) { + [tabWindow setAlphaValue:[tabWindow alphaValue] + kPSMTabDragAlphaInterval]; + } + [viewWindow setAlphaValue:value - kPSMTabDragAlphaInterval]; + } } #pragma mark - #pragma mark Private -- (NSImage *)_imageForViewOfCell:(PSMTabBarCell *)cell styleMask:(NSUInteger *)outMask { - PSMTabBarControl *control = [cell controlView]; - NSImage *viewImage = nil; +- (NSImage *)_imageForViewOfCell:(PSMTabBarCell *)cell styleMask:(NSUInteger *)outMask +{ + PSMTabBarControl *control = [cell controlView]; + NSImage *viewImage = nil; - if(outMask) { - *outMask = NSWindowStyleMaskBorderless; - } + if (outMask) { + *outMask = NSWindowStyleMaskBorderless; + } - if([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:imageForTabViewItem:offset:styleMask:)]) { - //get a custom image representation of the view to drag from the delegate - NSImage *tabImage = [_draggedTab image]; - NSPoint drawPoint; - _dragWindowOffset = NSZeroSize; - viewImage = [[control delegate] tabView:[control tabView] imageForTabViewItem:[cell representedObject] offset:&_dragWindowOffset styleMask:outMask]; - [viewImage lockFocus]; + if ([control delegate] && [[control delegate] respondsToSelector:@selector(tabView:imageForTabViewItem:offset:styleMask:)]) { + //get a custom image representation of the view to drag from the delegate + NSImage *tabImage = [_draggedTab image]; + NSPoint drawPoint; + _dragWindowOffset = NSZeroSize; + viewImage = [[control delegate] tabView:[control tabView] imageForTabViewItem:[cell representedObject] offset:&_dragWindowOffset styleMask:outMask]; + [viewImage lockFocus]; - //draw the tab into the returned window, that way we don't have two windows being dragged (this assumes the tab will be on the window) - drawPoint = NSMakePoint(_dragWindowOffset.width, [viewImage size].height - _dragWindowOffset.height); + //draw the tab into the returned window, that way we don't have two windows being dragged (this assumes the tab will be on the window) + drawPoint = NSMakePoint(_dragWindowOffset.width, [viewImage size].height - _dragWindowOffset.height); - if([control orientation] == PSMTabBarHorizontalOrientation) { - drawPoint.y += [[control style] tabCellHeight] - [tabImage size].height; - _dragWindowOffset.height -= [[control style] tabCellHeight] - [tabImage size].height; - } else { - drawPoint.x += [control frame].size.width - [tabImage size].width; - } + if ([control orientation] == PSMTabBarHorizontalOrientation) { + drawPoint.y += [[control style] tabCellHeight] - [tabImage size].height; + _dragWindowOffset.height -= [[control style] tabCellHeight] - [tabImage size].height; + } else { + drawPoint.x += [control frame].size.width - [tabImage size].width; + } - [tabImage drawAtPoint:drawPoint fromRect: NSZeroRect operation:NSCompositingOperationSourceOver fraction: 1.0]; + [tabImage drawAtPoint:drawPoint fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0]; - [viewImage unlockFocus]; - } else { - //the delegate doesn't give a custom image, so use an image of the view - NSView *tabView = [[cell representedObject] view]; - viewImage = [[NSImage alloc] initWithSize:[tabView frame].size] ; - [viewImage lockFocus]; - [tabView drawRect:[tabView bounds]]; - [viewImage unlockFocus]; - } + [viewImage unlockFocus]; + } else { + //the delegate doesn't give a custom image, so use an image of the view + NSView *tabView = [[cell representedObject] view]; + viewImage = [[NSImage alloc] initWithSize:[tabView frame].size]; + [viewImage lockFocus]; + [tabView drawRect:[tabView bounds]]; + [viewImage unlockFocus]; + } - if(*outMask | NSWindowStyleMaskBorderless) { - _dragWindowOffset.height += 22; - } + if (*outMask | NSWindowStyleMaskBorderless) { + _dragWindowOffset.height += 22; + } - return viewImage; + return viewImage; } -- (NSImage *)_miniwindowImageOfWindow:(NSWindow *)window { - NSRect rect = [window frame]; - NSImage *image = [[NSImage alloc] initWithSize:rect.size] ; - [image lockFocus]; - rect.origin = NSZeroPoint; - CGContextCopyWindowCaptureContentsToRect([[NSGraphicsContext currentContext] graphicsPort], *(CGRect *)&rect, [NSApp contextID], [window windowNumber], 0); - [image unlockFocus]; +- (NSImage *)_miniwindowImageOfWindow:(NSWindow *)window +{ + NSRect rect = [window frame]; + NSImage *image = [[NSImage alloc] initWithSize:rect.size]; + [image lockFocus]; + rect.origin = NSZeroPoint; + CGContextCopyWindowCaptureContentsToRect([[NSGraphicsContext currentContext] graphicsPort], *(CGRect *)&rect, [NSApp contextID], [window windowNumber], 0); + [image unlockFocus]; - return image; + return image; } -- (void)_expandWindow:(NSWindow *)window atPoint:(NSPoint)point { - NSRect frame = [window frame]; - [window setFrameTopLeftPoint:NSMakePoint(point.x - frame.size.width / 2, point.y + frame.size.height / 2)]; - [window setAlphaValue:0.0]; - [window makeKeyAndOrderFront:nil]; +- (void)_expandWindow:(NSWindow *)window atPoint:(NSPoint)point +{ + NSRect frame = [window frame]; + [window setFrameTopLeftPoint:NSMakePoint(point.x - frame.size.width / 2, point.y + frame.size.height / 2)]; + [window setAlphaValue:0.0]; + [window makeKeyAndOrderFront:nil]; - NSAnimation *animation = [[NSAnimation alloc] initWithDuration:0.25 animationCurve:NSAnimationEaseInOut]; - [animation setAnimationBlockingMode:NSAnimationNonblocking]; - [animation setCurrentProgress:0.1]; - [animation startAnimation]; - NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(_expandWindowTimerFired:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys:window, @"Window", animation, @"Animation", nil] repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode]; + NSAnimation *animation = [[NSAnimation alloc] initWithDuration:0.25 animationCurve:NSAnimationEaseInOut]; + [animation setAnimationBlockingMode:NSAnimationNonblocking]; + [animation setCurrentProgress:0.1]; + [animation startAnimation]; + NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(_expandWindowTimerFired:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys:window, @"Window", animation, @"Animation", nil] repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode]; } -- (void)_expandWindowTimerFired:(NSTimer *)timer { - NSWindow *window = [[timer userInfo] objectForKey:@"Window"]; - NSAnimation *animation = [[timer userInfo] objectForKey:@"Animation"]; - CGAffineTransform transform; - NSPoint translation; - NSRect winFrame = [window frame]; +- (void)_expandWindowTimerFired:(NSTimer *)timer +{ + NSWindow *window = [[timer userInfo] objectForKey:@"Window"]; + NSAnimation *animation = [[timer userInfo] objectForKey:@"Animation"]; + CGAffineTransform transform; + NSPoint translation; + NSRect winFrame = [window frame]; - translation.x = (winFrame.size.width / 2.0); - translation.y = (winFrame.size.height / 2.0); - transform = CGAffineTransformMakeTranslation(translation.x, translation.y); - transform = CGAffineTransformScale(transform, 1.0 / [animation currentValue], 1.0 / [animation currentValue]); - transform = CGAffineTransformTranslate(transform, -translation.x, -translation.y); + translation.x = (winFrame.size.width / 2.0); + translation.y = (winFrame.size.height / 2.0); + transform = CGAffineTransformMakeTranslation(translation.x, translation.y); + transform = CGAffineTransformScale(transform, 1.0 / [animation currentValue], 1.0 / [animation currentValue]); + transform = CGAffineTransformTranslate(transform, -translation.x, -translation.y); - translation.x = -winFrame.origin.x; - translation.y = winFrame.origin.y + winFrame.size.height - [[NSScreen mainScreen] frame].size.height; + translation.x = -winFrame.origin.x; + translation.y = winFrame.origin.y + winFrame.size.height - [[NSScreen mainScreen] frame].size.height; - transform = CGAffineTransformTranslate(transform, translation.x, translation.y); + transform = CGAffineTransformTranslate(transform, translation.x, translation.y); - CGSSetWindowTransform([NSApp contextID], [window windowNumber], transform); + CGSSetWindowTransform([NSApp contextID], [window windowNumber], transform); - [window setAlphaValue:[animation currentValue]]; + [window setAlphaValue:[animation currentValue]]; - if(![animation isAnimating]) { - [timer invalidate]; - } + if (![animation isAnimating]) { + [timer invalidate]; + } } #pragma mark - #pragma mark Animation -- (void)animateDrag:(NSTimer *)timer { - NSEnumerator *e = [[_participatingTabBars copy] objectEnumerator]; - PSMTabBarControl *tabBar; - while((tabBar = [e nextObject])) { - [self calculateDragAnimationForTabBar:tabBar]; - [[NSRunLoop currentRunLoop] performSelector:@selector(display) target:tabBar argument:nil order:1 modes:[NSArray arrayWithObjects:@"NSEventTrackingRunLoopMode", @"NSDefaultRunLoopMode", nil]]; - } -} - -- (void)calculateDragAnimationForTabBar:(PSMTabBarControl *)control { - BOOL removeFlag = YES; - NSMutableArray *cells = [control cells]; - NSInteger i, cellCount = [cells count]; - CGFloat position = [control orientation] == PSMTabBarHorizontalOrientation ?[[control style] leftMarginForTabBarControl] :[[control style] topMarginForTabBarControl]; - - // identify target cell - // mouse at beginning of tabs - NSPoint mouseLoc = [self currentMouseLoc]; - if([self destinationTabBar] == control) { - removeFlag = NO; - if(mouseLoc.x < [[control style] leftMarginForTabBarControl]) { - [self setTargetCell:[cells objectAtIndex:0]]; - } else { - NSRect overCellRect; - PSMTabBarCell *overCell = [control cellForPoint:mouseLoc cellFrame:&overCellRect]; - if(overCell) { - // mouse among cells - placeholder - if([overCell isPlaceholder]) { - [self setTargetCell:overCell]; - } else if([control orientation] == PSMTabBarHorizontalOrientation) { - // non-placeholders - horizontal orientation - if(mouseLoc.x < (overCellRect.origin.x + (overCellRect.size.width / 2.0))) { - // mouse on left side of cell - [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; - } else { - // mouse on right side of cell - [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; - } - } else { - // non-placeholders - vertical orientation - if(mouseLoc.y < (overCellRect.origin.y + (overCellRect.size.height / 2.0))) { - // mouse on top of cell - [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; - } else { - // mouse on bottom of cell - [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; - } - } - } else { - // out at end - must find proper cell (could be more in overflow menu) - [self setTargetCell:[control lastVisibleTab]]; - } - } - } else { - [self setTargetCell:nil]; - } - - for(i = 0; i < cellCount; i++) { - PSMTabBarCell *cell = [cells objectAtIndex:i]; - NSRect newRect = [cell frame]; - if(![cell isInOverflowMenu]) { - if([cell isPlaceholder]) { - if(cell == [self targetCell]) { - [cell setCurrentStep:([cell currentStep] + 1)]; - } else { - [cell setCurrentStep:([cell currentStep] - 1)]; - if([cell currentStep] > 0) { - removeFlag = NO; - } - } - - if([control orientation] == PSMTabBarHorizontalOrientation) { - newRect.size.width = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue]; - } else { - newRect.size.height = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue]; - } - } - } else { - break; - } - - if([control orientation] == PSMTabBarHorizontalOrientation) { - newRect.origin.x = position; - position += newRect.size.width; - } else { - newRect.origin.y = position; - position += newRect.size.height; - } - [cell setFrame:newRect]; - if([cell indicator]) { - [[cell indicator] setFrame:[[control style] indicatorRectForTabCell:cell]]; - } - } - if(removeFlag) { - [_participatingTabBars removeObject:control]; - [self removeAllPlaceholdersFromTabBar:control]; - } +- (void)animateDrag:(NSTimer *)timer +{ + NSEnumerator *e = [[_participatingTabBars copy] objectEnumerator]; + PSMTabBarControl *tabBar; + while ((tabBar = [e nextObject])) { + [self calculateDragAnimationForTabBar:tabBar]; + [[NSRunLoop currentRunLoop] performSelector:@selector(display) target:tabBar argument:nil order:1 modes:[NSArray arrayWithObjects:@"NSEventTrackingRunLoopMode", @"NSDefaultRunLoopMode", nil]]; + } +} + +- (void)calculateDragAnimationForTabBar:(PSMTabBarControl *)control +{ + BOOL removeFlag = YES; + NSMutableArray *cells = [control cells]; + NSInteger i, cellCount = [cells count]; + CGFloat position = [control orientation] == PSMTabBarHorizontalOrientation ? [[control style] leftMarginForTabBarControl] : [[control style] topMarginForTabBarControl]; + + // identify target cell + // mouse at beginning of tabs + NSPoint mouseLoc = [self currentMouseLoc]; + if ([self destinationTabBar] == control) { + removeFlag = NO; + if (mouseLoc.x < [[control style] leftMarginForTabBarControl]) { + [self setTargetCell:[cells objectAtIndex:0]]; + } else { + NSRect overCellRect; + PSMTabBarCell *overCell = [control cellForPoint:mouseLoc cellFrame:&overCellRect]; + if (overCell) { + // mouse among cells - placeholder + if ([overCell isPlaceholder]) { + [self setTargetCell:overCell]; + } else if ([control orientation] == PSMTabBarHorizontalOrientation) { + // non-placeholders - horizontal orientation + if (mouseLoc.x < (overCellRect.origin.x + (overCellRect.size.width / 2.0))) { + // mouse on left side of cell + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; + } else { + // mouse on right side of cell + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; + } + } else { + // non-placeholders - vertical orientation + if (mouseLoc.y < (overCellRect.origin.y + (overCellRect.size.height / 2.0))) { + // mouse on top of cell + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; + } else { + // mouse on bottom of cell + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; + } + } + } else { + // out at end - must find proper cell (could be more in overflow menu) + [self setTargetCell:[control lastVisibleTab]]; + } + } + } else { + [self setTargetCell:nil]; + } + + for (i = 0; i < cellCount; i++) { + PSMTabBarCell *cell = [cells objectAtIndex:i]; + NSRect newRect = [cell frame]; + if (![cell isInOverflowMenu]) { + if ([cell isPlaceholder]) { + if (cell == [self targetCell]) { + [cell setCurrentStep:([cell currentStep] + 1)]; + } else { + [cell setCurrentStep:([cell currentStep] - 1)]; + if ([cell currentStep] > 0) { + removeFlag = NO; + } + } + + if ([control orientation] == PSMTabBarHorizontalOrientation) { + newRect.size.width = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue]; + } else { + newRect.size.height = [[_sineCurveWidths objectAtIndex:[cell currentStep]] integerValue]; + } + } + } else { + break; + } + + if ([control orientation] == PSMTabBarHorizontalOrientation) { + newRect.origin.x = position; + position += newRect.size.width; + } else { + newRect.origin.y = position; + position += newRect.size.height; + } + [cell setFrame:newRect]; + if ([cell indicator]) { + [[cell indicator] setFrame:[[control style] indicatorRectForTabCell:cell]]; + } + } + if (removeFlag) { + [_participatingTabBars removeObject:control]; + [self removeAllPlaceholdersFromTabBar:control]; + } } #pragma mark - #pragma mark Placeholders -- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control withDraggedCell:(PSMTabBarCell *)cell { - // called upon first drag - must distribute placeholders - [self distributePlaceholdersInTabBar:control]; - - NSMutableArray *cells = [control cells]; - - // replace dragged cell with a placeholder, and clean up surrounding cells - NSInteger cellIndex = [cells indexOfObject:cell]; - PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:YES inControlView:control] ; - [cells replaceObjectAtIndex:cellIndex withObject:pc]; - [cells removeObjectAtIndex:(cellIndex + 1)]; - [cells removeObjectAtIndex:(cellIndex - 1)]; - - if(cellIndex - 2 >= 0) { - pc = [cells objectAtIndex:cellIndex - 2]; - [pc setTabState:~[pc tabState] & PSMTab_RightIsSelectedMask]; - } -} - -- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control { - NSUInteger i, numVisibleTabs = [control numberOfVisibleTabs]; - for(i = 0; i < numVisibleTabs; i++) { - PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control] ; - [[control cells] insertObject:pc atIndex:(2 * i)]; - } - - PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control] ; - if([[control cells] count] > (2 * numVisibleTabs)) { - [[control cells] insertObject:pc atIndex:(2 * numVisibleTabs)]; - } else { - [[control cells] addObject:pc]; - } -} - -- (void)removeAllPlaceholdersFromTabBar:(PSMTabBarControl *)control { - NSInteger i, cellCount = [[control cells] count]; - for(i = (cellCount - 1); i >= 0; i--) { - PSMTabBarCell *cell = [[control cells] objectAtIndex:i]; - if([cell isPlaceholder]) { - [control removeTabForCell:cell]; - } - } - // redraw - [control update:NO]; +- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control withDraggedCell:(PSMTabBarCell *)cell +{ + // called upon first drag - must distribute placeholders + [self distributePlaceholdersInTabBar:control]; + + NSMutableArray *cells = [control cells]; + + // replace dragged cell with a placeholder, and clean up surrounding cells + NSInteger cellIndex = [cells indexOfObject:cell]; + PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:YES inControlView:control]; + [cells replaceObjectAtIndex:cellIndex withObject:pc]; + [cells removeObjectAtIndex:(cellIndex + 1)]; + [cells removeObjectAtIndex:(cellIndex - 1)]; + + if (cellIndex - 2 >= 0) { + pc = [cells objectAtIndex:cellIndex - 2]; + [pc setTabState:~[pc tabState] & PSMTab_RightIsSelectedMask]; + } +} + +- (void)distributePlaceholdersInTabBar:(PSMTabBarControl *)control +{ + NSUInteger i, numVisibleTabs = [control numberOfVisibleTabs]; + for (i = 0; i < numVisibleTabs; i++) { + PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control]; + [[control cells] insertObject:pc atIndex:(2 * i)]; + } + + PSMTabBarCell *pc = [[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control]; + if ([[control cells] count] > (2 * numVisibleTabs)) { + [[control cells] insertObject:pc atIndex:(2 * numVisibleTabs)]; + } else { + [[control cells] addObject:pc]; + } +} + +- (void)removeAllPlaceholdersFromTabBar:(PSMTabBarControl *)control +{ + NSInteger i, cellCount = [[control cells] count]; + for (i = (cellCount - 1); i >= 0; i--) { + PSMTabBarCell *cell = [[control cells] objectAtIndex:i]; + if ([cell isPlaceholder]) { + [control removeTabForCell:cell]; + } + } + // redraw + [control update:NO]; } #pragma mark - #pragma mark Archiving -- (void)encodeWithCoder:(NSCoder *)aCoder { - //[super encodeWithCoder:aCoder]; - if([aCoder allowsKeyedCoding]) { - [aCoder encodeObject:_sourceTabBar forKey:@"sourceTabBar"]; - [aCoder encodeObject:_destinationTabBar forKey:@"destinationTabBar"]; - [aCoder encodeObject:_participatingTabBars forKey:@"participatingTabBars"]; - [aCoder encodeObject:_draggedCell forKey:@"draggedCell"]; - [aCoder encodeInteger:_draggedCellIndex forKey:@"draggedCellIndex"]; - [aCoder encodeBool:_isDragging forKey:@"isDragging"]; - [aCoder encodeObject:_animationTimer forKey:@"animationTimer"]; - [aCoder encodeObject:_sineCurveWidths forKey:@"sineCurveWidths"]; - [aCoder encodePoint:_currentMouseLoc forKey:@"currentMouseLoc"]; - [aCoder encodeObject:_targetCell forKey:@"targetCell"]; - } -} - -- (id)initWithCoder:(NSCoder *)aDecoder { - //self = [super initWithCoder:aDecoder]; - //if (self) { - if([aDecoder allowsKeyedCoding]) { - _sourceTabBar = [aDecoder decodeObjectForKey:@"sourceTabBar"] ; - _destinationTabBar = [aDecoder decodeObjectForKey:@"destinationTabBar"] ; - _participatingTabBars = [aDecoder decodeObjectForKey:@"participatingTabBars"] ; - _draggedCell = [aDecoder decodeObjectForKey:@"draggedCell"] ; - _draggedCellIndex = [aDecoder decodeIntegerForKey:@"draggedCellIndex"]; - _isDragging = [aDecoder decodeBoolForKey:@"isDragging"]; - _animationTimer = [aDecoder decodeObjectForKey:@"animationTimer"] ; - _sineCurveWidths = [aDecoder decodeObjectForKey:@"sineCurveWidths"] ; - _currentMouseLoc = [aDecoder decodePointForKey:@"currentMouseLoc"]; - _targetCell = [aDecoder decodeObjectForKey:@"targetCell"] ; - } - //} - return self; +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + //[super encodeWithCoder:aCoder]; + if ([aCoder allowsKeyedCoding]) { + [aCoder encodeObject:_sourceTabBar forKey:@"sourceTabBar"]; + [aCoder encodeObject:_destinationTabBar forKey:@"destinationTabBar"]; + [aCoder encodeObject:_participatingTabBars forKey:@"participatingTabBars"]; + [aCoder encodeObject:_draggedCell forKey:@"draggedCell"]; + [aCoder encodeInteger:_draggedCellIndex forKey:@"draggedCellIndex"]; + [aCoder encodeBool:_isDragging forKey:@"isDragging"]; + [aCoder encodeObject:_animationTimer forKey:@"animationTimer"]; + [aCoder encodeObject:_sineCurveWidths forKey:@"sineCurveWidths"]; + [aCoder encodePoint:_currentMouseLoc forKey:@"currentMouseLoc"]; + [aCoder encodeObject:_targetCell forKey:@"targetCell"]; + } +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + //self = [super initWithCoder:aDecoder]; + //if (self) { + if ([aDecoder allowsKeyedCoding]) { + _sourceTabBar = [aDecoder decodeObjectForKey:@"sourceTabBar"]; + _destinationTabBar = [aDecoder decodeObjectForKey:@"destinationTabBar"]; + _participatingTabBars = [aDecoder decodeObjectForKey:@"participatingTabBars"]; + _draggedCell = [aDecoder decodeObjectForKey:@"draggedCell"]; + _draggedCellIndex = [aDecoder decodeIntegerForKey:@"draggedCellIndex"]; + _isDragging = [aDecoder decodeBoolForKey:@"isDragging"]; + _animationTimer = [aDecoder decodeObjectForKey:@"animationTimer"]; + _sineCurveWidths = [aDecoder decodeObjectForKey:@"sineCurveWidths"]; + _currentMouseLoc = [aDecoder decodePointForKey:@"currentMouseLoc"]; + _targetCell = [aDecoder decodeObjectForKey:@"targetCell"]; + } + //} + return self; } - @end |