summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/tab_view.mm
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-28 19:03:39 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-28 19:03:39 +0000
commit2feb19b125ef3fd6bebef1b5eefd08e92523d897 (patch)
tree13d5f0ce125e06b367fc1170fdc3556655b1ba6e /chrome/browser/cocoa/tab_view.mm
parentc6b5b4f6a3f379e01299292f36b626d491912366 (diff)
downloadchromium_src-2feb19b125ef3fd6bebef1b5eefd08e92523d897.zip
chromium_src-2feb19b125ef3fd6bebef1b5eefd08e92523d897.tar.gz
chromium_src-2feb19b125ef3fd6bebef1b5eefd08e92523d897.tar.bz2
Support for tabs reaching a threshold before tearing off (magnetism), showing position of where the tab will go in the destination tab strip. Use new close box icon. Don't draw the tab title over the close box. Patch from alcor@google.com
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14758 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/tab_view.mm')
-rw-r--r--chrome/browser/cocoa/tab_view.mm143
1 files changed, 95 insertions, 48 deletions
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index 2aef856..fd31652 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "chrome/browser/cocoa/tab_view.h"
-
#include "chrome/browser/cocoa/tab_window_controller.h"
@implementation TabView
@@ -44,6 +43,8 @@
// ideas of dragging cocoa views between windows and how the Browser and
// TabStrip models want to manage tabs.
- (void)mouseDown:(NSEvent *)theEvent {
+ static const CGFloat kTearDistance = 36.0;
+
// Make sure the controller doesn't go away while we're doing this.
// TODO(pinkerton): cole had this, not sure why it's necessary.
[[controller_ retain] autorelease];
@@ -53,26 +54,63 @@
[[controller_ target] performSelector:[controller_ action]
withObject:self];
- // TODO(pinkerton): necessary to pre-arrange the tabs here?
-
// Resolve overlay back to original window.
NSWindow* sourceWindow = [self window];
if ([sourceWindow isKindOfClass:[NSPanel class]]) {
sourceWindow = [sourceWindow parentWindow];
}
+
TabWindowController* sourceController = [sourceWindow windowController];
- TabWindowController* draggedController = nil;
- TabWindowController* targetController = nil;
// We don't want to "tear off" a tab if there's only one in the window. Treat
- // it like we're dragging around a tab we've already detached.
- BOOL isLastRemainingTab = [sourceController numberOfTabs] == 1;
+ // it like we're dragging around a tab we've already detached. Note that
+ // unit tests might have |-numberOfTabs| reporting zero since the model
+ // won't be fully hooked up. We need to be prepared for that and not send
+ // them into the "magnetic" codepath.
+ BOOL isLastRemainingTab = [sourceController numberOfTabs] <= 1;
- NSWindow* dragWindow = nil;
- NSWindow* dragOverlay = nil;
BOOL dragging = YES;
BOOL moved = NO;
+ NSPoint lastPoint =
+ [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
+
+ // First, go through the magnetic drag cycle. We break out of this if
+ // "stretchiness" ever exceeds the a set amount.
+ NSRect frame = [self frame];
+ if (!isLastRemainingTab) {
+ while (dragging) {
+ theEvent =
+ [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSDefaultRunLoopMode dequeue:YES];
+ NSPoint thisPoint = [NSEvent mouseLocation];
+ CGFloat stretchiness = thisPoint.y - lastPoint.y;
+ stretchiness = copysign(sqrtf(fabs(stretchiness))/sqrtf(kTearDistance),
+ stretchiness);
+ [sourceController insertPlaceholderForTab:self
+ frame:NSOffsetRect(frame,
+ thisPoint.x - lastPoint.x, 0)
+ yStretchiness:stretchiness];
+
+ CGFloat tearForce = fabs(thisPoint.y - lastPoint.y);
+ if (tearForce > kTearDistance) break;
+ if ([theEvent type] == NSLeftMouseUp) {
+ // Mouse up, break out of the drag event tracking loop
+ dragging = NO;
+ break;
+ }
+ }
+ }
+
+ [sourceController removePlaceholder];
+
+ TabWindowController* draggedController = nil;
+ TabWindowController* targetController = nil;
+
+ NSWindow* dragWindow = nil;
+ NSWindow* dragOverlay = nil;
+
// Do not start dragging until the user has "torn" the tab off by
// moving more than 3 pixels.
BOOL torn = NO;
@@ -81,9 +119,6 @@
NSDate* targetDwellDate = nil; // The date this target was first chosen
NSMutableArray* targets = [NSMutableArray array];
- NSPoint lastPoint =
- [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
-
while (dragging) {
theEvent =
[NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask
@@ -91,16 +126,13 @@
inMode:NSDefaultRunLoopMode dequeue:YES];
NSPoint thisPoint = [NSEvent mouseLocation];
- // TODO(alcor): Pinkerton indicated that cole is adding a more
- // formal concept of "magnetism" to tab detachment, which would
- // be an alternative solution.
if (!torn) {
double dx = thisPoint.x - lastPoint.x;
double dy = thisPoint.y - lastPoint.y;
if (dx * dx + dy * dy < kDragStartDistance * kDragStartDistance
- && [theEvent type] == NSLeftMouseDragged) {
- continue;
+ && [theEvent type] == NSLeftMouseDragged) {
+ continue;
}
torn = YES;
}
@@ -125,7 +157,11 @@
for (TabWindowController* target in targets) {
NSRect windowFrame = [[target window] frame];
if (NSPointInRect(thisPoint, windowFrame)) {
- if (NSPointInRect(thisPoint, [[target tabStripView] frame])) {
+ NSRect tabStripFrame = [[target tabStripView] frame];
+ tabStripFrame = [[target tabStripView] convertRectToBase:tabStripFrame];
+ tabStripFrame.origin = [[target window]
+ convertBaseToScreen:tabStripFrame.origin];
+ if (NSPointInRect(thisPoint, tabStripFrame)) {
newTarget = target;
}
break;
@@ -136,7 +172,7 @@
// target and reset how long we've been hovering over this new one.
if (targetController != newTarget) {
targetDwellDate = [NSDate date];
- [targetController arrangeTabs];
+ [targetController removePlaceholder];
targetController = newTarget;
}
@@ -161,8 +197,12 @@
[draggedController showOverlay];
dragOverlay = [draggedController overlayWindow];
- if (![targets count])
- [dragOverlay setHasShadow:NO];
+ NSPoint origin = [sourceWindow frame].origin;
+
+ origin.y += thisPoint.y - lastPoint.y;
+ [dragWindow setFrameOrigin:NSMakePoint(origin.x, origin.y)];
+ //if (![targets count])
+ // [dragOverlay setHasShadow:NO];
} else {
NSPoint origin = [dragWindow frame].origin;
origin.x += thisPoint.x - lastPoint.x;
@@ -173,9 +213,7 @@
// If we're not hovering over any window, make the window is fully
// opaque. Otherwise, find where the tab might be dropped and insert
// a placeholder so it appears like it's part of that window.
- if (!targetController) {
- [[dragWindow animator] setAlphaValue:1.0];
- } else {
+ if (targetController) {
if (![[targetController window] isKeyWindow]) {
// && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) {
[[targetController window] makeKeyAndOrderFront:nil];
@@ -186,21 +224,30 @@
// Compute where placeholder should go and insert it into the
// destination tab strip.
NSRect dropTabFrame = [[targetController tabStripView] frame];
+ NSView *draggedTabView = [draggedController selectedTabView];
+ NSRect tabFrame = [draggedTabView frame];
+ tabFrame = [draggedTabView convertRectToBase:[self bounds]];
+ tabFrame.origin = [dragWindow
+ convertBaseToScreen:tabFrame.origin];
+ tabFrame.origin = [[targetController window]
+ convertScreenToBase:tabFrame.origin];
+ tabFrame = [[targetController tabStripView]
+ convertRectFromBase:tabFrame];
NSPoint point =
[sourceWindow convertBaseToScreen:
[self convertPointToBase:NSZeroPoint]];
- int x = NSWidth([self bounds]) / 2 + point.x - dropTabFrame.origin.x;
- [targetController insertPlaceholderForTab:self atLocation:x];
- [targetController arrangeTabs];
-
- if (!targetController)
- [dragWindow makeKeyAndOrderFront:nil];
- [[dragWindow animator] setAlphaValue:targetController ? 0.0 : 0.333];
-
- [[[draggedController overlayWindow] animator]
- setAlphaValue:targetController ? 0.85 : 1.0];
- // [setAlphaValue:targetController ? 0.0 : 0.6];
+ [targetController insertPlaceholderForTab:self
+ frame:tabFrame
+ yStretchiness:0];
+ [targetController layoutTabs];
+ } else {
+ [dragWindow makeKeyAndOrderFront:nil];
}
+
+ [dragWindow setHasShadow:NO];
+ [dragWindow setAlphaValue:targetController ? 0.1 : 0.5];
+ [[draggedController overlayWindow]
+ setAlphaValue:targetController ? 0.85 : 1.0];
} else if (type == NSLeftMouseUp) {
// Mouse up, break out of the drag event tracking loop
dragging = NO;
@@ -212,38 +259,38 @@
// and clean up.
if (moved) {
TabWindowController *dropController = targetController;
+#if 1
+ dropController = nil; // Don't allow drops on other windows for now
+#endif
if (dropController) {
-#if 0
-// TODO(alcor/pinkerton): hookup drops on existing windows
+ // TODO(alcor/pinkerton): hookup drops on existing windows
NSRect adjustedFrame = [self bounds];
NSRect dropTabFrame = [[dropController tabStripView] frame];
adjustedFrame.origin = [self convertPointToBase:NSZeroPoint];
adjustedFrame.origin =
- [sourceWindow convertBaseToScreen:adjustedFrame.origin];
+ [sourceWindow convertBaseToScreen:adjustedFrame.origin];
adjustedFrame.origin.x = adjustedFrame.origin.x - dropTabFrame.origin.x;
-// adjustedFrame.origin.y = adjustedFrame.origin.y - dropTabFrame.origin.y;
-// adjustedFrame.size.height += adjustedFrame.origin.y;
+ //adjustedFrame.origin.y = adjustedFrame.origin.y - dropTabFrame.origin.y;
+ //adjustedFrame.size.height += adjustedFrame.origin.y;
adjustedFrame.origin.y = 0;
-
// TODO(alcor): get add tab stuff working
// [dropController addTab:tab_];
-
[self setFrame:adjustedFrame];
- [dropController arrangeTabs];
+ [dropController layoutTabs];
[draggedController close];
[dropController showWindow:nil];
-#endif
} else {
+ [targetController removePlaceholder];
[[dragWindow animator] setAlphaValue:1.0];
[dragOverlay setHasShadow:NO];
- [draggedController removeOverlayAfterDelay:
- [[NSAnimationContext currentContext] duration]];
+ [dragWindow setHasShadow:YES];
+ [draggedController removeOverlay];
[dragWindow makeKeyAndOrderFront:nil];
[[draggedController window] setLevel:NSNormalWindowLevel];
- [draggedController arrangeTabs];
+ [draggedController layoutTabs];
}
- [sourceController arrangeTabs];
+ [sourceController layoutTabs];
}
}