From 219afc56c02b508fbb6d706dfed4e1a1ccc949d4 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Wed, 30 Jun 2010 23:44:55 +0000 Subject: Improve tab functionality, behaviour and interaction. PSMTabBar general improvements: - Fix a phantom tab appearing in windows a tab was just dragged out of - Add support for a new control usersSafariStyleDragging property; this causes tabs being dragged inside a tab bar to snap to the tab bar, be drawn at full transparency (also no longer darkening the placeholder position), and alters tab ordering within the tab bar to be based on the tab position rather than the mouse position, for a more Mac-like reordering feel. - Add support for dragging items onto the menubar to cancel the drag - Alter the image of the dragged tab to use a tab drawn onto a transparent background instead of snapshotting a rectangle around the tab, improving drag appearance - Allow tabs to be dragged partially off screen and keep their position instead of snapping back fully onto the screen - Improve behaviour when dragging tabs out of and back into tab bars, or into new windows, resizing the tabs in the target tab bar to improve display and no longer intermittently showing close buttons while dragging - Pull windows to the front as tabs are dragged onto their tab bars - Abstract Custom Query Editor text snippet code, adding a delegate method so code could be moved to the SP window manager. Sequel Pro tab styling improvements: - Improve and clean up tab drawing code - Draw background tabs with shadows as appropriate - Improve logic for how background tab edges are drawn, handling edges cases better (active tab in overflow menu etc) and vastly improving drawing when a tab is being dragged (respect placeholder position when stacking tabs, draw edges on either side) Sequel Pro tab behaviour improvements: - Improve show/hide tab bar interaction - Improve window positioning after creating new windows via a drag - Alter tab dragging out of the tab bar to use an image based on the full window appearance - looks better, and fixes issues like the tab bar background not being drawn while dragging --- Frameworks/PSMTabBar/PSMTabBarCell.m | 38 ++-- Frameworks/PSMTabBar/PSMTabBarControl.h | 5 +- Frameworks/PSMTabBar/PSMTabBarControl.m | 35 ++- Frameworks/PSMTabBar/PSMTabBarController.m | 13 +- Frameworks/PSMTabBar/PSMTabDragAssistant.h | 2 +- Frameworks/PSMTabBar/PSMTabDragAssistant.m | 191 +++++++++++++--- Frameworks/PSMTabBar/PSMTabDragWindow.m | 1 + Frameworks/PSMTabBar/PSMTabDragWindowController.h | 2 +- Frameworks/PSMTabBar/PSMTabDragWindowController.m | 4 +- Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m | 242 +++++++++++++-------- Source/SPDatabaseDocument.m | 2 +- Source/SPWindowController.m | 55 +++-- 12 files changed, 422 insertions(+), 168 deletions(-) diff --git a/Frameworks/PSMTabBar/PSMTabBarCell.m b/Frameworks/PSMTabBar/PSMTabBarCell.m index d35f68ee..7ecaa183 100644 --- a/Frameworks/PSMTabBar/PSMTabBarCell.m +++ b/Frameworks/PSMTabBar/PSMTabBarCell.m @@ -347,8 +347,10 @@ - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { if (_isPlaceholder) { - [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set]; - NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop); + if (![_controlView usesSafariStyleDragging]) { + [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set]; + NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop); + } return; } @@ -400,25 +402,31 @@ { NSRect cellFrame = [(id )[(PSMTabBarControl *)_controlView style] dragRectForTabCell:self orientation:(PSMTabBarOrientation)[(PSMTabBarControl *)_controlView orientation]]; //NSRect cellFrame = [self frame]; - - [_controlView lockFocus]; - NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:cellFrame] autorelease]; - [_controlView unlockFocus]; - NSImage *image = [[[NSImage alloc] initWithSize:[rep size]] autorelease]; - [image addRepresentation:rep]; - NSImage *returnImage = [[[NSImage alloc] initWithSize:[rep size]] autorelease]; - [returnImage lockFocus]; - [image compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeSourceOver fraction:1.0]; - [returnImage unlockFocus]; + + // Determine the target coordinates to draw into + NSRect oldFrame = [self frame]; + NSRect tabDrawFrame = oldFrame; + tabDrawFrame.origin.x -= cellFrame.origin.x; + + // Draw the tab into a new image + NSImage *image = [[[NSImage alloc] initWithSize:cellFrame.size] autorelease]; + [image lockFocusFlipped:YES]; + [self setFrame:tabDrawFrame]; + [(id )[(PSMTabBarControl *)_controlView style] drawTabCell:self]; + [self setFrame:oldFrame]; + [image unlockFocus]; + + // Add the indicator if appropriate if (![[self indicator] isHidden]) { NSImage *pi = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"pi"]]; - [returnImage lockFocus]; + [image lockFocus]; NSPoint indicatorPoint = NSMakePoint([self frame].size.width - MARGIN_X - kPSMTabBarIndicatorWidth, MARGIN_Y); [pi compositeToPoint:indicatorPoint operation:NSCompositeSourceOver fraction:1.0]; - [returnImage unlockFocus]; + [image unlockFocus]; [pi release]; } - return returnImage; + + return image; } #pragma mark - diff --git a/Frameworks/PSMTabBar/PSMTabBarControl.h b/Frameworks/PSMTabBar/PSMTabBarControl.h index c61b92f4..fdfc8f31 100644 --- a/Frameworks/PSMTabBar/PSMTabBarControl.h +++ b/Frameworks/PSMTabBar/PSMTabBarControl.h @@ -79,6 +79,7 @@ enum { BOOL _useOverflowMenu; BOOL _alwaysShowActiveTab; BOOL _allowsScrubbing; + BOOL _useSafariStyleDragging; NSInteger _resizeAreaCompensation; PSMTabBarOrientation _orientation; BOOL _automaticallyAnimates; @@ -157,6 +158,8 @@ enum { - (void)setAlwaysShowActiveTab:(BOOL)value; - (BOOL)allowsScrubbing; - (void)setAllowsScrubbing:(BOOL)value; +- (BOOL)usesSafariStyleDragging; +- (void)setUsesSafariStyleDragging:(BOOL)value; - (PSMTabBarTearOffStyle)tearOffStyle; - (void)setTearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle; @@ -207,7 +210,7 @@ enum { - (BOOL)tabView:(NSTabView *)aTabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl; - (BOOL)tabView:(NSTabView *)aTabView shouldAllowTabViewItem:(NSTabViewItem *)tabViewItem toLeaveTabBar:(PSMTabBarControl *)tabBarControl; - (void)tabView:(NSTabView*)aTabView didDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl; - +- (void)draggingEvent:(id )dragEvent enteredTabBar:(PSMTabBarControl *)tabBarControl tabView:(NSTabViewItem *)tabViewItem; //Tear-off tabs methods - (NSImage *)tabView:(NSTabView *)aTabView imageForTabViewItem:(NSTabViewItem *)tabViewItem offset:(NSSize *)offset styleMask:(NSUInteger *)styleMask; diff --git a/Frameworks/PSMTabBar/PSMTabBarControl.m b/Frameworks/PSMTabBar/PSMTabBarControl.m index d361364e..6753bc08 100644 --- a/Frameworks/PSMTabBar/PSMTabBarControl.m +++ b/Frameworks/PSMTabBar/PSMTabBarControl.m @@ -137,6 +137,7 @@ _selectsTabsOnMouseDown = NO; _alwaysShowActiveTab = NO; _allowsScrubbing = NO; + _useSafariStyleDragging = NO; _cellMinWidth = 100; _cellMaxWidth = 280; _cellOptimumWidth = 130; @@ -594,6 +595,16 @@ _allowsScrubbing = value; } +- (BOOL)usesSafariStyleDragging +{ + return _useSafariStyleDragging; +} + +- (void)setUsesSafariStyleDragging:(BOOL)value +{ + _useSafariStyleDragging = value; +} + - (PSMTabBarTearOffStyle)tearOffStyle { return _tearOffStyle; @@ -1002,8 +1013,9 @@ - (void)update:(BOOL)animate { - // make sure all of our tabs are accounted for before updating - if ([[self tabView] numberOfTabViewItems] != [_cells count]) { + // make sure all of our tabs are accounted for before updating, + // or only proceed if a drag is in progress (where counts may mismatch) + if ([[self tabView] numberOfTabViewItems] != [_cells count] && ![[PSMTabDragAssistant sharedDragAssistant] isDragging]) { return; } @@ -1163,11 +1175,18 @@ - (void)_setupTrackingRectsForCell:(PSMTabBarCell *)cell { + + // Skip tracking rects for placeholders - not required. + if ([cell isPlaceholder]) return; + NSInteger tag, index = [_cells indexOfObject:cell]; NSRect cellTrackingRect = [_controller cellTrackingRectAtIndex:index]; NSPoint mousePoint = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil]; BOOL mouseInCell = NSMouseInRect(mousePoint, cellTrackingRect, [self isFlipped]); - + + // If dragging, suppress mouse interaction + if ([[PSMTabDragAssistant sharedDragAssistant] isDragging]) mouseInCell = NO; + //set the cell tracking rect [self removeTrackingRect:[cell cellTrackingTag]]; tag = [self addTrackingRect:cellTrackingRect owner:cell userData:nil assumeInside:mouseInCell]; @@ -1496,10 +1515,12 @@ userInfo:sender repeats:NO] retain]; } - //If user drags a text string to a tab switch to Custom Query Editor - if (![[[cell representedObject] identifier] isCustomQuerySelected] - && [[[sender draggingPasteboard] types] indexOfObject:NSStringPboardType] != NSNotFound) { - [[[cell representedObject] identifier] performSelector:@selector(viewQuery:) withObject:nil]; + + // Notify the delegate to respond to drag events if supported. This allows custom + // behaviour when dragging certain drag types onto the tab - for example changing the + // view appropriately. + if ([self delegate] && [[self delegate] respondsToSelector:@selector(draggingEvent:enteredTabBar:tabView:)]) { + [[self delegate] draggingEvent:sender enteredTabBar:self tabView:[cell representedObject]]; } } return NSDragOperationCopy; diff --git a/Frameworks/PSMTabBar/PSMTabBarController.m b/Frameworks/PSMTabBar/PSMTabBarController.m index 76f3a91b..62e7a818 100644 --- a/Frameworks/PSMTabBar/PSMTabBarController.m +++ b/Frameworks/PSMTabBar/PSMTabBarController.m @@ -11,6 +11,7 @@ #import "PSMTabBarCell.h" #import "PSMTabStyle.h" #import "NSString_AITruncation.h" +#import "PSMTabDragAssistant.h" #define MAX_OVERFLOW_MENUITEM_TITLE_LENGTH 60 @@ -194,11 +195,13 @@ NSArray *cells = [_control cells]; NSInteger cellCount = [cells count]; - // make sure all of our tabs are accounted for before updating - if ([[_control tabView] numberOfTabViewItems] != cellCount) { + // make sure all of our tabs are accounted for before updating, + // or only proceed if a drag is in progress (where counts may mismatch) + if ([[_control tabView] numberOfTabViewItems] != cellCount && ![[PSMTabDragAssistant sharedDragAssistant] isDragging]) { return; } + // [_cellTrackingRects removeAllObjects]; [_closeButtonTrackingRects removeAllObjects]; [_cellFrames removeAllObjects]; @@ -211,7 +214,7 @@ _addButtonRect.size = [[_control addTabButton] frame].size; if ([_control orientation] == PSMTabBarHorizontalOrientation) { _addButtonRect.origin.y = MARGIN_Y; - _addButtonRect.origin.x += [[cellWidths valueForKeyPath:@"@sum.floatValue"] doubleValue] + 2; + _addButtonRect.origin.x += [[cellWidths valueForKeyPath:@"@sum.floatValue"] doubleValue] + MARGIN_X; } else { _addButtonRect.origin.x = 0; _addButtonRect.origin.y = [[cellWidths lastObject] doubleValue]; @@ -326,8 +329,10 @@ static NSInteger potentialMinimumForArray(NSArray *array, NSInteger minimum) width = [_control cellOptimumWidth]; } - width = ceil(width); + //if ([currentCell isPlaceholder]) width = 1; + width = ceil(width); + //check to see if there is not enough space to place all tabs as preferred if (totalOccupiedWidth + width >= availableWidth) { //There's not enough space to add currentCell at its preferred width! diff --git a/Frameworks/PSMTabBar/PSMTabDragAssistant.h b/Frameworks/PSMTabBar/PSMTabDragAssistant.h index 07703b7d..2f42c573 100644 --- a/Frameworks/PSMTabBar/PSMTabDragAssistant.h +++ b/Frameworks/PSMTabBar/PSMTabDragAssistant.h @@ -22,7 +22,7 @@ PSMTabBarControl *_destinationTabBar; NSMutableSet *_participatingTabBars; PSMTabBarCell *_draggedCell; - NSInteger _draggedCellIndex; // for snap back + NSInteger _draggedCellIndex; // for snap back BOOL _isDragging; // Support for dragging into new windows diff --git a/Frameworks/PSMTabBar/PSMTabDragAssistant.m b/Frameworks/PSMTabBar/PSMTabDragAssistant.m index 9c9eb2a8..29fa036c 100644 --- a/Frameworks/PSMTabBar/PSMTabDragAssistant.m +++ b/Frameworks/PSMTabBar/PSMTabDragAssistant.m @@ -153,6 +153,10 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; - (void)startDraggingCell:(PSMTabBarCell *)cell fromTabBar:(PSMTabBarControl *)control withMouseDownEvent:(NSEvent *)event { + + // Ensure the window is frontmost + [[control window] makeKeyAndOrderFront:self]; + [self setIsDragging:YES]; [self setSourceTabBar:control]; [self setDestinationTabBar:control]; @@ -161,7 +165,8 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; [self setDraggedCellIndex:[[control cells] indexOfObject:cell]]; NSRect cellFrame = [cell frame]; - // list of widths for animation + + // Generate a 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++) { @@ -198,7 +203,7 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; 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:NSBorderlessWindowMask tearOffStyle:_currentTearOffStyle]; + _draggedTab = [[PSMTabDragWindowController alloc] initWithImage:dragImage styleMask:NSBorderlessWindowMask tearOffStyle:_currentTearOffStyle initialAlpha:[control usesSafariStyleDragging]?1:kPSMTabDragWindowAlpha]; cellFrame.origin.y -= cellFrame.size.height; [control dragImage:[[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] autorelease] at:cellFrame.origin offset:offset event:event pasteboard:pboard source:control slideBack:NO]; @@ -211,20 +216,47 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; - (void)draggingEnteredTabBar:(PSMTabBarControl *)control atPoint:(NSPoint)mouseLoc { + + // Bring the new tab window to the front + [[control window] makeKeyAndOrderFront:self]; + if (_currentTearOffStyle == PSMTabBarTearOffMiniwindow && ![self destinationTabBar]) { [_draggedTab switchImages]; } + + // If this is not the starting drag bar... + if ([self sourceTabBar] != [self destinationTabBar] && control != [self destinationTabBar]) { + + // Add a single placeholder to the tab bar and tell the new tab bar to update. + // The placeholder is later removed by distributePlaceholdersInTabBar:. + PSMTabBarCell *pc = [[[PSMTabBarCell alloc] initPlaceholderWithFrame:[[self draggedCell] frame] expanded:NO inControlView:control] autorelease]; + [[control cells] addObject:pc]; + [control update:NO]; + + // Deselect any currently selected tabs after the update + for (PSMTabBarCell *aCell in [control cells]) { + if ([aCell tabState] & PSMTab_SelectedMask) { + [aCell setState:NSOffState]; + [aCell setTabState:PSMTab_PositionMiddleMask]; + break; + } + } + } [self setDestinationTabBar:control]; [self setCurrentMouseLoc:mouseLoc]; - // hide UI buttons - [[control overflowPopUpButton] setHidden:YES]; - [[control addTabButton] setHidden:YES]; + + [_participatingTabBars addObject:control]; + + // Add placeholders if necessary if ([[control cells] count] == 0 || ![[[control cells] objectAtIndex:0] isPlaceholder]) { [self distributePlaceholdersInTabBar:control]; } - [_participatingTabBars addObject:control]; + // hide UI buttons + [[control overflowPopUpButton] setHidden:YES]; + [[control addTabButton] setHidden:YES]; + //tell the drag window to display only the header if there is one if (_currentTearOffStyle == PSMTabBarTearOffAlphaWindow && _draggedView) { if (_fadeTimer) { @@ -264,8 +296,13 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; NSUInteger styleMask; NSImage *viewImage = [self _imageForViewOfCell:[self draggedCell] styleMask:&styleMask]; - _draggedView = [[PSMTabDragWindowController alloc] initWithImage:viewImage styleMask:styleMask tearOffStyle:PSMTabBarTearOffAlphaWindow]; + _draggedView = [[PSMTabDragWindowController alloc] initWithImage:viewImage styleMask:styleMask tearOffStyle:PSMTabBarTearOffAlphaWindow initialAlpha:[control usesSafariStyleDragging]?1:kPSMTabDragWindowAlpha]; [[_draggedView window] setAlphaValue:0.0]; + + // Inform the delegate a new drag window was created to allow any changes + if ([control delegate] && [[control delegate] respondsToSelector:@selector(tabViewDragWindowCreated:)]) { + [[control delegate] tabViewDragWindowCreated:[_draggedView window]]; + } } NSPoint windowOrigin = [[control window] frame].origin; @@ -303,7 +340,7 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; [[[self sourceTabBar] window] setAlphaValue:0.0]; if ([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) { - [[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha]; + [[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha]; } else { #warning fix me - what should we do when the last tab is dragged as a miniwindow? } @@ -333,6 +370,7 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; // 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]]; @@ -404,12 +442,22 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; { 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:)]) { + + // Extract the menu bar rect + NSScreen *menuBarScreen = [[NSScreen screens] objectAtIndex:0]; + NSRect menuBarRect = [menuBarScreen frame]; + menuBarRect.origin.y = menuBarRect.size.height; + menuBarRect.size.height = 22; + + // Split off the dragged tab into a new window. + // Do this if there's no destination tab bar, the delegate approves it, and the delegate supports it - and + // not if the drag ended in the menu bar (which acts as a cancel) + 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:)] + && !NSPointInRect(aPoint, menuBarRect)) + { PSMTabBarControl *control = [sourceDelegate tabView:[[self sourceTabBar] tabView] newTabBarForDraggedTabViewItem:[[self draggedCell] representedObject] atPoint:aPoint]; if (control) { @@ -432,7 +480,11 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; [control update:NO]; //make sure the new tab is set in the correct position if (_currentTearOffStyle == PSMTabBarTearOffAlphaWindow) { + + // Grab the window frame, and show - which moves it fully onto screen - before restoring + NSRect draggedWindowFrame = [[control window] frame]; [[control window] makeKeyAndOrderFront:nil]; + [[control window] setFrame:draggedWindowFrame display:YES]; } else { //center the window over where we ended dragging [self _expandWindow:[control window] atPoint:[NSEvent mouseLocation]]; @@ -447,8 +499,15 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; } } else { + // put cell back [[[self sourceTabBar] cells] insertObject:[self draggedCell] atIndex:[self draggedCellIndex]]; + [[[self sourceTabBar] window] makeKeyAndOrderFront:self]; + + // Restore the window alpha if appropriate + if ([[[self sourceTabBar] tabView] numberOfTabViewItems]) { + [[[self sourceTabBar] window] setAlphaValue:1.0]; + } } [[NSNotificationCenter defaultCenter] postNotificationName:PSMTabDragDidEndNotification object:nil]; @@ -477,21 +536,24 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; _centersDragWindows = NO; - [self setIsDragging:NO]; + [_animationTimer invalidate]; + _animationTimer = nil; + [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; + + [self setDraggedCell:nil]; [_sineCurveWidths removeAllObjects]; [self setTargetCell:nil]; + [self setIsDragging:NO]; } - (void)draggingBeganAt:(NSPoint)aPoint @@ -522,6 +584,22 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; frame.origin.y -= frame.size.height / 2; [[_draggedTab window] setFrame:frame display:NO]; } else { + + // If there is a destination tab bar set to snapping, snap the tab to it. + if ([self destinationTabBar] + && [[self destinationTabBar] usesSafariStyleDragging] + && [[self destinationTabBar] orientation] == PSMTabBarHorizontalOrientation) + { + NSRect windowFrame = [[[self destinationTabBar] window] frame]; + NSPoint dragPointInWindow = [[self destinationTabBar] convertPoint:aPoint fromView:nil]; + + // Vertical snapping + aPoint.y += windowFrame.origin.y + dragPointInWindow.y; + + // Horizontal constraining/snapping + if (dragPointInWindow.x - windowFrame.origin.x < 0) aPoint.x = windowFrame.origin.x; + if (dragPointInWindow.x - windowFrame.origin.x + [[_draggedTab window] frame].size.width > windowFrame.size.width) aPoint.x = windowFrame.origin.x + windowFrame.size.width - [[_draggedTab window] frame].size.width; + } [[_draggedTab window] setFrameTopLeftPoint:aPoint]; } @@ -554,15 +632,16 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; { CGFloat value = [[_draggedView window] alphaValue]; NSWindow *tabWindow = [_draggedTab window], *viewWindow = [_draggedView window]; + float tabWindowAlphaValue = [[self destinationTabBar] usesSafariStyleDragging]?1:kPSMTabDragWindowAlpha; if (value <= 0.0) { [viewWindow setAlphaValue:0.0]; - [tabWindow setAlphaValue:kPSMTabDragWindowAlpha]; + [tabWindow setAlphaValue:tabWindowAlphaValue]; [timer invalidate]; _fadeTimer = nil; } else { - if ([tabWindow alphaValue] < kPSMTabDragWindowAlpha) { + if ([tabWindow alphaValue] < tabWindowAlphaValue) { [tabWindow setAlphaValue:[tabWindow alphaValue] + kPSMTabDragAlphaInterval]; } [viewWindow setAlphaValue:value - kPSMTabDragAlphaInterval]; @@ -693,33 +772,76 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; 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]) { + + // Determine the location of the point to use. + NSPoint targetPoint; + if ([control usesSafariStyleDragging]) { + NSRect draggedTabWindowFrame = [[_draggedTab window] contentRectForFrameRect:[[_draggedTab window] frame]]; + NSRect controlWindowFrame = [[control window] contentRectForFrameRect:[[control window] frame]]; + NSPoint tabTopLeftInWindowCoords = NSMakePoint(draggedTabWindowFrame.origin.x - controlWindowFrame.origin.x, controlWindowFrame.origin.y + (2*controlWindowFrame.size.height) - draggedTabWindowFrame.origin.y); + targetPoint = [control convertPoint:tabTopLeftInWindowCoords fromView:nil]; + targetPoint.x += (draggedTabWindowFrame.size.width / 2.0); + targetPoint.y = 0 - (draggedTabWindowFrame.size.height / 2.0) - targetPoint.y; + } else { + targetPoint = [self currentMouseLoc]; + } + + if (targetPoint.x < [[control style] leftMarginForTabBarControl]) { [self setTargetCell:[cells objectAtIndex:0]]; } else { + + // Identify which cell the mouse is over NSRect overCellRect; - PSMTabBarCell *overCell = [control cellForPoint:mouseLoc cellFrame:&overCellRect]; + PSMTabBarCell *overCell = [control cellForPoint:targetPoint cellFrame:&overCellRect]; if (overCell) { - // mouse among cells - placeholder + + // Mouse is among cells - placeholder if ([overCell isPlaceholder]) { [self setTargetCell:overCell]; + + // Non-placeholder cells - horizontal orientation } 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)]]; + + // Handle Safari-style dragging + if ([control usesSafariStyleDragging]) { + + // Determine the index of the tab the dragged tab is over + NSUInteger overCellIndex = [cells indexOfObject:overCell]; + + // Ensure that drag changes aren't as a result of an animation + NSInteger currentCellStep = [[cells objectAtIndex:(overCellIndex - 1)] currentStep]; + if (!currentCellStep || currentCellStep == kPSMTabDragAnimationSteps - 1) { + + // Center of the tab is past the edge of the tab to the left + if (targetPoint.x < (overCellRect.origin.x + overCellRect.size.width) + && targetPoint.x > (overCellRect.origin.x + overCellRect.size.width/2.0)) + { + [self setTargetCell:[cells objectAtIndex:(overCellIndex - 1)]]; + + // Center of the tab is past the edge of the tab to the right + } else if (targetPoint.x > overCellRect.origin.x) { + [self setTargetCell:[cells objectAtIndex:(overCellIndex + 1)]]; + } + } + + // Handle old-style dragging based on mouse position } else { - // mouse on right side of cell - [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; + + // Mouse is over the left side of the cell + if (targetPoint.x < (overCellRect.origin.x + (overCellRect.size.width / 2.0))) { + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; + + // Otherwise the mouse is over the right side of the cell + } else { + [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] + 1)]]; + } } } else { // non-placeholders - vertical orientation - if (mouseLoc.y < (overCellRect.origin.y + (overCellRect.size.height / 2.0))) { + if (targetPoint.y < (overCellRect.origin.y + (overCellRect.size.height / 2.0))) { // mouse on top of cell [self setTargetCell:[cells objectAtIndex:([cells indexOfObject:overCell] - 1)]]; } else { @@ -823,6 +945,7 @@ static PSMTabDragAssistant *sharedDragAssistant = nil; for (i = (cellCount - 1); i >= 0; i--) { PSMTabBarCell *cell = [[control cells] objectAtIndex:i]; if ([cell isPlaceholder]) { + [NSObject cancelPreviousPerformRequestsWithTarget:cell]; [control removeTabForCell:cell]; } } diff --git a/Frameworks/PSMTabBar/PSMTabDragWindow.m b/Frameworks/PSMTabBar/PSMTabDragWindow.m index 0d07c432..7a6d6bc6 100644 --- a/Frameworks/PSMTabBar/PSMTabDragWindow.m +++ b/Frameworks/PSMTabBar/PSMTabDragWindow.m @@ -26,6 +26,7 @@ [self setLevel:NSStatusWindowLevel]; [self setIgnoresMouseEvents:YES]; [self setOpaque:NO]; + [self setBackgroundColor:[NSColor clearColor]]; [_dragView setImage:image]; diff --git a/Frameworks/PSMTabBar/PSMTabDragWindowController.h b/Frameworks/PSMTabBar/PSMTabDragWindowController.h index 1727d8b8..babfb1a7 100644 --- a/Frameworks/PSMTabBar/PSMTabDragWindowController.h +++ b/Frameworks/PSMTabBar/PSMTabDragWindowController.h @@ -23,7 +23,7 @@ BOOL _showingAlternate; NSRect _originalWindowFrame; } -- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle; +- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle initialAlpha:(CGFloat)initialAlpha; - (NSImage *)image; - (NSImage *)alternateImage; diff --git a/Frameworks/PSMTabBar/PSMTabDragWindowController.m b/Frameworks/PSMTabBar/PSMTabDragWindowController.m index 018bca17..43340786 100644 --- a/Frameworks/PSMTabBar/PSMTabDragWindowController.m +++ b/Frameworks/PSMTabBar/PSMTabDragWindowController.m @@ -12,7 +12,7 @@ @implementation PSMTabDragWindowController -- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle +- (id)initWithImage:(NSImage *)image styleMask:(NSUInteger)styleMask tearOffStyle:(PSMTabBarTearOffStyle)tearOffStyle initialAlpha:(CGFloat)initialAlpha { PSMTabDragWindow *window = [PSMTabDragWindow dragWindowWithImage:image styleMask:styleMask]; if ( (self = [super initWithWindow:window]) ) { @@ -24,7 +24,7 @@ [window setHasShadow:YES]; } - [window setAlphaValue:kPSMTabDragWindowAlpha]; + [window setAlphaValue:initialAlpha]; } return self; } diff --git a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m index 70ceb943..e33aeff8 100644 --- a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m +++ b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m @@ -26,6 +26,7 @@ #import "PSMTabBarCell.h" #import "PSMTabBarControl.h" #import "NSBezierPath_AMShading.h" +#import "PSMTabDragAssistant.h" #define kPSMSequelProObjectCounterRadius 7.0 #define kPSMSequelProCounterMinWidth 20 @@ -133,7 +134,8 @@ if ([cell tabState] & PSMTab_SelectedMask) { if (tabOrientation == PSMTabBarHorizontalOrientation) { - dragRect.size.height -= 2.0; + dragRect.origin.x -= 5.0; + dragRect.size.width += 10.0; } else { dragRect.size.height += 1.0; dragRect.origin.y -= 1.0; @@ -345,7 +347,7 @@ } #pragma mark - -#pragma mark ---- drawing ---- +#pragma mark Drawing // Step 1 - (void)drawTabBar:(PSMTabBarControl *)bar inRect:(NSRect)rect @@ -449,82 +451,143 @@ { NSRect cellFrame = [cell frame]; NSColor *lineColor = nil; + NSColor *fillColor = nil; + NSColor *shadowColor = nil; NSBezierPath *outlineBezier = [NSBezierPath bezierPath]; NSBezierPath *fillBezier = [NSBezierPath bezierPath]; NSPoint center = NSZeroPoint; - BOOL tabBarIsRightOfSelectedTab = NO; - - // Determine if the selected tab is right of this tab - for (PSMTabBarCell *aCell in [tabBar cells]) { - if (aCell == cell) break; - if ([aCell state] == NSOnState) { - tabBarIsRightOfSelectedTab = YES; - break; + NSPoint topLeftArcCenter, bottomLeftArcCenter, topRightArcCenter, bottomRightArcCenter; + BOOL drawRightEdge = YES; + BOOL drawLeftEdge = YES; + + // For cells in the off state, determine whether to draw the edges. + if ([cell state] == NSOffState) { + NSUInteger selectedCellIndex = NSUIntegerMax; + NSUInteger drawingCellIndex = NSUIntegerMax; + NSUInteger firstOverflowedCellIndex = NSUIntegerMax; + + NSUInteger currentIndex = 0; + for (PSMTabBarCell *aCell in [tabBar cells]) { + if (aCell == cell) drawingCellIndex = currentIndex; + if ([aCell state] == NSOnState || ([aCell isPlaceholder] && [aCell currentStep] > 1)) { + selectedCellIndex = currentIndex; + } + if ([aCell isInOverflowMenu]) { + firstOverflowedCellIndex = currentIndex; + break; + } + currentIndex++; + } + + // Draw the left edge if the cell is to the left of the active tab, or if the preceding cell is + // being dragged, and not for the very first cell. + if ((!drawingCellIndex || (drawingCellIndex == 1 && [[[tabBar cells] objectAtIndex:0] isPlaceholder])) + || (drawingCellIndex > selectedCellIndex + && (drawingCellIndex != selectedCellIndex + 1 || ![[[tabBar cells] objectAtIndex:selectedCellIndex] isPlaceholder]))) + { + drawLeftEdge = NO; + } + + // Draw the right edge for tabs to the right, the last tab in the bar, and where the following + // cell is being dragged. + if (drawingCellIndex < selectedCellIndex + && drawingCellIndex != firstOverflowedCellIndex - 1 + && (drawingCellIndex >= selectedCellIndex + 1 || ![[[tabBar cells] objectAtIndex:selectedCellIndex] isPlaceholder])) + { + drawRightEdge = NO; } } - + + // Set up colours if ([[tabBar window] isKeyWindow]) { lineColor = [NSColor darkGrayColor]; + if ([cell state] == NSOnState) { + fillColor = [NSColor colorWithCalibratedWhite:0.59 alpha:1.0]; + shadowColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.7]; + } else { + fillColor = [NSColor colorWithCalibratedWhite:0.495 alpha:1.0]; + shadowColor = [NSColor colorWithCalibratedWhite:0.0 alpha:1.0]; + } } else { lineColor = [NSColor colorWithCalibratedWhite:0.49 alpha:1.0]; + if ([cell state] == NSOnState) { + fillColor = [NSColor colorWithCalibratedWhite:0.81 alpha:1.0]; + shadowColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.4]; + } else { + fillColor = [NSColor colorWithCalibratedWhite:0.685 alpha:1.0]; + shadowColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.7]; + } } - //disable antialiasing of bezier paths [NSGraphicsContext saveGraphicsState]; - [[NSGraphicsContext currentContext] setShouldAntialias:YES]; - NSRect aRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height); - // selected tab - if ([cell state] == NSOnState) { + // If the tab bar is hidden, don't draw the top pixel + if ([tabBar isTabBarHidden]) { + aRect.origin.y++; + aRect.size.height--; + } - // draw top left arc - center = NSMakePoint(aRect.origin.x - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:270 endAngle:360 clockwise:NO]; - - // draw bottom left arc - center = NSMakePoint(aRect.origin.x + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:90 clockwise:YES]; + // Set up the corner bezier paths arc centers + topLeftArcCenter = NSMakePoint(aRect.origin.x - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); + topRightArcCenter = NSMakePoint(aRect.origin.x + aRect.size.width + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); + bottomLeftArcCenter = NSMakePoint(aRect.origin.x + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius); + bottomRightArcCenter = NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius ); - // draw bottom right arc - center = NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius ); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:90 endAngle:0 clockwise:YES]; - - // draw top right arc - center = NSMakePoint(aRect.origin.x + aRect.size.width + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:270 clockwise:NO]; + // Construct the outline path + if (drawLeftEdge) { + [outlineBezier appendBezierPathWithArcWithCenter:topLeftArcCenter radius:kPSMSequelProTabCornerRadius startAngle:270 endAngle:360 clockwise:NO]; + [outlineBezier appendBezierPathWithArcWithCenter:bottomLeftArcCenter radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:90 clockwise:YES]; + } + if (drawRightEdge) { + [outlineBezier appendBezierPathWithArcWithCenter:bottomRightArcCenter radius:kPSMSequelProTabCornerRadius startAngle:90 endAngle:0 clockwise:YES]; + [outlineBezier appendBezierPathWithArcWithCenter:topRightArcCenter radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:270 clockwise:NO]; + } - // Set up a fill bezier with the pieced-together path - [fillBezier appendBezierPath:outlineBezier]; + // Set up a fill bezier based on the outline path + [fillBezier appendBezierPath:outlineBezier]; - // Set the tab outer shadow and draw the shadow - [NSGraphicsContext saveGraphicsState]; - NSShadow *shadow = [[NSShadow alloc] init]; - [shadow setShadowBlurRadius:4]; - [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:[[tabBar window] isKeyWindow]?0.7:0.4]]; - [shadow setShadowOffset:NSMakeSize(0, 0)]; - [shadow set]; - [outlineBezier stroke]; - [shadow release]; - [NSGraphicsContext restoreGraphicsState]; + // If one edge is missing, apply a local fill to the other edge + if (drawRightEdge && !drawLeftEdge) { + [fillBezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y)]; + [fillBezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height)]; + } else if (!drawRightEdge && drawLeftEdge) { + [fillBezier lineToPoint:NSMakePoint(aRect.origin.x + 0.5 + kPSMSequelProTabCornerRadius, aRect.origin.y)]; + } - // Fill the tab with a solid colour - if ([[tabBar window] isKeyWindow]) { - [[NSColor colorWithCalibratedWhite:0.59 alpha:1.0] set]; - } else { - [[NSColor colorWithCalibratedWhite:0.81 alpha:1.0] set]; - } - [fillBezier fill]; + // Set the tab outer shadow and draw the shadow + [NSGraphicsContext saveGraphicsState]; + NSShadow *shadow = [[NSShadow alloc] init]; + [shadow setShadowBlurRadius:4]; + [shadow setShadowColor:shadowColor]; + [shadow setShadowOffset:NSMakeSize(0, 0)]; + [shadow set]; + [outlineBezier stroke]; + [shadow release]; + [NSGraphicsContext restoreGraphicsState]; - // Re-stroke without shadow over the fill. - [lineColor set]; - [outlineBezier stroke]; + // Fill the tab with a solid colour + [fillColor set]; + [fillBezier fill]; - // Add a bottom line to the tab, with a slight inner glow + // Re-stroke without shadow over the fill. + [lineColor set]; + [outlineBezier stroke]; + + // Add a bottom line to the active tab, with a slight inner glow + if ([cell state] == NSOnState) { outlineBezier = [NSBezierPath bezierPath]; - [outlineBezier moveToPoint:NSMakePoint(aRect.origin.x + (2 * kPSMSequelProTabCornerRadius), aRect.origin.y + aRect.size.height - 0.5)]; - [outlineBezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width - (2 * kPSMSequelProTabCornerRadius), aRect.origin.y + aRect.size.height - 0.5)]; + if (drawLeftEdge) { + [outlineBezier appendBezierPathWithArcWithCenter:bottomLeftArcCenter radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:90 clockwise:YES]; + } else { + [outlineBezier moveToPoint:NSMakePoint(aRect.origin.x, aRect.origin.y + aRect.size.height - 0.5)]; + } + if (drawRightEdge) { + [outlineBezier appendBezierPathWithArcWithCenter:bottomRightArcCenter radius:kPSMSequelProTabCornerRadius startAngle:90 endAngle:0 clockwise:YES]; + } else { + [outlineBezier lineToPoint:NSMakePoint(aRect.origin.x + aRect.size.width, aRect.origin.y + aRect.size.height - 0.5)]; + } shadow = [[NSShadow alloc] init]; [shadow setShadowBlurRadius:1]; [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.3]]; @@ -532,42 +595,45 @@ [shadow set]; [outlineBezier stroke]; - // unselected tab - } else { - - // rollover -// if ([cell isHighlighted]) { -// [[NSColor colorWithCalibratedWhite:1.0 alpha:0.1] set]; -// NSRectFillUsingOperation(aRect, NSCompositeSourceAtop); -// } - - if (tabBarIsRightOfSelectedTab) { - //lineColor = [NSColor greenColor]; - - // draw bottom right arc - center = NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:90 endAngle:0 clockwise:YES]; - - // draw top right arc - center = NSMakePoint(aRect.origin.x + aRect.size.width + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:270 clockwise:NO]; - - // Don't draw the left edge for the leftmost tab - } else if ([[tabBar cells] objectAtIndex:0] != cell) { - //lineColor = [NSColor redColor]; - - // draw top left arc - center = NSMakePoint(aRect.origin.x - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:270 endAngle:360 clockwise:NO]; - - // draw bottom left arc - center = NSMakePoint(aRect.origin.x + kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + aRect.size.height - kPSMSequelProTabCornerRadius); - [outlineBezier appendBezierPathWithArcWithCenter:center radius:kPSMSequelProTabCornerRadius startAngle:180 endAngle:90 clockwise:YES]; + // Add the shadow over the tops of background tabs + } else if (drawLeftEdge || drawRightEdge) { + + // Set up a CGContext so that drawing can be clipped (to prevent shadow issues) + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + CGContextSaveGState(context); + NSPoint topLeft, topRight; + CGFloat drawAlpha = [[tabBar window] isKeyWindow] ? 1.0 : 0.7; + outlineBezier = [NSBezierPath bezierPath]; + + // Calculate the endpoints of the line + if (drawLeftEdge) { + topLeft = NSMakePoint(aRect.origin.x + 0.5 - kPSMSequelProTabCornerRadius + 2, aRect.origin.y + 0.5); + } else { + topLeft = NSMakePoint(aRect.origin.x + aRect.size.width - kPSMSequelProTabCornerRadius + 0.5, aRect.origin.y + 0.5); + } + if (drawRightEdge) { + topRight = NSMakePoint(aRect.origin.x + aRect.size.width + kPSMSequelProTabCornerRadius + 0.5 - 2, aRect.origin.y + 0.5); + } else { + topRight = NSMakePoint(aRect.origin.x + 0.5 + kPSMSequelProTabCornerRadius, aRect.origin.y + 0.5); } - [lineColor set]; + // Set up the line and clipping point + CGContextClipToRect(context, NSMakeRect(topLeft.x, topLeft.y, topRight.x-topLeft.x, aRect.size.height)); + [[NSColor colorWithCalibratedWhite:0.2 alpha:drawAlpha] set]; + [outlineBezier moveToPoint:topLeft]; + [outlineBezier lineToPoint:topRight]; + + // Set up the shadow + shadow = [[NSShadow alloc] init]; + [shadow setShadowBlurRadius:4]; + [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.2 alpha:drawAlpha]]; + [shadow setShadowOffset:NSMakeSize(0,0)]; + [shadow set]; + + // Draw, and then restore the previous graphics state [outlineBezier stroke]; - } + CGContextRestoreGState(context); + } [NSGraphicsContext restoreGraphicsState]; diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index 1614718d..e7c12fcf 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -4225,7 +4225,7 @@ // Update the toolbar BOOL toolbarVisible = ![parentWindow toolbar] || [[parentWindow toolbar] isVisible]; [parentWindow setToolbar:mainToolbar]; - if (!toolbarVisible) [[parentWindow toolbar] setVisible:NO]; + [[parentWindow toolbar] setVisible:toolbarVisible]; // Update the window's title and represented document [self updateWindowTitle:self]; diff --git a/Source/SPWindowController.m b/Source/SPWindowController.m index 5cd98870..ed443ac4 100644 --- a/Source/SPWindowController.m +++ b/Source/SPWindowController.m @@ -27,6 +27,7 @@ #import "SPDatabaseDocument.h" #import #import +#import "PSMTabDragAssistant.h" @interface SPWindowController (PrivateAPI) @@ -61,6 +62,7 @@ [tabBar setCellOptimumWidth:250]; [tabBar setSelectsTabsOnMouseDown:YES]; [tabBar setTearOffStyle:PSMTabBarTearOffAlphaWindow]; + [tabBar setUsesSafariStyleDragging:YES]; // hook up add tab button [[tabBar addTabButton] setTarget:self]; @@ -265,7 +267,7 @@ - (IBAction)toggleTabBarShown:(id)sender { - [tabBar setHideForSingleTab:![tabBar isTabBarHidden]]; + [tabBar setHideForSingleTab:![tabBar hideForSingleTab]]; [[NSUserDefaults standardUserDefaults] setBool:![tabBar hideForSingleTab] forKey:SPAlwaysShowWindowTabBar]; } @@ -341,6 +343,7 @@ */ - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem { + if ([[PSMTabDragAssistant sharedDragAssistant] isDragging]) return; selectedTableDocument = [tabViewItem identifier]; [selectedTableDocument didBecomeActiveTabInWindow]; if ([[self window] isKeyWindow]) [selectedTableDocument tabDidBecomeKey]; @@ -409,6 +412,22 @@ [[NSNotificationCenter defaultCenter] postNotificationName:@"SPTabDragStop" object:self]; } +/** + * Respond to dragging events entering the tab in the tab bar. + * Allows custom behaviours - for example, if dragging text, switch to the custom + * query view. + */ +- (void)draggingEvent:(id )dragEvent enteredTabBar:(PSMTabBarControl *)tabBarControl tabView:(NSTabViewItem *)tabViewItem +{ + SPDatabaseDocument *theDocument = [tabViewItem identifier]; + + if (![theDocument isCustomQuerySelected] + && [[[dragEvent draggingPasteboard] types] indexOfObject:NSStringPboardType] != NSNotFound) + { + [theDocument viewQuery:self]; + } +} + /** * Show tooltip for a tab view item. */ @@ -455,6 +474,14 @@ [[aTabView window] close]; } +/** + * When dragging a tab off a tab bar, add a shadow to the drag window. + */ +- (void)tabViewDragWindowCreated:(NSWindow *)dragWindow +{ + [dragWindow setHasShadow:YES]; +} + /** * Allow dragging and dropping of tabs to any position, including out of a tab bar * to create a new window. @@ -481,9 +508,9 @@ toolbarHeight = innerFrame.size.height - [[[self window] contentView] frame].size.height; } - // Tweak window positioning according to the style and toolbar - point.x -= [[tabBar style] leftMarginForTabBarControl]; - point.y += 21 + toolbarHeight - kPSMTabBarControlHeight; + // Adjust the positioning as appropriate + point.y += toolbarHeight; + if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) point.y += kPSMTabBarControlHeight; // Set the new window position and size NSRect targetWindowFrame = [[self window] frame]; @@ -510,10 +537,13 @@ NSImage *viewImage = [[NSImage alloc] init]; // Capture an image of the entire window - [[[self window] contentView] lockFocus]; - NSBitmapImageRep *viewRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[[[self window] contentView] frame]] autorelease]; + CGImageRef windowImage = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[self window] windowNumber], kCGWindowImageBoundsIgnoreFraming); + NSBitmapImageRep *viewRep = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; [viewImage addRepresentation:viewRep]; - [[[self window] contentView] unlockFocus]; + + // Calculate the titlebar+toolbar height + CGFloat contentViewOffsetY = [[self window] frame].size.height - [[[self window] contentView] frame].size.height; + offset->height = contentViewOffsetY + [tabBar frame].size.height; // Draw over the tab bar area [viewImage lockFocus]; @@ -529,17 +559,12 @@ // Draw the background flipped, which is actually the right way up NSAffineTransform *transform = [NSAffineTransform transform]; + [transform translateXBy:0.0 yBy:[[[self window] contentView] frame].size.height]; [transform scaleXBy:1.0 yBy:-1.0]; [transform concat]; - tabFrame.origin.y = -tabFrame.origin.y - tabFrame.size.height; [(id )[[aTabView delegate] style] drawBackgroundInRect:tabFrame]; - [transform invert]; - [transform concat]; [viewImage unlockFocus]; - offset->height = 21; - *styleMask = NSTitledWindowMask | NSUnifiedTitleAndToolbarWindowMask; - return [viewImage autorelease]; } @@ -557,7 +582,9 @@ */ - (void)tabDragStopped:(id)sender { - [tabBar setHideForSingleTab:YES]; + if (![[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) { + [tabBar setHideForSingleTab:YES]; + } } #pragma mark - -- cgit v1.2.3