diff options
author | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-22 21:35:33 +0000 |
---|---|---|
committer | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-22 21:35:33 +0000 |
commit | b4f110750aee9a6b99ac8f9eb9f1a2558dc9463c (patch) | |
tree | 6880fc17593a38612a4b21fd4632014edd98869c /chrome/browser/cocoa/extensions | |
parent | ea500fc6e9828bc028a26b5be33d102a260cfc05 (diff) | |
download | chromium_src-b4f110750aee9a6b99ac8f9eb9f1a2558dc9463c.zip chromium_src-b4f110750aee9a6b99ac8f9eb9f1a2558dc9463c.tar.gz chromium_src-b4f110750aee9a6b99ac8f9eb9f1a2558dc9463c.tar.bz2 |
[Mac] Draw the icons within the browser actions overflow menu. Also...
o Fix an issue where the grippy was too far to the right when no browser actions were shown.
o Maintain the correct order of extensions within the overflow menu.
Still to be done:
o Animating once resize is complete.
o Syncing the size of the container accross windows.
TEST=none
BUG=32101
Review URL: http://codereview.chromium.org/1165002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42263 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/extensions')
3 files changed, 137 insertions, 40 deletions
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.h b/chrome/browser/cocoa/extensions/browser_action_button.h index 8321828..3470f3e 100644 --- a/chrome/browser/cocoa/extensions/browser_action_button.h +++ b/chrome/browser/cocoa/extensions/browser_action_button.h @@ -16,6 +16,10 @@ class ExtensionAction; class ExtensionImageTrackerBridge; class Profile; +// Fired when the Browser Action's state has changed. Usually the image needs to +// be updated. +extern const NSString* kBrowserActionButtonUpdatedNotification; + extern const CGFloat kBrowserActionWidth; @interface BrowserActionButton : NSButton { @@ -43,6 +47,10 @@ extern const CGFloat kBrowserActionWidth; - (void)updateState; +// Returns a pointer to an autoreleased NSImage with the badge, shadow and +// cell image drawn into it. +- (NSImage*)compositedImage; + @property(readwrite, nonatomic) int tabId; @property(readonly, nonatomic) Extension* extension; diff --git a/chrome/browser/cocoa/extensions/browser_action_button.mm b/chrome/browser/cocoa/extensions/browser_action_button.mm index c21b76fd..ab497e6 100644 --- a/chrome/browser/cocoa/extensions/browser_action_button.mm +++ b/chrome/browser/cocoa/extensions/browser_action_button.mm @@ -17,6 +17,9 @@ #include "gfx/size.h" #include "skia/ext/skia_utils_mac.h" +extern const NSString* kBrowserActionButtonUpdatedNotification = + @"BrowserActionButtonUpdatedNotification"; + static const CGFloat kBrowserActionBadgeOriginYOffset = 5; // Since the container is the maximum height of the toolbar, we have to move the @@ -28,6 +31,10 @@ static const CGFloat kBrowserActionOriginYOffset = 5; static const CGFloat kBrowserActionHeight = 27; extern const CGFloat kBrowserActionWidth = 29; +namespace { +const CGFloat kShadowOffset = 2.0; +} // anonymous namespace + // A helper class to bridge the asynchronous Skia bitmap loading mechanism to // the extension's button. class ExtensionImageTrackerBridge : public NotificationObserver, @@ -85,6 +92,11 @@ class ExtensionImageTrackerBridge : public NotificationObserver, DISALLOW_COPY_AND_ASSIGN(ExtensionImageTrackerBridge); }; +@interface BrowserActionCell(Internals) +- (void)setIconShadow; +- (void)drawBadgeWithinFrame:(NSRect)frame; +@end + @implementation BrowserActionButton + (Class)cellClass { @@ -156,6 +168,53 @@ class ExtensionImageTrackerBridge : public NotificationObserver, [[self cell] setTabId:tabId_]; [self setNeedsDisplay:YES]; + + [[NSNotificationCenter defaultCenter] + postNotificationName:kBrowserActionButtonUpdatedNotification + object:self]; +} + +- (NSImage*)compositedImage { + NSRect bounds = NSMakeRect(0, 0, kBrowserActionWidth, kBrowserActionHeight); + NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL + pixelsWide:NSWidth(bounds) + pixelsHigh:NSWidth(bounds) + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:0 + bytesPerRow:0 + bitsPerPixel:0]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]]; + [[self cell] setIconShadow]; + + NSImage* actionImage = [self image]; + // Never draw within a flipped coordinate system. + // 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); + [actionImage drawAtPoint:NSMakePoint(xPos, yPos) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; + + bounds.origin.y += kShadowOffset - kBrowserActionBadgeOriginYOffset; + bounds.origin.x -= kShadowOffset; + [[self cell] drawBadgeWithinFrame:bounds]; + + [NSGraphicsContext restoreGraphicsState]; + NSImage* compositeImage = + [[[NSImage alloc] initWithSize:[bitmap size]] autorelease]; + [compositeImage addRepresentation:bitmap]; + return compositeImage; } @synthesize tabId = tabId_; @@ -165,29 +224,29 @@ class ExtensionImageTrackerBridge : public NotificationObserver, @implementation BrowserActionCell -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - [NSGraphicsContext saveGraphicsState]; - +- (void)setIconShadow { // Create the shadow below and to the right of the drawn image. scoped_nsobject<NSShadow> imgShadow([[NSShadow alloc] init]); - [imgShadow.get() setShadowOffset:NSMakeSize(2.0, -2.0)]; + [imgShadow.get() setShadowOffset:NSMakeSize(kShadowOffset, -kShadowOffset)]; [imgShadow setShadowBlurRadius:2.0]; [imgShadow.get() setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]]; [imgShadow set]; +} - [super drawInteriorWithFrame:cellFrame inView:controlView]; - - // CanvasPaint draws its content to the current NSGraphicsContext in its - // destructor, so it is enclosed in a nested block. - { - cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; - gfx::CanvasPaint canvas(cellFrame, false); - canvas.set_composite_alpha(true); - gfx::Rect boundingRect(NSRectToCGRect(cellFrame)); - extensionAction_->PaintBadge(&canvas, boundingRect, tabId_); - } +- (void)drawBadgeWithinFrame:(NSRect)frame { + gfx::CanvasPaint canvas(frame, false); + canvas.set_composite_alpha(true); + gfx::Rect boundingRect(NSRectToCGRect(frame)); + extensionAction_->PaintBadge(&canvas, boundingRect, tabId_); +} +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { + [NSGraphicsContext saveGraphicsState]; + [self setIconShadow]; + [super drawInteriorWithFrame:cellFrame inView:controlView]; + cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; + [self drawBadgeWithinFrame:cellFrame]; [NSGraphicsContext restoreGraphicsState]; } diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm index 9466b82..e88f0a9 100644 --- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm +++ b/chrome/browser/cocoa/extensions/browser_actions_controller.mm @@ -51,10 +51,11 @@ const CGFloat kGrippyXOffset = 8.0; - (NSUInteger)containerButtonCapacity; - (void)repositionActionButtons; - (void)updateButtonOpacityAndDragAbilities; -- (void)containerFrameChanged; -- (void)containerDragStart; -- (void)containerDragging; -- (void)containerDragFinished; +- (void)containerFrameChanged:(NSNotification*)notification; +- (void)containerDragStart:(NSNotification*)notification; +- (void)containerDragging:(NSNotification*)notification; +- (void)containerDragFinished:(NSNotification*)notification; +- (void)actionButtonUpdated:(NSNotification*)notification; - (void)browserActionClicked:(BrowserActionButton*)button; - (int)currentTabId; - (bool)shouldDisplayBrowserAction:(Extension*)extension; @@ -62,6 +63,7 @@ const CGFloat kGrippyXOffset = 8.0; - (void)updateChevronPosition; - (void)updateOverflowMenu; - (void)chevronItemSelected:(BrowserActionButton*)button; +- (BrowserActionButton*)buttonForExtension:(Extension*)extension; @end // A helper class to proxy extension notifications to the view controller's @@ -144,22 +146,22 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, [containerView_ setPostsFrameChangedNotifications:YES]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(containerFrameChanged) + selector:@selector(containerFrameChanged:) name:NSViewFrameDidChangeNotification object:containerView_]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(containerDragStart) + selector:@selector(containerDragStart:) name:kBrowserActionGrippyDragStartedNotification object:containerView_]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(containerDragging) + selector:@selector(containerDragging:) name:kBrowserActionGrippyDraggingNotification object:containerView_]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(containerDragFinished) + selector:@selector(containerDragFinished:) name:kBrowserActionGrippyDragFinishedNotification object:containerView_]; @@ -206,6 +208,12 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, [self createActionButtonForExtension:*iter withIndex:i++]; } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(actionButtonUpdated:) + name:kBrowserActionButtonUpdatedNotification + object:nil]; + CGFloat width = [self savedWidth]; [containerView_ resizeToWidth:width animate:NO]; } @@ -288,11 +296,9 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, CGFloat xOffset = kGrippyXOffset + (i * (kBrowserActionWidth + kBrowserActionButtonPadding)); - NSString* extensionId = base::SysUTF8ToNSString((*iter)->id()); - DCHECK(extensionId); - if (!extensionId) + BrowserActionButton* button = [self buttonForExtension:(*iter)]; + if (!button) continue; - BrowserActionButton* button = [buttons_ objectForKey:extensionId]; NSRect buttonFrame = [button frame]; buttonFrame.origin.x = xOffset; [button setFrame:buttonFrame]; @@ -305,9 +311,13 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, if (buttonCount > 0) { width = kGrippyXOffset + kContainerPadding + (buttonCount * (kBrowserActionWidth + kBrowserActionButtonPadding)); - // Make room for the chevron if necessary. - if ([self buttonCount] != [self visibleButtonCount]) - width += kChevronWidth + kBrowserActionButtonPadding; + } + // Make room for the chevron if any buttons are hidden. + if ([self buttonCount] != [self visibleButtonCount]) { + width += kChevronWidth + kBrowserActionButtonPadding; + // Add extra padding if all buttons are hidden. + if ([self visibleButtonCount] == 0) + width += 3 * kBrowserActionButtonPadding; } return width; } @@ -360,12 +370,12 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, [[containerView_ window] invalidateCursorRectsForView:containerView_]; } -- (void)containerFrameChanged { +- (void)containerFrameChanged:(NSNotification*)notification { [self updateButtonOpacityAndDragAbilities]; [self updateChevronPosition]; } -- (void)containerDragStart { +- (void)containerDragStart:(NSNotification*)notification { [self setChevronHidden:YES animate:YES]; while([hiddenButtons_ count] > 0) { [containerView_ addSubview:[hiddenButtons_ objectAtIndex:0]]; @@ -373,15 +383,17 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, } } -- (void)containerDragging { +- (void)containerDragging:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:kBrowserActionGrippyDraggingNotification object:self]; } // Handles when a user initiated drag to resize the container has finished. -- (void)containerDragFinished { - for (BrowserActionButton* button in [buttons_ allValues]) { +- (void)containerDragFinished:(NSNotification*)notification { + for (ExtensionList::iterator iter = toolbarModel_->begin(); + iter != toolbarModel_->end(); ++iter) { + BrowserActionButton* button = [self buttonForExtension:(*iter)]; NSRect buttonFrame = [button frame]; if (NSContainsRect([containerView_ bounds], buttonFrame)) continue; @@ -401,6 +413,18 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, [self resizeContainerWithAnimation:NO]; } +- (void)actionButtonUpdated:(NSNotification*)notification { + BrowserActionButton* button = [notification object]; + if (![hiddenButtons_ containsObject:button]) + return; + + // +1 item because of the title placeholder. See |updateOverflowMenu|. + NSUInteger menuIndex = [hiddenButtons_ indexOfObject:button] + 1; + NSMenuItem* item = [[chevronMenuButton_ attachedMenu] itemAtIndex:menuIndex]; + DCHECK(button == [item representedObject]); + [item setImage:[button compositedImage]]; +} + - (NSUInteger)buttonCount { return [buttons_ count]; } @@ -499,13 +523,10 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, - (NSPoint)popupPointForBrowserAction:(Extension*)extension { if (!extension->browser_action()) return NSZeroPoint; - - NSString* extensionId = base::SysUTF8ToNSString(extension->id()); - DCHECK(extensionId); - if (!extensionId) + BrowserActionButton* button = [self buttonForExtension:extension]; + if (!button) return NSZeroPoint; - BrowserActionButton* button = [buttons_ objectForKey:extensionId]; NSView* view = button; BOOL isHidden = [hiddenButtons_ containsObject:button]; if (isHidden) @@ -610,6 +631,7 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, action:@selector(chevronItemSelected:) keyEquivalent:@""]; [item setRepresentedObject:button]; + [item setImage:[button compositedImage]]; [item setTarget:self]; } [chevronMenuButton_ setAttachedMenu:overflowMenu_]; @@ -619,6 +641,14 @@ class ExtensionsServiceObserverBridge : public NotificationObserver, [self browserActionClicked:[menuItem representedObject]]; } +- (BrowserActionButton*)buttonForExtension:(Extension*)extension { + NSString* extensionId = base::SysUTF8ToNSString(extension->id()); + DCHECK(extensionId); + if (!extensionId) + return nil; + return [buttons_ objectForKey:extensionId]; +} + + (void)registerUserPrefs:(PrefService*)prefs { prefs->RegisterRealPref(prefs::kBrowserActionContainerWidth, 0); } |