summaryrefslogtreecommitdiff
path: root/frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m')
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabDragAssistant.m1424
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