Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Unified Diff: chrome/browser/cocoa/extensions/extension_infobar_controller.mm

Issue 2973003: [Mac] Finish up extension infobar UI implementation. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/cocoa/extensions/extension_infobar_controller.mm
===================================================================
--- chrome/browser/cocoa/extensions/extension_infobar_controller.mm (revision 52101)
+++ chrome/browser/cocoa/extensions/extension_infobar_controller.mm (working copy)
@@ -4,30 +4,155 @@
#import "chrome/browser/cocoa/extensions/extension_infobar_controller.h"
+#include <cmath>
+
+#include "app/resource_bundle.h"
#import "chrome/browser/cocoa/animatable_view.h"
+#import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/cocoa/menu_button.h"
#include "chrome/browser/cocoa/infobar.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "gfx/canvas_skia.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
namespace {
const CGFloat kAnimationDuration = 0.12;
const CGFloat kBottomBorderHeightPx = 1.0;
-} // namepsace
+const CGFloat kButtonHeightPx = 26.0;
+const CGFloat kButtonLeftMarginPx = 2.0;
+const CGFloat kButtonWidthPx = 34.0;
+const CGFloat kDropArrowLeftMarginPx = 3.0;
+const CGFloat kToolbarMinHeightPx = 36.0;
+const CGFloat kToolbarMaxHeightPx = 72.0;
+} // namespace
@interface ExtensionInfoBarController(Private)
// Called when the extension's hosted NSView has been resized.
- (void)extensionViewFrameChanged;
-// Adjusts the width of the extension's hosted view to match the window's width.
-- (void)adjustWidthToFitWindow;
+// Returns the clamped height of the extension view to be within the min and max
+// values defined above.
+- (CGFloat)clampedExtensionViewHeight;
+// Adjusts the width of the extension's hosted view to match the window's width
+// and sets the proper height for it as well.
+- (void)adjustExtensionViewSize;
+// Sets the image to be used in the button on the left side of the infobar.
+- (void)setButtonImage:(NSImage*)image;
@end
+// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
+// the extension's button.
+class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
+ public ImageLoadingTracker::Observer {
+ public:
+ explicit InfobarBridge(ExtensionInfoBarController* owner)
+ : owner_(owner),
+ delegate_([owner delegate]->AsExtensionInfoBarDelegate()),
+ tracker_(this) {
+ delegate_->set_observer(this);
+ LoadIcon();
+ }
+
+ virtual ~InfobarBridge() {
+ if (delegate_)
+ delegate_->set_observer(NULL);
+ }
+
+ // Load the Extension's icon image.
+ void LoadIcon() {
+ ExtensionResource icon_resource;
+ Extension* extension = delegate_->extension_host()->extension();
+ Extension::Icons size =
+ extension->GetIconPathAllowLargerSize(&icon_resource,
+ Extension::EXTENSION_ICON_BITTY);
+ if (!icon_resource.relative_path().empty()) {
+ tracker_.LoadImage(extension, icon_resource, gfx::Size(size, size),
+ ImageLoadingTracker::DONT_CACHE);
+ } else {
+ OnImageLoaded(NULL, icon_resource, 0);
+ }
+ }
+
+ // ImageLoadingTracker::Observer implementation.
+ // TODO(andybons): The infobar view implementations share a lot of the same
+ // code. Come up with a strategy to share amongst them.
+ virtual void OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index) {
+ if (!delegate_)
+ return; // The delegate can go away while the image asynchronously loads.
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ // Fall back on the default extension icon on failure.
+ SkBitmap* icon;
+ if (!image || image->empty())
+ icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
+ else
+ icon = image;
+
+ SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
+
+ const int image_size = Extension::EXTENSION_ICON_BITTY;
+ scoped_ptr<gfx::CanvasSkia> canvas(
+ new gfx::CanvasSkia(
+ image_size + kDropArrowLeftMarginPx + drop_image->width(),
+ image_size, false));
+ canvas->DrawBitmapInt(*icon,
+ 0, 0, icon->width(), icon->height(),
+ 0, 0, image_size, image_size,
+ false);
+ canvas->DrawBitmapInt(*drop_image,
+ image_size + kDropArrowLeftMarginPx,
+ image_size / 2);
+ [owner_ setButtonImage:gfx::SkBitmapToNSImage(canvas->ExtractBitmap())];
+ }
+
+ // Overridden from ExtensionInfoBarDelegate::DelegateObserver:
+ virtual void OnDelegateDeleted() {
+ delegate_ = NULL;
+ }
+
+ private:
+ // Weak. Owns us.
+ ExtensionInfoBarController* owner_;
+
+ // Weak.
+ ExtensionInfoBarDelegate* delegate_;
+
+ // Loads the extensions's icon on the file thread.
+ ImageLoadingTracker tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfobarBridge);
+};
+
+
@implementation ExtensionInfoBarController
- (id)initWithDelegate:(InfoBarDelegate*)delegate
window:(NSWindow*)window {
if ((self = [super initWithDelegate:delegate])) {
window_ = window;
+ dropdownButton_.reset([[MenuButton alloc] init]);
+
+ ExtensionHost* extensionHost = delegate_->AsExtensionInfoBarDelegate()->
+ extension_host();
+ contextMenu_.reset([[ExtensionActionContextMenu alloc]
+ initWithExtension:extensionHost->extension()
+ profile:extensionHost->profile()
+ extensionAction:NULL]);
+ // See menu_button.h for documentation on why this is needed.
+ NSMenuItem* dummyItem =
+ [[[NSMenuItem alloc] initWithTitle:@""
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [contextMenu_ insertItem:dummyItem atIndex:0];
+ [dropdownButton_ setAttachedMenu:contextMenu_.get()];
+
+ bridge_.reset(new InfobarBridge(self));
}
return self;
}
@@ -40,8 +165,8 @@
- (void)addAdditionalControls {
[self removeButtons];
- extensionView_ = delegate_->AsExtensionInfoBarDelegate()->
- extension_host()->view()->native_view();
+ extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()->
+ view()->native_view();
// Add the extension's RenderWidgetHostViewMac to the view hierarchy of the
// InfoBar and make sure to place it below the Close button.
@@ -49,6 +174,17 @@
positioned:NSWindowBelow
relativeTo:(NSView*)closeButton_];
+ // Add the context menu button to the hierarchy.
+ [dropdownButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ CGFloat buttonY =
+ std::floor(NSMidY([infoBarView_ frame]) - (kButtonHeightPx / 2.0)) +
+ kBottomBorderHeightPx;
+ NSRect buttonFrame = NSMakeRect(
+ kButtonLeftMarginPx, buttonY, kButtonWidthPx, kButtonHeightPx);
+ [dropdownButton_ setFrame:buttonFrame];
+ [dropdownButton_ setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
+ [infoBarView_ addSubview:dropdownButton_];
+
// Because the parent view has a bottom border, account for it during
// positioning.
NSRect extensionFrame = [extensionView_ frame];
@@ -61,14 +197,15 @@
// needed is because the extension view's frame will not have changed in the
// above case, so the NSViewFrameDidChangeNotification registered below will
// never fire.
- if (extensionFrame.size.height > 0.0) {
+ if (NSHeight(extensionFrame) > 0.0) {
NSSize infoBarSize = [[self view] frame].size;
- infoBarSize.height = extensionFrame.size.height + kBottomBorderHeightPx;
+ infoBarSize.height = [self clampedExtensionViewHeight] +
+ kBottomBorderHeightPx;
[[self view] setFrameSize:infoBarSize];
[infoBarView_ setFrameSize:infoBarSize];
}
- [self adjustWidthToFitWindow];
+ [self adjustExtensionViewSize];
// These two notification handlers are here to ensure the width of the
// native extension view is the same as the browser window's width and that
@@ -87,11 +224,11 @@
}
- (void)extensionViewFrameChanged {
- [self adjustWidthToFitWindow];
+ [self adjustExtensionViewSize];
AnimatableView* view = [self animatableView];
NSRect infoBarFrame = [view frame];
- CGFloat newHeight = NSHeight([extensionView_ frame]) + kBottomBorderHeightPx;
+ CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx;
[infoBarView_ setPostsFrameChangedNotifications:NO];
infoBarFrame.size.height = newHeight;
[infoBarView_ setFrame:infoBarFrame];
@@ -99,14 +236,24 @@
[view animateToNewHeight:newHeight duration:kAnimationDuration];
}
-- (void)adjustWidthToFitWindow {
+- (CGFloat)clampedExtensionViewHeight {
+ return std::max(kToolbarMinHeightPx,
+ std::min(NSHeight([extensionView_ frame]), kToolbarMaxHeightPx));
+}
+
+- (void)adjustExtensionViewSize {
[extensionView_ setPostsFrameChangedNotifications:NO];
NSSize extensionViewSize = [extensionView_ frame].size;
extensionViewSize.width = NSWidth([window_ frame]);
+ extensionViewSize.height = [self clampedExtensionViewHeight];
[extensionView_ setFrameSize:extensionViewSize];
[extensionView_ setPostsFrameChangedNotifications:YES];
}
+- (void)setButtonImage:(NSImage*)image {
+ [dropdownButton_ setImage:image];
+}
+
@end
InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
« no previous file with comments | « chrome/browser/cocoa/extensions/extension_infobar_controller.h ('k') | chrome/browser/extensions/extension_infobar_apitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698