| Index: chrome/browser/cocoa/extensions/browser_action_button.mm
|
| ===================================================================
|
| --- chrome/browser/cocoa/extensions/browser_action_button.mm (revision 42818)
|
| +++ chrome/browser/cocoa/extensions/browser_action_button.mm (working copy)
|
| @@ -4,6 +4,9 @@
|
|
|
| #import "chrome/browser/cocoa/extensions/browser_action_button.h"
|
|
|
| +#include <algorithm>
|
| +#include <cmath>
|
| +
|
| #include "base/sys_string_conversions.h"
|
| #include "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
|
| #include "chrome/browser/extensions/image_loading_tracker.h"
|
| @@ -16,10 +19,16 @@
|
| #include "gfx/rect.h"
|
| #include "gfx/size.h"
|
| #include "skia/ext/skia_utils_mac.h"
|
| +#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
|
|
|
| extern const NSString* kBrowserActionButtonUpdatedNotification =
|
| @"BrowserActionButtonUpdatedNotification";
|
|
|
| +extern const NSString* kBrowserActionButtonDraggingNotification =
|
| + @"BrowserActionButtonDraggingNotification";
|
| +extern const NSString* kBrowserActionButtonDragEndNotification =
|
| + @"BrowserActionButtonDragEndNotification";
|
| +
|
| static const CGFloat kBrowserActionBadgeOriginYOffset = 5;
|
|
|
| // Since the container is the maximum height of the toolbar, we have to move the
|
| @@ -32,6 +41,7 @@
|
| extern const CGFloat kBrowserActionWidth = 29;
|
|
|
| namespace {
|
| +const CGFloat kAnimationDuration = 0.2;
|
| const CGFloat kShadowOffset = 2.0;
|
| } // anonymous namespace
|
|
|
| @@ -93,8 +103,16 @@
|
| - (void)drawBadgeWithinFrame:(NSRect)frame;
|
| @end
|
|
|
| +@interface BrowserActionButton(Private)
|
| +- (void)endDrag;
|
| +@end
|
| +
|
| @implementation BrowserActionButton
|
|
|
| +@synthesize isBeingDragged = isBeingDragged_;
|
| +@synthesize extension = extension_;
|
| +@synthesize tabId = tabId_;
|
| +
|
| + (Class)cellClass {
|
| return [BrowserActionCell class];
|
| }
|
| @@ -128,12 +146,90 @@
|
| extension_ = extension;
|
| imageLoadingBridge_.reset(new ExtensionImageTrackerBridge(self, extension));
|
|
|
| + moveAnimation_.reset([[NSViewAnimation alloc] init]);
|
| + [moveAnimation_ gtm_setDuration:kAnimationDuration
|
| + eventMask:NSLeftMouseDownMask];
|
| + [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
|
| +
|
| [self updateState];
|
| }
|
|
|
| return self;
|
| }
|
|
|
| +- (BOOL)acceptsFirstResponder {
|
| + return YES;
|
| +}
|
| +
|
| +- (void)mouseDown:(NSEvent*)theEvent {
|
| + [[self cell] setHighlighted:YES];
|
| +}
|
| +
|
| +- (void)mouseDragged:(NSEvent*)theEvent {
|
| + if (!isBeingDragged_) {
|
| + // The start of a drag. Position the button above all others.
|
| + [[self superview] addSubview:self positioned:NSWindowAbove relativeTo:nil];
|
| + }
|
| + isBeingDragged_ = YES;
|
| + NSPoint location = [self convertPoint:[theEvent locationInWindow]
|
| + fromView:nil];
|
| + NSRect buttonFrame = [self frame];
|
| + // TODO(andybons): Constrain the buttons to be within the container.
|
| + // Clamp the button to be within its superview along the X-axis.
|
| + buttonFrame.origin.x += [theEvent deltaX];
|
| + [self setFrame:buttonFrame];
|
| + [self setNeedsDisplay:YES];
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:kBrowserActionButtonDraggingNotification
|
| + object:self];
|
| +}
|
| +
|
| +- (void)mouseUp:(NSEvent*)theEvent {
|
| + // There are non-drag cases where a mouseUp: may happen
|
| + // (e.g. mouse-down, cmd-tab to another application, move mouse,
|
| + // mouse-up).
|
| + NSPoint location = [self convertPoint:[theEvent locationInWindow]
|
| + fromView:nil];
|
| + if (NSPointInRect(location, [self bounds]) && !isBeingDragged_) {
|
| + // Only perform the click if we didn't drag the button.
|
| + [self performClick:self];
|
| + } else {
|
| + // Make sure an ESC to end a drag doesn't trigger 2 endDrags.
|
| + if (isBeingDragged_) {
|
| + [self endDrag];
|
| + } else {
|
| + [super mouseUp:theEvent];
|
| + }
|
| + }
|
| +}
|
| +
|
| +- (void)endDrag {
|
| + isBeingDragged_ = NO;
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:kBrowserActionButtonDragEndNotification
|
| + object:self];
|
| + [[self cell] setHighlighted:NO];
|
| +}
|
| +
|
| +- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate {
|
| + if (!animate) {
|
| + [self setFrame:frameRect];
|
| + } else {
|
| + if ([moveAnimation_ isAnimating])
|
| + [moveAnimation_ stopAnimation];
|
| +
|
| + NSDictionary* animationDictionary =
|
| + [NSDictionary dictionaryWithObjectsAndKeys:
|
| + self, NSViewAnimationTargetKey,
|
| + [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
|
| + [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey,
|
| + nil];
|
| + [moveAnimation_ setViewAnimations:
|
| + [NSArray arrayWithObject:animationDictionary]];
|
| + [moveAnimation_ startAnimation];
|
| + }
|
| +}
|
| +
|
| - (void)setDefaultIcon:(NSImage*)image {
|
| defaultIcon_.reset([image retain]);
|
| }
|
| @@ -170,12 +266,16 @@
|
| object:self];
|
| }
|
|
|
| +- (BOOL)isAnimating {
|
| + return [moveAnimation_ isAnimating];
|
| +}
|
| +
|
| - (NSImage*)compositedImage {
|
| NSRect bounds = NSMakeRect(0, 0, kBrowserActionWidth, kBrowserActionHeight);
|
| NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc]
|
| initWithBitmapDataPlanes:NULL
|
| pixelsWide:NSWidth(bounds)
|
| - pixelsHigh:NSWidth(bounds)
|
| + pixelsHigh:NSHeight(bounds)
|
| bitsPerSample:8
|
| samplesPerPixel:4
|
| hasAlpha:YES
|
| @@ -197,8 +297,8 @@
|
| // TODO(andybons): Figure out why |flipped| can be yes in certain cases.
|
| // http://crbug.com/38943
|
| [actionImage setFlipped:NO];
|
| - CGFloat xPos = floor((NSWidth(bounds) - [actionImage size].width) / 2);
|
| - CGFloat yPos = floor((NSHeight(bounds) - [actionImage size].height) / 2);
|
| + CGFloat xPos = std::floor((NSWidth(bounds) - [actionImage size].width) / 2);
|
| + CGFloat yPos = std::floor((NSHeight(bounds) - [actionImage size].height) / 2);
|
| [actionImage drawAtPoint:NSMakePoint(xPos, yPos)
|
| fromRect:NSZeroRect
|
| operation:NSCompositeSourceOver
|
| @@ -215,13 +315,13 @@
|
| return compositeImage;
|
| }
|
|
|
| -@synthesize tabId = tabId_;
|
| -@synthesize extension = extension_;
|
| -
|
| @end
|
|
|
| @implementation BrowserActionCell
|
|
|
| +@synthesize tabId = tabId_;
|
| +@synthesize extensionAction = extensionAction_;
|
| +
|
| - (void)setIconShadow {
|
| // Create the shadow below and to the right of the drawn image.
|
| scoped_nsobject<NSShadow> imgShadow([[NSShadow alloc] init]);
|
| @@ -248,7 +348,4 @@
|
| [NSGraphicsContext restoreGraphicsState];
|
| }
|
|
|
| -@synthesize tabId = tabId_;
|
| -@synthesize extensionAction = extensionAction_;
|
| -
|
| @end
|
|
|