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

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, 1 month 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"
Avi (use Gerrit) 2014/10/30 23:21:25 alphabetize prev 4 lines
Devlin 2014/10/31 17:50:43 Whoops! (Clearly I became reliant on the presubmit
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 [controller_ currentWebContents];
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_;
89 @synthesize tabId = tabId_;
90 98
91 + (Class)cellClass { 99 + (Class)cellClass {
92 return [BrowserActionCell class]; 100 return [BrowserActionCell class];
93 } 101 }
94 102
95 - (id)initWithFrame:(NSRect)frame 103 - (id)initWithFrame:(NSRect)frame
96 extension:(const Extension*)extension 104 viewController:(scoped_ptr<ToolbarActionViewController>)viewController
97 browser:(Browser*)browser 105 controller:(BrowserActionsController*)controller
98 tabId:(int)tabId { 106 menuController:(ExtensionActionContextMenuController*)menuController {
99 if ((self = [super initWithFrame:frame])) { 107 if ((self = [super initWithFrame:frame])) {
100 BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease]; 108 BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease];
101 // [NSButton setCell:] warns to NOT use setCell: other than in the 109 // [NSButton setCell:] warns to NOT use setCell: other than in the
102 // initializer of a control. However, we are using a basic 110 // initializer of a control. However, we are using a basic
103 // NSButton whose initializer does not take an NSCell as an 111 // NSButton whose initializer does not take an NSCell as an
104 // object. To honor the assumed semantics, we do nothing with 112 // object. To honor the assumed semantics, we do nothing with
105 // NSButton between alloc/init and setCell:. 113 // NSButton between alloc/init and setCell:.
106 [self setCell:cell]; 114 [self setCell:cell];
107 [cell setTabId:tabId]; 115
108 ExtensionAction* browser_action = 116 browserActionsController_ = controller;
109 extensions::ExtensionActionManager::Get(browser->profile())-> 117 viewControllerDelegate_.reset(
110 GetExtensionAction(*extension); 118 new ToolbarActionViewDelegateBridge(self, controller));
111 CHECK(browser_action) 119 viewController_ = viewController.Pass();
112 << "Don't create a BrowserActionButton if there is no browser action."; 120 viewController_->SetDelegate(viewControllerDelegate_.get());
113 [cell setExtensionAction:browser_action]; 121
122 [cell setBrowserActionsController:controller];
123 [cell setViewController:viewController_.get()];
114 [cell 124 [cell
115 accessibilitySetOverrideValue:base::SysUTF8ToNSString(extension->name()) 125 accessibilitySetOverrideValue:base::SysUTF16ToNSString(
126 viewController_->GetAccessibleName([controller currentWebContents]))
116 forAttribute:NSAccessibilityDescriptionAttribute]; 127 forAttribute:NSAccessibilityDescriptionAttribute];
117 [cell setImageID:IDR_BROWSER_ACTION 128 [cell setImageID:IDR_BROWSER_ACTION
118 forButtonState:image_button_cell::kDefaultState]; 129 forButtonState:image_button_cell::kDefaultState];
119 [cell setImageID:IDR_BROWSER_ACTION_H 130 [cell setImageID:IDR_BROWSER_ACTION_H
120 forButtonState:image_button_cell::kHoverState]; 131 forButtonState:image_button_cell::kHoverState];
121 [cell setImageID:IDR_BROWSER_ACTION_P 132 [cell setImageID:IDR_BROWSER_ACTION_P
122 forButtonState:image_button_cell::kPressedState]; 133 forButtonState:image_button_cell::kPressedState];
123 [cell setImageID:IDR_BROWSER_ACTION 134 [cell setImageID:IDR_BROWSER_ACTION
124 forButtonState:image_button_cell::kDisabledState]; 135 forButtonState:image_button_cell::kDisabledState];
125 136
126 [self setTitle:@""]; 137 [self setTitle:@""];
127 [self setButtonType:NSMomentaryChangeButton]; 138 [self setButtonType:NSMomentaryChangeButton];
128 [self setShowsBorderOnlyWhileMouseInside:YES]; 139 [self setShowsBorderOnlyWhileMouseInside:YES];
129 140
130 contextMenuController_.reset([[ExtensionActionContextMenuController alloc] 141 contextMenuController_.reset(menuController);
131 initWithExtension:extension 142
132 browser:browser
133 extensionAction:browser_action]);
134 base::scoped_nsobject<NSMenu> contextMenu( 143 base::scoped_nsobject<NSMenu> contextMenu(
135 [[NSMenu alloc] initWithTitle:@""]); 144 [[NSMenu alloc] initWithTitle:@""]);
136 [contextMenu setDelegate:self]; 145 [contextMenu setDelegate:self];
137 [self setMenu:contextMenu]; 146 [self setMenu:contextMenu];
138 147
139 tabId_ = tabId;
140 extension_ = extension;
141 iconFactoryBridge_.reset(new ExtensionActionIconFactoryBridge(
142 self, browser->profile(), extension));
143
144 moveAnimation_.reset([[NSViewAnimation alloc] init]); 148 moveAnimation_.reset([[NSViewAnimation alloc] init]);
145 [moveAnimation_ gtm_setDuration:kAnimationDuration 149 [moveAnimation_ gtm_setDuration:kAnimationDuration
146 eventMask:NSLeftMouseUpMask]; 150 eventMask:NSLeftMouseUpMask];
147 [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking]; 151 [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
148 152
149 [self updateState]; 153 [self updateState];
150 } 154 }
151 155
152 return self; 156 return self;
153 } 157 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey, 237 [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
234 [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey, 238 [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey,
235 nil]; 239 nil];
236 [moveAnimation_ setViewAnimations: 240 [moveAnimation_ setViewAnimations:
237 [NSArray arrayWithObject:animationDictionary]]; 241 [NSArray arrayWithObject:animationDictionary]];
238 [moveAnimation_ startAnimation]; 242 [moveAnimation_ startAnimation];
239 } 243 }
240 } 244 }
241 245
242 - (void)updateState { 246 - (void)updateState {
243 if (tabId_ < 0) 247 content::WebContents* webContents =
248 [browserActionsController_ currentWebContents];
249 if (!webContents)
244 return; 250 return;
245 251
246 std::string tooltip = [[self cell] extensionAction]->GetTitle(tabId_); 252 base::string16 tooltip = viewController_->GetTooltip(webContents);
247 if (tooltip.empty()) { 253 [self setToolTip:(tooltip.empty() ? nil : base::SysUTF16ToNSString(tooltip))];
248 [self setToolTip:nil];
249 } else {
250 [self setToolTip:base::SysUTF8ToNSString(tooltip)];
251 }
252 254
253 gfx::Image image = iconFactoryBridge_->GetIcon(tabId_); 255 gfx::Image image = viewController_->GetIcon(webContents);
254 256
255 if (!image.IsEmpty()) 257 if (!image.IsEmpty())
256 [self setImage:image.ToNSImage()]; 258 [self setImage:image.ToNSImage()];
257 259
258 [[self cell] setTabId:tabId_]; 260 [self setEnabled:viewController_->IsEnabled(webContents)];
259
260 bool enabled = [[self cell] extensionAction]->GetIsVisible(tabId_);
261 [self setEnabled:enabled];
262 261
263 [self setNeedsDisplay:YES]; 262 [self setNeedsDisplay:YES];
264 } 263 }
265 264
266 - (BOOL)isAnimating { 265 - (BOOL)isAnimating {
267 return [moveAnimation_ isAnimating]; 266 return [moveAnimation_ isAnimating];
268 } 267 }
269 268
269 - (ToolbarActionViewController*)viewController {
270 return viewController_.get();
271 }
272
270 - (NSImage*)compositedImage { 273 - (NSImage*)compositedImage {
271 NSRect bounds = [self bounds]; 274 NSRect bounds = [self bounds];
272 NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease]; 275 NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease];
273 [image lockFocus]; 276 [image lockFocus];
274 277
275 [[NSColor clearColor] set]; 278 [[NSColor clearColor] set];
276 NSRectFill(bounds); 279 NSRectFill(bounds);
277 280
278 NSImage* actionImage = [self image]; 281 NSImage* actionImage = [self image];
279 const NSSize imageSize = [actionImage size]; 282 const NSSize imageSize = [actionImage size];
(...skipping 17 matching lines...) Expand all
297 300
298 - (void)menuNeedsUpdate:(NSMenu*)menu { 301 - (void)menuNeedsUpdate:(NSMenu*)menu {
299 [menu removeAllItems]; 302 [menu removeAllItems];
300 [contextMenuController_ populateMenu:menu]; 303 [contextMenuController_ populateMenu:menu];
301 } 304 }
302 305
303 @end 306 @end
304 307
305 @implementation BrowserActionCell 308 @implementation BrowserActionCell
306 309
307 @synthesize tabId = tabId_; 310 @synthesize browserActionsController = browserActionsController_;
308 @synthesize extensionAction = extensionAction_; 311 @synthesize viewController = viewController_;
309 312
310 - (void)drawBadgeWithinFrame:(NSRect)frame { 313 - (void)drawBadgeWithinFrame:(NSRect)frame
314 webContents:(content::WebContents*)webContents {
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_);
Avi (use Gerrit) 2014/10/30 23:21:25 Why CHECK and not DCHECK? Usually that's saved for
Devlin 2014/10/31 17:50:43 Was just matching the previous CHECK(extensionActi
321 bool enabled = extensionAction_->GetIsVisible(tabId_); 325 content::WebContents* webContents =
326 [browserActionsController_ currentWebContents];
327 bool enabled = viewController_->IsEnabled(webContents);
322 const NSSize imageSize = self.image.size; 328 const NSSize imageSize = self.image.size;
323 const NSRect imageRect = 329 const NSRect imageRect =
324 NSMakeRect(std::floor((NSWidth(cellFrame) - imageSize.width) / 2.0), 330 NSMakeRect(std::floor((NSWidth(cellFrame) - imageSize.width) / 2.0),
325 std::floor((NSHeight(cellFrame) - imageSize.height) / 2.0), 331 std::floor((NSHeight(cellFrame) - imageSize.height) / 2.0),
326 imageSize.width, imageSize.height); 332 imageSize.width, imageSize.height);
327 [self.image drawInRect:imageRect 333 [self.image drawInRect:imageRect
328 fromRect:NSZeroRect 334 fromRect:NSZeroRect
329 operation:NSCompositeSourceOver 335 operation:NSCompositeSourceOver
330 fraction:enabled ? 1.0 : 0.4 336 fraction:enabled ? 1.0 : 0.4
331 respectFlipped:YES 337 respectFlipped:YES
332 hints:nil]; 338 hints:nil];
333 339
334 cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; 340 cellFrame.origin.y += kBrowserActionBadgeOriginYOffset;
335 [self drawBadgeWithinFrame:cellFrame]; 341 [self drawBadgeWithinFrame:cellFrame
342 webContents:webContents];
336 } 343 }
337 344
338 @end 345 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698