summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/extensions
diff options
context:
space:
mode:
authorandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-22 21:35:33 +0000
committerandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-22 21:35:33 +0000
commitb4f110750aee9a6b99ac8f9eb9f1a2558dc9463c (patch)
tree6880fc17593a38612a4b21fd4632014edd98869c /chrome/browser/cocoa/extensions
parentea500fc6e9828bc028a26b5be33d102a260cfc05 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.h8
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.mm89
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.mm80
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);
}