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

Side by Side Diff: chrome/browser/ui/cocoa/extensions/browser_action_button.mm

Issue 670463004: Make a platform-independent ToolbarActionViewController (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/ui/cocoa/extensions/browser_action_button.h" 5 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/strings/sys_string_conversions.h" 11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/extensions/extension_action.h"
13 #include "chrome/browser/extensions/extension_action_icon_factory.h"
14 #include "chrome/browser/extensions/extension_action_manager.h"
15 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_contr oller.h" 14 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
18 #include "extensions/common/extension.h" 15 #import "chrome/browser/ui/cocoa/toolbar/toolbar_action_view_delegate_cocoa.h"
16 #import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_contro ller.h"
17 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
19 #include "grit/theme_resources.h" 18 #include "grit/theme_resources.h"
20 #include "skia/ext/skia_utils_mac.h" 19 #include "skia/ext/skia_utils_mac.h"
21 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h " 20 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h "
22 #include "ui/gfx/canvas_skia_paint.h" 21 #include "ui/gfx/canvas_skia_paint.h"
23 #include "ui/gfx/image/image.h" 22 #include "ui/gfx/image/image.h"
24 #include "ui/gfx/rect.h" 23 #include "ui/gfx/rect.h"
25 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 24 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
26 #include "ui/gfx/size.h"
27
28 using extensions::Extension;
29 25
30 NSString* const kBrowserActionButtonDraggingNotification = 26 NSString* const kBrowserActionButtonDraggingNotification =
31 @"BrowserActionButtonDraggingNotification"; 27 @"BrowserActionButtonDraggingNotification";
32 NSString* const kBrowserActionButtonDragEndNotification = 28 NSString* const kBrowserActionButtonDragEndNotification =
33 @"BrowserActionButtonDragEndNotification"; 29 @"BrowserActionButtonDragEndNotification";
34 30
35 static const CGFloat kBrowserActionBadgeOriginYOffset = 5; 31 static const CGFloat kBrowserActionBadgeOriginYOffset = 5;
36 static const CGFloat kAnimationDuration = 0.2; 32 static const CGFloat kAnimationDuration = 0.2;
37 static const CGFloat kMinimumDragDistance = 5; 33 static const CGFloat kMinimumDragDistance = 5;
38 34
39 // A helper class to bridge the asynchronous Skia bitmap loading mechanism to 35 // A class to bridge the ToolbarActionViewController and the
40 // the extension's button. 36 // BrowserActionButton.
41 class ExtensionActionIconFactoryBridge 37 class ToolbarActionViewDelegateBridge : public ToolbarActionViewDelegateCocoa {
42 : public ExtensionActionIconFactory::Observer {
43 public: 38 public:
44 ExtensionActionIconFactoryBridge(BrowserActionButton* owner, 39 ToolbarActionViewDelegateBridge(BrowserActionButton* owner,
45 Profile* profile, 40 BrowserActionsController* controller);
46 const Extension* extension) 41 ~ToolbarActionViewDelegateBridge();
47 : owner_(owner),
48 browser_action_([[owner cell] extensionAction]),
49 icon_factory_(profile, extension, browser_action_, this) {
50 }
51
52 ~ExtensionActionIconFactoryBridge() override {}
53
54 // ExtensionActionIconFactory::Observer implementation.
55 void OnIconUpdated() override { [owner_ updateState]; }
56
57 gfx::Image GetIcon(int tabId) {
58 return icon_factory_.GetIcon(tabId);
59 }
60 42
61 private: 43 private:
62 // Weak. Owns us. 44 // ToolbarActionViewDelegateCocoa:
45 ToolbarActionViewController* GetPreferredPopupViewController() override;
46 content::WebContents* GetCurrentWebContents() const override;
47 void UpdateState() override;
48 NSPoint GetPopupPoint() override;
49
50 // The owning button. Weak.
63 BrowserActionButton* owner_; 51 BrowserActionButton* owner_;
64 52
65 // The browser action whose images we're loading. 53 // The BrowserActionsController that owns the button. Weak.
66 ExtensionAction* const browser_action_; 54 BrowserActionsController* controller_;
67 55
68 // The object that will be used to get the browser action icon for us. 56 DISALLOW_COPY_AND_ASSIGN(ToolbarActionViewDelegateBridge);
69 // It may load the icon asynchronously (in which case the initial icon 57 };
70 // returned by the factory will be transparent), so we have to observe it for
71 // updates to the icon.
72 ExtensionActionIconFactory icon_factory_;
73 58
74 DISALLOW_COPY_AND_ASSIGN(ExtensionActionIconFactoryBridge); 59 ToolbarActionViewDelegateBridge::ToolbarActionViewDelegateBridge(
75 }; 60 BrowserActionButton* owner,
61 BrowserActionsController* controller)
62 : owner_(owner),
63 controller_(controller) {
64 }
65
66 ToolbarActionViewDelegateBridge::~ToolbarActionViewDelegateBridge() {
67 }
68
69 ToolbarActionViewController*
70 ToolbarActionViewDelegateBridge::GetPreferredPopupViewController() {
71 return [owner_ viewController];
72 }
73
74 content::WebContents* ToolbarActionViewDelegateBridge::GetCurrentWebContents()
75 const {
76 return [owner_ webContents];
77 }
78
79 void ToolbarActionViewDelegateBridge::UpdateState() {
80 [owner_ updateState];
81 }
82
83 NSPoint ToolbarActionViewDelegateBridge::GetPopupPoint() {
84 return [controller_ popupPointForId:[owner_ viewController]->GetId()];
85 }
76 86
77 @interface BrowserActionCell (Internals) 87 @interface BrowserActionCell (Internals)
78 - (void)drawBadgeWithinFrame:(NSRect)frame; 88 - (void)drawBadgeWithinFrame:(NSRect)frame;
79 @end 89 @end
80 90
81 @interface BrowserActionButton (Private) 91 @interface BrowserActionButton (Private)
82 - (void)endDrag; 92 - (void)endDrag;
83 @end 93 @end
84 94
85 @implementation BrowserActionButton 95 @implementation BrowserActionButton
86 96
87 @synthesize isBeingDragged = isBeingDragged_; 97 @synthesize isBeingDragged = isBeingDragged_;
88 @synthesize extension = extension_; 98 @synthesize webContents = webContents_;
89 @synthesize tabId = tabId_;
90 99
91 + (Class)cellClass { 100 + (Class)cellClass {
92 return [BrowserActionCell class]; 101 return [BrowserActionCell class];
93 } 102 }
94 103
95 - (id)initWithFrame:(NSRect)frame 104 - (id)initWithFrame:(NSRect)frame
96 extension:(const Extension*)extension 105 viewController:(scoped_ptr<ToolbarActionViewController>)viewController
97 browser:(Browser*)browser 106 webContents:(content::WebContents*)webContents
98 tabId:(int)tabId { 107 controller:(BrowserActionsController*)controller
108 menuController:(ExtensionActionContextMenuController*)menuController {
99 if ((self = [super initWithFrame:frame])) { 109 if ((self = [super initWithFrame:frame])) {
110 viewControllerDelegate_.reset(
111 new ToolbarActionViewDelegateBridge(self, controller));
112 webContents_ = webContents;
113 viewController_ = viewController.Pass();
114 viewController_->SetDelegate(viewControllerDelegate_.get());
115
100 BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease]; 116 BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease];
101 // [NSButton setCell:] warns to NOT use setCell: other than in the 117 // [NSButton setCell:] warns to NOT use setCell: other than in the
102 // initializer of a control. However, we are using a basic 118 // initializer of a control. However, we are using a basic
103 // NSButton whose initializer does not take an NSCell as an 119 // NSButton whose initializer does not take an NSCell as an
104 // object. To honor the assumed semantics, we do nothing with 120 // object. To honor the assumed semantics, we do nothing with
105 // NSButton between alloc/init and setCell:. 121 // NSButton between alloc/init and setCell:.
106 [self setCell:cell]; 122 [self setCell:cell];
107 [cell setTabId:tabId]; 123 [cell setWebContents:webContents];
108 ExtensionAction* browser_action = 124 [cell setViewController:viewController.get()];
109 extensions::ExtensionActionManager::Get(browser->profile())->
110 GetExtensionAction(*extension);
111 CHECK(browser_action)
112 << "Don't create a BrowserActionButton if there is no browser action.";
113 [cell setExtensionAction:browser_action];
114 [cell 125 [cell
115 accessibilitySetOverrideValue:base::SysUTF8ToNSString(extension->name()) 126 accessibilitySetOverrideValue:base::SysUTF16ToNSString(
127 viewController->GetAccessibleName(webContents))
116 forAttribute:NSAccessibilityDescriptionAttribute]; 128 forAttribute:NSAccessibilityDescriptionAttribute];
117 [cell setImageID:IDR_BROWSER_ACTION 129 [cell setImageID:IDR_BROWSER_ACTION
118 forButtonState:image_button_cell::kDefaultState]; 130 forButtonState:image_button_cell::kDefaultState];
119 [cell setImageID:IDR_BROWSER_ACTION_H 131 [cell setImageID:IDR_BROWSER_ACTION_H
120 forButtonState:image_button_cell::kHoverState]; 132 forButtonState:image_button_cell::kHoverState];
121 [cell setImageID:IDR_BROWSER_ACTION_P 133 [cell setImageID:IDR_BROWSER_ACTION_P
122 forButtonState:image_button_cell::kPressedState]; 134 forButtonState:image_button_cell::kPressedState];
123 [cell setImageID:IDR_BROWSER_ACTION 135 [cell setImageID:IDR_BROWSER_ACTION
124 forButtonState:image_button_cell::kDisabledState]; 136 forButtonState:image_button_cell::kDisabledState];
125 137
126 [self setTitle:@""]; 138 [self setTitle:@""];
127 [self setButtonType:NSMomentaryChangeButton]; 139 [self setButtonType:NSMomentaryChangeButton];
128 [self setShowsBorderOnlyWhileMouseInside:YES]; 140 [self setShowsBorderOnlyWhileMouseInside:YES];
129 141
130 contextMenuController_.reset([[ExtensionActionContextMenuController alloc] 142 contextMenuController_.reset(menuController);
131 initWithExtension:extension 143
132 browser:browser
133 extensionAction:browser_action]);
134 base::scoped_nsobject<NSMenu> contextMenu( 144 base::scoped_nsobject<NSMenu> contextMenu(
135 [[NSMenu alloc] initWithTitle:@""]); 145 [[NSMenu alloc] initWithTitle:@""]);
136 [contextMenu setDelegate:self]; 146 [contextMenu setDelegate:self];
137 [self setMenu:contextMenu]; 147 [self setMenu:contextMenu];
138 148
139 tabId_ = tabId;
140 extension_ = extension;
141 iconFactoryBridge_.reset(new ExtensionActionIconFactoryBridge(
142 self, browser->profile(), extension));
143
144 moveAnimation_.reset([[NSViewAnimation alloc] init]); 149 moveAnimation_.reset([[NSViewAnimation alloc] init]);
145 [moveAnimation_ gtm_setDuration:kAnimationDuration 150 [moveAnimation_ gtm_setDuration:kAnimationDuration
146 eventMask:NSLeftMouseUpMask]; 151 eventMask:NSLeftMouseUpMask];
147 [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; 152 [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
148 153
149 [self updateState]; 154 [self updateState];
150 } 155 }
151 156
152 return self; 157 return self;
153 } 158 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey, 238 [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
234 [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey, 239 [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey,
235 nil]; 240 nil];
236 [moveAnimation_ setViewAnimations: 241 [moveAnimation_ setViewAnimations:
237 [NSArray arrayWithObject:animationDictionary]]; 242 [NSArray arrayWithObject:animationDictionary]];
238 [moveAnimation_ startAnimation]; 243 [moveAnimation_ startAnimation];
239 } 244 }
240 } 245 }
241 246
242 - (void)updateState { 247 - (void)updateState {
243 if (tabId_ < 0) 248 if (!webContents_)
244 return; 249 return;
245 250
246 std::string tooltip = [[self cell] extensionAction]->GetTitle(tabId_); 251 base::string16 tooltip = viewController_->GetTooltip(webContents_);
247 if (tooltip.empty()) { 252 [self setToolTip:(tooltip.empty() ? nil : base::SysUTF16ToNSString(tooltip))];
248 [self setToolTip:nil];
249 } else {
250 [self setToolTip:base::SysUTF8ToNSString(tooltip)];
251 }
252 253
253 gfx::Image image = iconFactoryBridge_->GetIcon(tabId_); 254 gfx::Image image = viewController_->GetIcon(webContents_);
254 255
255 if (!image.IsEmpty()) 256 if (!image.IsEmpty())
256 [self setImage:image.ToNSImage()]; 257 [self setImage:image.ToNSImage()];
257 258
258 [[self cell] setTabId:tabId_]; 259 [[self cell] setWebContents:webContents_];
259 260
260 bool enabled = [[self cell] extensionAction]->GetIsVisible(tabId_); 261 [self setEnabled:viewController_->IsEnabled(webContents_)];
261 [self setEnabled:enabled];
262 262
263 [self setNeedsDisplay:YES]; 263 [self setNeedsDisplay:YES];
264 } 264 }
265 265
266 - (BOOL)isAnimating { 266 - (BOOL)isAnimating {
267 return [moveAnimation_ isAnimating]; 267 return [moveAnimation_ isAnimating];
268 } 268 }
269 269
270 - (ToolbarActionViewController*)viewController {
271 return viewController_.get();
272 }
273
270 - (NSImage*)compositedImage { 274 - (NSImage*)compositedImage {
271 NSRect bounds = [self bounds]; 275 NSRect bounds = [self bounds];
272 NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease]; 276 NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease];
273 [image lockFocus]; 277 [image lockFocus];
274 278
275 [[NSColor clearColor] set]; 279 [[NSColor clearColor] set];
276 NSRectFill(bounds); 280 NSRectFill(bounds);
277 281
278 NSImage* actionImage = [self image]; 282 NSImage* actionImage = [self image];
279 const NSSize imageSize = [actionImage size]; 283 const NSSize imageSize = [actionImage size];
(...skipping 17 matching lines...) Expand all
297 301
298 - (void)menuNeedsUpdate:(NSMenu*)menu { 302 - (void)menuNeedsUpdate:(NSMenu*)menu {
299 [menu removeAllItems]; 303 [menu removeAllItems];
300 [contextMenuController_ populateMenu:menu]; 304 [contextMenuController_ populateMenu:menu];
301 } 305 }
302 306
303 @end 307 @end
304 308
305 @implementation BrowserActionCell 309 @implementation BrowserActionCell
306 310
307 @synthesize tabId = tabId_; 311 @synthesize webContents = webContents_;
308 @synthesize extensionAction = extensionAction_; 312 @synthesize viewController = viewController_;
309 313
310 - (void)drawBadgeWithinFrame:(NSRect)frame { 314 - (void)drawBadgeWithinFrame:(NSRect)frame {
311 gfx::CanvasSkiaPaint canvas(frame, false); 315 gfx::CanvasSkiaPaint canvas(frame, false);
312 canvas.set_composite_alpha(true); 316 canvas.set_composite_alpha(true);
313 gfx::Rect boundingRect(NSRectToCGRect(frame)); 317 gfx::Rect boundingRect(NSRectToCGRect(frame));
314 extensionAction_->PaintBadge(&canvas, boundingRect, tabId_); 318 viewController_->PaintExtra(&canvas, boundingRect, webContents_);
315 } 319 }
316 320
317 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { 321 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
318 gfx::ScopedNSGraphicsContextSaveGState scopedGState; 322 gfx::ScopedNSGraphicsContextSaveGState scopedGState;
319 [super drawWithFrame:cellFrame inView:controlView]; 323 [super drawWithFrame:cellFrame inView:controlView];
320 CHECK(extensionAction_); 324 CHECK(viewController_);
321 bool enabled = extensionAction_->GetIsVisible(tabId_); 325 bool enabled = viewController_->IsEnabled(webContents_);
322 const NSSize imageSize = self.image.size; 326 const NSSize imageSize = self.image.size;
323 const NSRect imageRect = 327 const NSRect imageRect =
324 NSMakeRect(std::floor((NSWidth(cellFrame) - imageSize.width) / 2.0), 328 NSMakeRect(std::floor((NSWidth(cellFrame) - imageSize.width) / 2.0),
325 std::floor((NSHeight(cellFrame) - imageSize.height) / 2.0), 329 std::floor((NSHeight(cellFrame) - imageSize.height) / 2.0),
326 imageSize.width, imageSize.height); 330 imageSize.width, imageSize.height);
327 [self.image drawInRect:imageRect 331 [self.image drawInRect:imageRect
328 fromRect:NSZeroRect 332 fromRect:NSZeroRect
329 operation:NSCompositeSourceOver 333 operation:NSCompositeSourceOver
330 fraction:enabled ? 1.0 : 0.4 334 fraction:enabled ? 1.0 : 0.4
331 respectFlipped:YES 335 respectFlipped:YES
332 hints:nil]; 336 hints:nil];
333 337
334 cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; 338 cellFrame.origin.y += kBrowserActionBadgeOriginYOffset;
335 [self drawBadgeWithinFrame:cellFrame]; 339 [self drawBadgeWithinFrame:cellFrame];
336 } 340 }
337 341
338 @end 342 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698