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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/cocoa/extensions/extension_infobar_controller.h" 5 #import "chrome/browser/cocoa/extensions/extension_infobar_controller.h"
6 6
7 #include <cmath>
8
9 #include "app/resource_bundle.h"
7 #import "chrome/browser/cocoa/animatable_view.h" 10 #import "chrome/browser/cocoa/animatable_view.h"
11 #import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
12 #import "chrome/browser/cocoa/menu_button.h"
8 #include "chrome/browser/cocoa/infobar.h" 13 #include "chrome/browser/cocoa/infobar.h"
9 #include "chrome/browser/extensions/extension_host.h" 14 #include "chrome/browser/extensions/extension_host.h"
10 #include "chrome/browser/extensions/extension_infobar_delegate.h" 15 #include "chrome/browser/extensions/extension_infobar_delegate.h"
11 #include "chrome/browser/tab_contents/tab_contents.h" 16 #include "chrome/browser/tab_contents/tab_contents.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "chrome/common/extensions/extension_resource.h"
19 #include "gfx/canvas_skia.h"
20 #include "grit/theme_resources.h"
21 #include "skia/ext/skia_utils_mac.h"
12 22
13 namespace { 23 namespace {
14 const CGFloat kAnimationDuration = 0.12; 24 const CGFloat kAnimationDuration = 0.12;
15 const CGFloat kBottomBorderHeightPx = 1.0; 25 const CGFloat kBottomBorderHeightPx = 1.0;
16 } // namepsace 26 const CGFloat kButtonHeightPx = 26.0;
27 const CGFloat kButtonLeftMarginPx = 2.0;
28 const CGFloat kButtonWidthPx = 34.0;
29 const CGFloat kDropArrowLeftMarginPx = 3.0;
30 const CGFloat kToolbarMinHeightPx = 36.0;
31 const CGFloat kToolbarMaxHeightPx = 72.0;
32 } // namespace
17 33
18 @interface ExtensionInfoBarController(Private) 34 @interface ExtensionInfoBarController(Private)
19 // Called when the extension's hosted NSView has been resized. 35 // Called when the extension's hosted NSView has been resized.
20 - (void)extensionViewFrameChanged; 36 - (void)extensionViewFrameChanged;
21 // Adjusts the width of the extension's hosted view to match the window's width. 37 // Returns the clamped height of the extension view to be within the min and max
22 - (void)adjustWidthToFitWindow; 38 // values defined above.
39 - (CGFloat)clampedExtensionViewHeight;
40 // Adjusts the width of the extension's hosted view to match the window's width
41 // and sets the proper height for it as well.
42 - (void)adjustExtensionViewSize;
43 // Sets the image to be used in the button on the left side of the infobar.
44 - (void)setButtonImage:(NSImage*)image;
23 @end 45 @end
24 46
47 // A helper class to bridge the asynchronous Skia bitmap loading mechanism to
48 // the extension's button.
49 class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
50 public ImageLoadingTracker::Observer {
51 public:
52 explicit InfobarBridge(ExtensionInfoBarController* owner)
53 : owner_(owner),
54 delegate_([owner delegate]->AsExtensionInfoBarDelegate()),
55 tracker_(this) {
56 delegate_->set_observer(this);
57 LoadIcon();
58 }
59
60 virtual ~InfobarBridge() {
61 if (delegate_)
62 delegate_->set_observer(NULL);
63 }
64
65 // Load the Extension's icon image.
66 void LoadIcon() {
67 ExtensionResource icon_resource;
68 Extension* extension = delegate_->extension_host()->extension();
69 Extension::Icons size =
70 extension->GetIconPathAllowLargerSize(&icon_resource,
71 Extension::EXTENSION_ICON_BITTY);
72 if (!icon_resource.relative_path().empty()) {
73 tracker_.LoadImage(extension, icon_resource, gfx::Size(size, size),
74 ImageLoadingTracker::DONT_CACHE);
75 } else {
76 OnImageLoaded(NULL, icon_resource, 0);
77 }
78 }
79
80 // ImageLoadingTracker::Observer implementation.
81 // TODO(andybons): The infobar view implementations share a lot of the same
82 // code. Come up with a strategy to share amongst them.
83 virtual void OnImageLoaded(
84 SkBitmap* image, ExtensionResource resource, int index) {
85 if (!delegate_)
86 return; // The delegate can go away while the image asynchronously loads.
87
88 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
89
90 // Fall back on the default extension icon on failure.
91 SkBitmap* icon;
92 if (!image || image->empty())
93 icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
94 else
95 icon = image;
96
97 SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
98
99 const int image_size = Extension::EXTENSION_ICON_BITTY;
100 scoped_ptr<gfx::CanvasSkia> canvas(
101 new gfx::CanvasSkia(
102 image_size + kDropArrowLeftMarginPx + drop_image->width(),
103 image_size, false));
104 canvas->DrawBitmapInt(*icon,
105 0, 0, icon->width(), icon->height(),
106 0, 0, image_size, image_size,
107 false);
108 canvas->DrawBitmapInt(*drop_image,
109 image_size + kDropArrowLeftMarginPx,
110 image_size / 2);
111 [owner_ setButtonImage:gfx::SkBitmapToNSImage(canvas->ExtractBitmap())];
112 }
113
114 // Overridden from ExtensionInfoBarDelegate::DelegateObserver:
115 virtual void OnDelegateDeleted() {
116 delegate_ = NULL;
117 }
118
119 private:
120 // Weak. Owns us.
121 ExtensionInfoBarController* owner_;
122
123 // Weak.
124 ExtensionInfoBarDelegate* delegate_;
125
126 // Loads the extensions's icon on the file thread.
127 ImageLoadingTracker tracker_;
128
129 DISALLOW_COPY_AND_ASSIGN(InfobarBridge);
130 };
131
132
25 @implementation ExtensionInfoBarController 133 @implementation ExtensionInfoBarController
26 134
27 - (id)initWithDelegate:(InfoBarDelegate*)delegate 135 - (id)initWithDelegate:(InfoBarDelegate*)delegate
28 window:(NSWindow*)window { 136 window:(NSWindow*)window {
29 if ((self = [super initWithDelegate:delegate])) { 137 if ((self = [super initWithDelegate:delegate])) {
30 window_ = window; 138 window_ = window;
139 dropdownButton_.reset([[MenuButton alloc] init]);
140
141 ExtensionHost* extensionHost = delegate_->AsExtensionInfoBarDelegate()->
142 extension_host();
143 contextMenu_.reset([[ExtensionActionContextMenu alloc]
144 initWithExtension:extensionHost->extension()
145 profile:extensionHost->profile()
146 extensionAction:NULL]);
147 // See menu_button.h for documentation on why this is needed.
148 NSMenuItem* dummyItem =
149 [[[NSMenuItem alloc] initWithTitle:@""
150 action:nil
151 keyEquivalent:@""] autorelease];
152 [contextMenu_ insertItem:dummyItem atIndex:0];
153 [dropdownButton_ setAttachedMenu:contextMenu_.get()];
154
155 bridge_.reset(new InfobarBridge(self));
31 } 156 }
32 return self; 157 return self;
33 } 158 }
34 159
35 - (void)dealloc { 160 - (void)dealloc {
36 [[NSNotificationCenter defaultCenter] removeObserver:self]; 161 [[NSNotificationCenter defaultCenter] removeObserver:self];
37 [super dealloc]; 162 [super dealloc];
38 } 163 }
39 164
40 - (void)addAdditionalControls { 165 - (void)addAdditionalControls {
41 [self removeButtons]; 166 [self removeButtons];
42 167
43 extensionView_ = delegate_->AsExtensionInfoBarDelegate()-> 168 extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()->
44 extension_host()->view()->native_view(); 169 view()->native_view();
45 170
46 // Add the extension's RenderWidgetHostViewMac to the view hierarchy of the 171 // Add the extension's RenderWidgetHostViewMac to the view hierarchy of the
47 // InfoBar and make sure to place it below the Close button. 172 // InfoBar and make sure to place it below the Close button.
48 [infoBarView_ addSubview:extensionView_ 173 [infoBarView_ addSubview:extensionView_
49 positioned:NSWindowBelow 174 positioned:NSWindowBelow
50 relativeTo:(NSView*)closeButton_]; 175 relativeTo:(NSView*)closeButton_];
51 176
177 // Add the context menu button to the hierarchy.
178 [dropdownButton_ setShowsBorderOnlyWhileMouseInside:YES];
179 CGFloat buttonY =
180 std::floor(NSMidY([infoBarView_ frame]) - (kButtonHeightPx / 2.0)) +
181 kBottomBorderHeightPx;
182 NSRect buttonFrame = NSMakeRect(
183 kButtonLeftMarginPx, buttonY, kButtonWidthPx, kButtonHeightPx);
184 [dropdownButton_ setFrame:buttonFrame];
185 [dropdownButton_ setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
186 [infoBarView_ addSubview:dropdownButton_];
187
52 // Because the parent view has a bottom border, account for it during 188 // Because the parent view has a bottom border, account for it during
53 // positioning. 189 // positioning.
54 NSRect extensionFrame = [extensionView_ frame]; 190 NSRect extensionFrame = [extensionView_ frame];
55 extensionFrame.origin.y = kBottomBorderHeightPx; 191 extensionFrame.origin.y = kBottomBorderHeightPx;
56 192
57 [extensionView_ setFrame:extensionFrame]; 193 [extensionView_ setFrame:extensionFrame];
58 // The extension's native view will only have a height that is non-zero if it 194 // The extension's native view will only have a height that is non-zero if it
59 // already has been loaded and rendered, which is the case when you switch 195 // already has been loaded and rendered, which is the case when you switch
60 // back to a tab with an extension infobar within it. The reason this is 196 // back to a tab with an extension infobar within it. The reason this is
61 // needed is because the extension view's frame will not have changed in the 197 // needed is because the extension view's frame will not have changed in the
62 // above case, so the NSViewFrameDidChangeNotification registered below will 198 // above case, so the NSViewFrameDidChangeNotification registered below will
63 // never fire. 199 // never fire.
64 if (extensionFrame.size.height > 0.0) { 200 if (NSHeight(extensionFrame) > 0.0) {
65 NSSize infoBarSize = [[self view] frame].size; 201 NSSize infoBarSize = [[self view] frame].size;
66 infoBarSize.height = extensionFrame.size.height + kBottomBorderHeightPx; 202 infoBarSize.height = [self clampedExtensionViewHeight] +
203 kBottomBorderHeightPx;
67 [[self view] setFrameSize:infoBarSize]; 204 [[self view] setFrameSize:infoBarSize];
68 [infoBarView_ setFrameSize:infoBarSize]; 205 [infoBarView_ setFrameSize:infoBarSize];
69 } 206 }
70 207
71 [self adjustWidthToFitWindow]; 208 [self adjustExtensionViewSize];
72 209
73 // These two notification handlers are here to ensure the width of the 210 // These two notification handlers are here to ensure the width of the
74 // native extension view is the same as the browser window's width and that 211 // native extension view is the same as the browser window's width and that
75 // the parent infobar view matches the height of the extension's native view. 212 // the parent infobar view matches the height of the extension's native view.
76 [[NSNotificationCenter defaultCenter] 213 [[NSNotificationCenter defaultCenter]
77 addObserver:self 214 addObserver:self
78 selector:@selector(extensionViewFrameChanged) 215 selector:@selector(extensionViewFrameChanged)
79 name:NSViewFrameDidChangeNotification 216 name:NSViewFrameDidChangeNotification
80 object:extensionView_]; 217 object:extensionView_];
81 218
82 [[NSNotificationCenter defaultCenter] 219 [[NSNotificationCenter defaultCenter]
83 addObserver:self 220 addObserver:self
84 selector:@selector(adjustWidthToFitWindow) 221 selector:@selector(adjustWidthToFitWindow)
85 name:NSWindowDidResizeNotification 222 name:NSWindowDidResizeNotification
86 object:window_]; 223 object:window_];
87 } 224 }
88 225
89 - (void)extensionViewFrameChanged { 226 - (void)extensionViewFrameChanged {
90 [self adjustWidthToFitWindow]; 227 [self adjustExtensionViewSize];
91 228
92 AnimatableView* view = [self animatableView]; 229 AnimatableView* view = [self animatableView];
93 NSRect infoBarFrame = [view frame]; 230 NSRect infoBarFrame = [view frame];
94 CGFloat newHeight = NSHeight([extensionView_ frame]) + kBottomBorderHeightPx; 231 CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx;
95 [infoBarView_ setPostsFrameChangedNotifications:NO]; 232 [infoBarView_ setPostsFrameChangedNotifications:NO];
96 infoBarFrame.size.height = newHeight; 233 infoBarFrame.size.height = newHeight;
97 [infoBarView_ setFrame:infoBarFrame]; 234 [infoBarView_ setFrame:infoBarFrame];
98 [infoBarView_ setPostsFrameChangedNotifications:YES]; 235 [infoBarView_ setPostsFrameChangedNotifications:YES];
99 [view animateToNewHeight:newHeight duration:kAnimationDuration]; 236 [view animateToNewHeight:newHeight duration:kAnimationDuration];
100 } 237 }
101 238
102 - (void)adjustWidthToFitWindow { 239 - (CGFloat)clampedExtensionViewHeight {
240 return std::max(kToolbarMinHeightPx,
241 std::min(NSHeight([extensionView_ frame]), kToolbarMaxHeightPx));
242 }
243
244 - (void)adjustExtensionViewSize {
103 [extensionView_ setPostsFrameChangedNotifications:NO]; 245 [extensionView_ setPostsFrameChangedNotifications:NO];
104 NSSize extensionViewSize = [extensionView_ frame].size; 246 NSSize extensionViewSize = [extensionView_ frame].size;
105 extensionViewSize.width = NSWidth([window_ frame]); 247 extensionViewSize.width = NSWidth([window_ frame]);
248 extensionViewSize.height = [self clampedExtensionViewHeight];
106 [extensionView_ setFrameSize:extensionViewSize]; 249 [extensionView_ setFrameSize:extensionViewSize];
107 [extensionView_ setPostsFrameChangedNotifications:YES]; 250 [extensionView_ setPostsFrameChangedNotifications:YES];
108 } 251 }
109 252
253 - (void)setButtonImage:(NSImage*)image {
254 [dropdownButton_ setImage:image];
255 }
256
110 @end 257 @end
111 258
112 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() { 259 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
113 NSWindow* window = [(NSView*)tab_contents_->GetContentNativeView() window]; 260 NSWindow* window = [(NSView*)tab_contents_->GetContentNativeView() window];
114 ExtensionInfoBarController* controller = 261 ExtensionInfoBarController* controller =
115 [[ExtensionInfoBarController alloc] initWithDelegate:this 262 [[ExtensionInfoBarController alloc] initWithDelegate:this
116 window:window]; 263 window:window];
117 return new InfoBar(controller); 264 return new InfoBar(controller);
118 } 265 }
OLDNEW
« 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