summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/bookmarks
diff options
context:
space:
mode:
authormaf@chromium.org <maf@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-05 02:18:36 +0000
committermaf@chromium.org <maf@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-05 02:18:36 +0000
commit797587a93927badde544d800c95739320eca04bb (patch)
tree03a10543cec88b7bf0b8419cb4999ae11a7fd626 /chrome/browser/ui/cocoa/bookmarks
parent9ad63d2ad848efdda29deef7ce65e6d286d2d478 (diff)
downloadchromium_src-797587a93927badde544d800c95739320eca04bb.zip
chromium_src-797587a93927badde544d800c95739320eca04bb.tar.gz
chromium_src-797587a93927badde544d800c95739320eca04bb.tar.bz2
Major rewrite of BookmarkButton event-handling to support proper menu
tracking on mousedown, sticky and non-sticky menus, drag-down to get menu on draggable folders, etc. Also contains first half of animation support for these UI items. Note that a forthcoming checkin will add live animation during the drag, but that's not covered by this checkin, which adds animation support for the bookmark toolbar buttons, but only in response to completed actions. BUG=72011,70002,72012 Review URL: http://codereview.chromium.org/6594065 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77022 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/cocoa/bookmarks')
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm17
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm3
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm8
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm2
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm2
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button.h7
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm97
7 files changed, 122 insertions, 14 deletions
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index 847b3cc..cad2d78 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -332,6 +332,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
// Complete init of the "off the side" button, as much as we can.
[offTheSideButton_ setDraggable:NO];
+ [offTheSideButton_ setActsOnMouseDown:YES];
// We are enabled by default.
barIsEnabled_ = YES;
@@ -1139,6 +1140,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
if (node->is_folder()) {
[button setTarget:self];
[button setAction:@selector(openBookmarkFolderFromButton:)];
+ [button setActsOnMouseDown:YES];
} else {
// Make the button do something
[button setTarget:self];
@@ -1203,6 +1205,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
frame.origin.x -= bookmarks::kBookmarkHorizontalPadding;
BookmarkButton* button = [[BookmarkButton alloc] initWithFrame:frame];
[button setDraggable:NO];
+ [button setActsOnMouseDown:YES];
otherBookmarksButton_.reset(button);
view_id_util::SetID(button, VIEW_ID_OTHER_BOOKMARKS);
@@ -1555,12 +1558,12 @@ void RecordAppLaunch(Profile* profile, GURL url) {
CGFloat delta = desiredSize - frame.size.width;
if (delta) {
frame.size.width = desiredSize;
- [button setFrame:frame];
+ [[button animator] setFrame:frame];
for (NSButton* button in buttons_.get()) {
NSRect buttonFrame = [button frame];
if (buttonFrame.origin.x > frame.origin.x) {
buttonFrame.origin.x += delta;
- [button setFrame:buttonFrame];
+ [[button animator] setFrame:buttonFrame];
}
}
}
@@ -1662,7 +1665,7 @@ void RecordAppLaunch(Profile* profile, GURL url) {
// - right-click (and unclick) on it to open context menu
// - move mouse to window titlebar then click-drag it by the titlebar
// http://crbug.com/49333
- return YES;
+ return NO;
default:
break;
}
@@ -2325,7 +2328,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSPoint buttonOrigin = [button frame].origin;
buttonOrigin.x += xOffset;
- [button setFrameOrigin:buttonOrigin];
+ [[button animator] setFrameOrigin:buttonOrigin];
}
++displayedButtonCount_;
[buttons_ insertObject:newButton atIndex:buttonIndex];
@@ -2410,7 +2413,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect frame = [button frame];
frame.origin.x -= xOffset;
- [button setFrameOrigin:frame.origin];
+ [[button animator] setFrameOrigin:frame.origin];
}
} else {
// Move the button from right to left within the bar.
@@ -2420,7 +2423,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect buttonFrame = [button frame];
buttonFrame.origin.x += xOffset;
- [button setFrameOrigin:buttonFrame.origin];
+ [[button animator] setFrameOrigin:buttonFrame.origin];
}
}
[buttons_ insertObject:movedButton atIndex:toIndex];
@@ -2475,7 +2478,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect buttonFrame = [button frame];
buttonFrame.origin.x -= xOffset;
- [button setFrame:buttonFrame];
+ [[button animator] setFrame:buttonFrame];
// If this button is showing its menu then we need to move the menu, too.
if (button == [folderController_ parentButton])
[folderController_ offsetFolderMenuWindow:NSMakeSize(xOffset, 0.0)];
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
index c63b362..a2655d6 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
@@ -12,6 +12,7 @@
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/animation_utils.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
@@ -877,6 +878,7 @@ TEST_F(BookmarkBarControllerTest, TestButtonMarch) {
}
TEST_F(BookmarkBarControllerTest, CheckForGrowth) {
+ WithNoAnimation at_all; // Turn off Cocoa auto animation in this scope.
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
GURL gurl1("http://www.google.com");
string16 title1(ASCIIToUTF16("x"));
@@ -1109,6 +1111,7 @@ TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
}
TEST_F(BookmarkBarControllerTest, TestDragButton) {
+ WithNoAnimation at_all;
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
GURL gurls[] = { GURL("http://www.google.com/a"),
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
index 5f4a182..9286220 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
@@ -393,6 +393,7 @@ struct LayoutMetrics {
NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
urlString.c_str()];
[button setToolTip:tooltip];
+ [button setAcceptsTrackIn:YES];
}
} else {
[button setEnabled:NO];
@@ -1203,6 +1204,10 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
#pragma mark NSWindowDelegate Functions
- (void)windowWillClose:(NSNotification*)notification {
+ // Also done by the dealloc method, but also doing it here is quicker and
+ // more reliable.
+ [parentButton_ forceButtonBorderToStayOnAlways:NO];
+
// If a "hover open" is pending when the bookmark bar folder is
// closed, be sure it gets cancelled.
[NSObject cancelPreviousPerformRequestsWithTarget:self];
@@ -1238,7 +1243,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
[self performSelector:@selector(openBookmarkFolderFromButtonAndCloseOldOne:)
withObject:sender
- afterDelay:bookmarks::kHoverOpenDelay];
+ afterDelay:bookmarks::kHoverOpenDelay
+ inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}
// Called from the BookmarkButton
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
index c1c2441..d357087 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
@@ -8,6 +8,7 @@
#include "base/scoped_nsobject.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/animation_utils.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
@@ -678,6 +679,7 @@ class BookmarkBarFolderControllerMenuTest : public CocoaTest {
};
TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
+ WithNoAnimation at_all;
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
index 06a5443..b3bb105 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
@@ -184,7 +184,7 @@
// TODO(port): This should probably return |YES| and the controller should
// slide the existing bookmark buttons interactively to the side to make
// room for the about-to-be-dropped bookmark.
- return NO;
+ return YES;
}
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
index e09c620..c04b3eb 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
@@ -199,9 +199,12 @@ class ThemeProvider;
NSPoint dragMouseOffset_;
NSPoint dragEndScreenLocation_;
BOOL dragPending_;
+ BOOL acceptsTrackIn_;
+ NSTrackingArea* area_;
}
@property(assign, nonatomic) NSObject<BookmarkButtonDelegate>* delegate;
+@property(assign, nonatomic) BOOL acceptsTrackIn;
// Return the bookmark node associated with this button, or NULL.
- (const BookmarkNode*)bookmarkNode;
@@ -228,6 +231,10 @@ class ThemeProvider;
// be displayed.
- (NSPoint)screenLocationForRemoveAnimation;
+// The BookmarkButton which is currently being dragged, if any.
++ (BookmarkButton*)draggedButton;
+
+
@end // @interface BookmarkButton
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
index dba0f6b..191f371 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
@@ -25,24 +25,37 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
};
+namespace {
+// We need a class variable to track the current dragged button to enable
+// proper live animated dragging behavior, and can't do it in the
+// delegate/controller since you can drag a button from one domain to the
+// other (from a "folder" menu, to the main bar, or vice versa).
+BookmarkButton* gDraggedButton = nil; // Weak
+};
+
@interface BookmarkButton(Private)
// Make a drag image for the button.
- (NSImage*)dragImage;
+- (void)installCustomTrackingArea;
+
@end // @interface BookmarkButton(Private)
@implementation BookmarkButton
@synthesize delegate = delegate_;
+@synthesize acceptsTrackIn = acceptsTrackIn_;
- (id)initWithFrame:(NSRect)frameRect {
// BookmarkButton's ViewID may be changed to VIEW_ID_OTHER_BOOKMARKS in
// BookmarkBarController, so we can't just override -viewID method to return
// it.
- if ((self = [super initWithFrame:frameRect]))
+ if ((self = [super initWithFrame:frameRect])) {
view_id_util::SetID(self, VIEW_ID_BOOKMARK_BAR_ELEMENT);
+ [self installCustomTrackingArea];
+ }
return self;
}
@@ -97,12 +110,43 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
return point;
}
+
+- (void)updateTrackingAreas {
+ [self installCustomTrackingArea];
+ [super updateTrackingAreas];
+}
+
+- (BOOL)deltaIndicatesDragStartWithXDelta:(float)xDelta
+ yDelta:(float)yDelta
+ xHysteresis:(float)xHysteresis
+ yHysteresis:(float)yHysteresis {
+ const float kDownProportion = 1.4142135f; // Square root of 2.
+
+ // We want to show a folder menu when you drag down on folder buttons,
+ // so don't classify this as a drag for that case.
+ if ([self isFolder] &&
+ (yDelta <= -yHysteresis) && // Bottom of hysteresis box was hit.
+ (ABS(yDelta)/ABS(xDelta)) >= kDownProportion)
+ return NO;
+
+ return [super deltaIndicatesDragStartWithXDelta:xDelta
+ yDelta:yDelta
+ xHysteresis:xHysteresis
+ yHysteresis:yHysteresis];
+}
+
+
// By default, NSButton ignores middle-clicks.
// But we want them.
- (void)otherMouseUp:(NSEvent*)event {
[self performClick:self];
}
+- (BOOL)acceptsTrackInFrom:(id)sender {
+ return [self isFolder] || [self acceptsTrackIn];
+}
+
+
// Overridden from DraggableButton.
- (void)beginDrag:(NSEvent*)event {
// Don't allow a drag of the empty node.
@@ -114,15 +158,16 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
NOTREACHED();
return;
}
- // Ask our delegate to fill the pasteboard for us.
- NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- [[self delegate] fillPasteboard:pboard forDragOfButton:self];
// At the moment, moving bookmarks causes their buttons (like me!)
// to be destroyed and rebuilt. Make sure we don't go away while on
// the stack.
[self retain];
+ // Ask our delegate to fill the pasteboard for us.
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [[self delegate] fillPasteboard:pboard forDragOfButton:self];
+
// Lock bar visibility, forcing the overlay to stay visible if we are in
// fullscreen mode.
if ([[self delegate] dragShouldLockBarVisibility]) {
@@ -144,19 +189,27 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
dragMouseOffset_ = [self convertPointFromBase:[event locationInWindow]];
dragPending_ = YES;
+ gDraggedButton = self;
+ [[self animator] setHidden:YES];
CGFloat yAt = [self bounds].size.height;
NSSize dragOffset = NSMakeSize(0.0, 0.0);
[self dragImage:[self dragImage] at:NSMakePoint(0, yAt) offset:dragOffset
event:event pasteboard:pboard source:self slideBack:YES];
+ [self setHidden:NO];
+
// And we're done.
dragPending_ = NO;
+ gDraggedButton = nil;
+
[self autorelease];
}
// Overridden to release bar visibility.
- (void)endDrag {
+ gDraggedButton = nil;
+
// visibilityDelegate_ can be nil if we're detached, and that's fine.
[visibilityDelegate_ releaseBarVisibilityForOwner:self
withAnimation:YES
@@ -179,6 +232,7 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
- (void)draggedImage:(NSImage *)anImage
endedAt:(NSPoint)aPoint
operation:(NSDragOperation)operation {
+ gDraggedButton = nil;
// Inform delegate of drag source that we're finished dragging,
// so it can close auto-opened bookmark folders etc.
[delegate_ bookmarkDragDidEnd:self];
@@ -202,10 +256,43 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
[delegate_ mouseExitedButton:self event:event];
}
++ (BookmarkButton*)draggedButton {
+ return gDraggedButton;
+}
+
+// This only gets called after a click that wasn't a drag, and only on folders.
+- (void)secondaryMouseUpAction:(BOOL)wasInside {
+ const NSTimeInterval kShortClickLength = 0.5;
+ // Long clicks that end over the folder button result in the menu hiding.
+ if (wasInside && ([self durationMouseWasDown] > kShortClickLength)) {
+ [[self target] performSelector:[self action] withObject:self];
+ } else {
+ // Mouse tracked out of button during menu track. Hide menus.
+ if (!wasInside)
+ [delegate_ bookmarkDragDidEnd:self];
+ }
+}
+
@end
@implementation BookmarkButton(Private)
+- (void)installCustomTrackingArea {
+ if (area_)
+ return;
+
+ NSTrackingAreaOptions options = NSTrackingActiveInActiveApp |
+ NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag |
+ NSTrackingInVisibleRect;
+
+ area_ = [[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:options
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:area_];
+}
+
+
- (NSImage*)dragImage {
NSRect bounds = [self bounds];
@@ -223,7 +310,7 @@ NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
// Make an autoreleased |NSImage|, which will be returned, and draw into it.
// By default, the |NSImage| will be completely transparent.
NSImage* dragImage =
- [[[NSImage alloc] initWithSize:[bitmap size]] autorelease];
+ [[[NSImage alloc] initWithSize:[bitmap size]] autorelease];
[dragImage lockFocus];
// Draw the image with the appropriate opacity, clipping it tightly.