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

Side by Side Diff: chrome/browser/ui/cocoa/browser/avatar_icon_controller.mm

Issue 117533002: [Mac] Redesign of the avatar menu button (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: now with less incorrect usage of initializers Created 6 years, 11 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/browser/avatar_button_controller.h" 5 #import "chrome/browser/ui/cocoa/browser/avatar_icon_controller.h"
6 6
7 #include "base/strings/sys_string_conversions.h" 7 #include "base/strings/sys_string_conversions.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/command_updater.h"
12 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/profiles/profile_info_cache.h" 10 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/browser/profiles/profile_info_util.h" 11 #include "chrome/browser/profiles/profile_info_util.h"
15 #include "chrome/browser/profiles/profile_manager.h" 12 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/profiles/profile_metrics.h"
17 #include "chrome/browser/profiles/profiles_state.h"
18 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_commands.h"
20 #include "chrome/browser/ui/browser_window.h" 14 #include "chrome/browser/ui/browser_window.h"
21 #import "chrome/browser/ui/cocoa/browser/avatar_label_button.h" 15 #import "chrome/browser/ui/cocoa/browser/avatar_label_button.h"
22 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
23 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
24 #import "chrome/browser/ui/cocoa/browser/profile_chooser_controller.h"
25 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 16 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
26 #include "chrome/common/profile_management_switches.h"
27 #include "content/public/browser/notification_service.h"
28 #include "grit/generated_resources.h" 17 #include "grit/generated_resources.h"
29 #include "grit/theme_resources.h" 18 #include "grit/theme_resources.h"
30 #include "ui/base/l10n/l10n_util_mac.h" 19 #include "ui/base/l10n/l10n_util_mac.h"
31 #include "ui/base/resource/resource_bundle.h" 20 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/gfx/image/image.h" 21 #include "ui/gfx/image/image.h"
33 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 22 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
34 23
35 namespace { 24 namespace {
36 25
37 // Space between the avatar icon and the avatar menu bubble.
38 const CGFloat kMenuYOffsetAdjust = 1.0;
39
40 // Space between the avatar label and the left edge of the container containing 26 // Space between the avatar label and the left edge of the container containing
41 // the label and the icon. 27 // the label and the icon.
42 const CGFloat kAvatarSpacing = 4; 28 const CGFloat kAvatarSpacing = 4;
43 29
44 // Space between the bottom of the avatar icon and the bottom of the avatar 30 // Space between the bottom of the avatar icon and the bottom of the avatar
45 // label. 31 // label.
46 const CGFloat kAvatarLabelBottomSpacing = 3; 32 const CGFloat kAvatarLabelBottomSpacing = 3;
47 33
48 // Space between the right edge of the avatar label and the right edge of the 34 // Space between the right edge of the avatar label and the right edge of the
49 // avatar icon. 35 // avatar icon.
50 const CGFloat kAvatarLabelRightSpacing = 2; 36 const CGFloat kAvatarLabelRightSpacing = 2;
51 37
52 } // namespace 38 } // namespace
53 39
54 @interface AvatarButtonController (Private) 40 @interface AvatarIconController (Private)
55 - (void)setButtonEnabled:(BOOL)flag; 41 - (void)setButtonEnabled:(BOOL)flag;
56 - (IBAction)buttonClicked:(id)sender;
57 - (void)bubbleWillClose:(NSNotification*)notif;
58 - (NSImage*)compositeImageWithShadow:(NSImage*)image; 42 - (NSImage*)compositeImageWithShadow:(NSImage*)image;
59 - (void)updateAvatar; 43 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
60 - (void)addOrRemoveButtonIfNecessary; 44 - (void)addOrRemoveButtonIfNecessary;
61 @end 45 @end
62 46
63 // Declare a 10.7+ private API. 47 // Declare a 10.7+ private API.
64 // NSThemeFrame < NSTitledFrame < NSFrameView < NSView. 48 // NSThemeFrame < NSTitledFrame < NSFrameView < NSView.
65 @interface NSView (NSThemeFrame) 49 @interface NSView (NSThemeFrame)
66 - (void)_tileTitlebarAndRedisplay:(BOOL)redisplay; 50 - (void)_tileTitlebarAndRedisplay:(BOOL)redisplay;
67 @end 51 @end
68 52
69 namespace AvatarButtonControllerInternal { 53 @implementation AvatarIconController
70
71 class Observer : public content::NotificationObserver {
72 public:
73 Observer(AvatarButtonController* button) : button_(button) {
74 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
75 content::NotificationService::AllSources());
76 }
77
78 // NotificationObserver:
79 virtual void Observe(int type,
80 const content::NotificationSource& source,
81 const content::NotificationDetails& details) OVERRIDE {
82 switch (type) {
83 case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
84 [button_ updateAvatar];
85 [button_ addOrRemoveButtonIfNecessary];
86 break;
87 default:
88 NOTREACHED();
89 break;
90 }
91 }
92
93 private:
94 content::NotificationRegistrar registrar_;
95
96 AvatarButtonController* button_; // Weak; owns this.
97 };
98
99 } // namespace AvatarButtonControllerInternal
100
101 ////////////////////////////////////////////////////////////////////////////////
102
103 @implementation AvatarButtonController
104 54
105 - (id)initWithBrowser:(Browser*)browser { 55 - (id)initWithBrowser:(Browser*)browser {
106 if ((self = [super init])) { 56 if ((self = [super initWithBrowser:browser])) {
107 browser_ = browser; 57 browser_ = browser;
108 58
109 base::scoped_nsobject<NSView> container( 59 base::scoped_nsobject<NSView> container(
110 [[NSView alloc] initWithFrame:NSMakeRect( 60 [[NSView alloc] initWithFrame:NSMakeRect(
111 0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]); 61 0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]);
112 [self setView:container]; 62 [self setView:container];
63
113 button_.reset([[NSButton alloc] initWithFrame:NSMakeRect( 64 button_.reset([[NSButton alloc] initWithFrame:NSMakeRect(
114 0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]); 65 0, 0, profiles::kAvatarIconWidth, profiles::kAvatarIconHeight)]);
115 NSButtonCell* cell = [button_ cell]; 66 NSButtonCell* cell = [button_ cell];
116 [button_ setButtonType:NSMomentaryLightButton]; 67 [button_ setButtonType:NSMomentaryLightButton];
117 68
118 [button_ setImagePosition:NSImageOnly]; 69 [button_ setImagePosition:NSImageOnly];
119 [cell setImageScaling:NSImageScaleProportionallyDown]; 70 [cell setImageScaling:NSImageScaleProportionallyDown];
120 [cell setImagePosition:NSImageBelow]; 71 [cell setImagePosition:NSImageBelow];
121 72
122 // AppKit sets a title for some reason when using |-setImagePosition:|. 73 // AppKit sets a title for some reason when using |-setImagePosition:|.
(...skipping 26 matching lines...) Expand all
149 100
150 if (profile->IsOffTheRecord() || profile->IsGuestSession()) { 101 if (profile->IsOffTheRecord() || profile->IsGuestSession()) {
151 const int icon_id = profile->IsGuestSession() ? IDR_LOGIN_GUEST : 102 const int icon_id = profile->IsGuestSession() ? IDR_LOGIN_GUEST :
152 IDR_OTR_ICON; 103 IDR_OTR_ICON;
153 NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed( 104 NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed(
154 icon_id).ToNSImage(); 105 icon_id).ToNSImage();
155 [self setImage:[self compositeImageWithShadow:icon]]; 106 [self setImage:[self compositeImageWithShadow:icon]];
156 [self setButtonEnabled:profile->IsGuestSession()]; 107 [self setButtonEnabled:profile->IsGuestSession()];
157 } else { 108 } else {
158 [self setButtonEnabled:YES]; 109 [self setButtonEnabled:YES];
159 observer_.reset(new AvatarButtonControllerInternal::Observer(self)); 110 [self updateAvatarButtonAndLayoutParent:NO];
160 [self updateAvatar];
161 111
162 // Managed users cannot enter incognito mode, so we only need to check 112 // Managed users cannot enter incognito mode, so we only need to check
163 // it in this code path. 113 // it in this code path.
164 if (profile->IsManaged()) { 114 if (profile->IsManaged()) {
165 // Initialize the avatar label button. 115 // Initialize the avatar label button.
166 CGFloat extraWidth = 116 CGFloat extraWidth =
167 profiles::kAvatarIconWidth + kAvatarLabelRightSpacing; 117 profiles::kAvatarIconWidth + kAvatarLabelRightSpacing;
168 NSRect frame = NSMakeRect( 118 NSRect frame = NSMakeRect(
169 kAvatarSpacing, kAvatarLabelBottomSpacing, extraWidth, 0); 119 kAvatarSpacing, kAvatarLabelBottomSpacing, extraWidth, 0);
170 labelButton_.reset([[AvatarLabelButton alloc] initWithFrame:frame]); 120 labelButton_.reset([[AvatarLabelButton alloc] initWithFrame:frame]);
171 [labelButton_ setTarget:self]; 121 [labelButton_ setTarget:self];
172 [labelButton_ setAction:@selector(buttonClicked:)]; 122 [labelButton_ setAction:@selector(buttonClicked:)];
173 [[self view] addSubview:labelButton_]; 123 [[self view] addSubview:labelButton_];
174 124
175 // Resize the container and reposition the avatar button. 125 // Resize the container and reposition the avatar button.
176 NSSize textSize = [[labelButton_ cell] labelTextSize]; 126 NSSize textSize = [[labelButton_ cell] labelTextSize];
177 [container setFrameSize: 127 [container setFrameSize:
178 NSMakeSize([labelButton_ frame].size.width + kAvatarSpacing, 128 NSMakeSize([labelButton_ frame].size.width + kAvatarSpacing,
179 profiles::kAvatarIconHeight)]; 129 profiles::kAvatarIconHeight)];
180 [button_ 130 [button_
181 setFrameOrigin:NSMakePoint(kAvatarSpacing + textSize.width, 0)]; 131 setFrameOrigin:NSMakePoint(kAvatarSpacing + textSize.width, 0)];
182 } 132 }
183 } 133 }
184 [[self view] addSubview:button_]; 134 [[self view] addSubview:button_];
185 } 135 }
186 return self; 136 return self;
187 } 137 }
188 138
189 - (void)dealloc {
190 [[NSNotificationCenter defaultCenter]
191 removeObserver:self
192 name:NSWindowWillCloseNotification
193 object:[menuController_ window]];
194 [super dealloc];
195 }
196
197 - (NSButton*)buttonView {
198 return button_.get();
199 }
200
201 - (NSButton*)labelButtonView { 139 - (NSButton*)labelButtonView {
202 return labelButton_.get(); 140 return labelButton_.get();
203 } 141 }
204 142
205 - (void)setImage:(NSImage*)image { 143 - (void)setImage:(NSImage*)image {
206 [button_ setImage:image]; 144 [button_ setImage:image];
207 } 145 }
208 146
209 - (void)showAvatarBubble:(NSView*)anchor {
210 if (menuController_)
211 return;
212
213 DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU));
214
215 NSWindowController* wc =
216 [browser_->window()->GetNativeWindow() windowController];
217 if ([wc isKindOfClass:[BrowserWindowController class]]) {
218 [static_cast<BrowserWindowController*>(wc)
219 lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
220 }
221
222 NSPoint point = NSMakePoint(NSMidX([anchor bounds]),
223 NSMaxY([anchor bounds]) - kMenuYOffsetAdjust);
224 point = [anchor convertPoint:point toView:nil];
225 point = [[anchor window] convertBaseToScreen:point];
226
227 // |menuController_| will automatically release itself on close.
228 if (switches::IsNewProfileManagement()) {
229 menuController_ =
230 [[ProfileChooserController alloc] initWithBrowser:browser_
231 anchoredAt:point];
232 } else {
233 menuController_ =
234 [[AvatarMenuBubbleController alloc] initWithBrowser:browser_
235 anchoredAt:point];
236 }
237 [[NSNotificationCenter defaultCenter]
238 addObserver:self
239 selector:@selector(bubbleWillClose:)
240 name:NSWindowWillCloseNotification
241 object:[menuController_ window]];
242 [menuController_ showWindow:self];
243
244 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE);
245 }
246
247 // Private /////////////////////////////////////////////////////////////////////
248
249 - (void)setButtonEnabled:(BOOL)flag { 147 - (void)setButtonEnabled:(BOOL)flag {
250 [button_ setEnabled:flag]; 148 [button_ setEnabled:flag];
251 } 149 }
252 150
253 - (IBAction)buttonClicked:(id)sender {
254 DCHECK(sender == button_.get() || sender == labelButton_.get());
255 [self showAvatarBubble:button_];
256 }
257
258 - (void)bubbleWillClose:(NSNotification*)notif {
259 NSWindowController* wc =
260 [browser_->window()->GetNativeWindow() windowController];
261 if ([wc isKindOfClass:[BrowserWindowController class]]) {
262 [static_cast<BrowserWindowController*>(wc)
263 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
264 }
265 menuController_ = nil;
266 }
267
268 // This will take in an original image and redraw it with a shadow. 151 // This will take in an original image and redraw it with a shadow.
269 - (NSImage*)compositeImageWithShadow:(NSImage*)image { 152 - (NSImage*)compositeImageWithShadow:(NSImage*)image {
270 gfx::ScopedNSGraphicsContextSaveGState scopedGState; 153 gfx::ScopedNSGraphicsContextSaveGState scopedGState;
271 154
272 base::scoped_nsobject<NSImage> destination( 155 base::scoped_nsobject<NSImage> destination(
273 [[NSImage alloc] initWithSize:[image size]]); 156 [[NSImage alloc] initWithSize:[image size]]);
274 157
275 NSRect destRect = NSZeroRect; 158 NSRect destRect = NSZeroRect;
276 destRect.size = [destination size]; 159 destRect.size = [destination size];
277 160
(...skipping 12 matching lines...) Expand all
290 fraction:1.0 173 fraction:1.0
291 respectFlipped:YES 174 respectFlipped:YES
292 hints:nil]; 175 hints:nil];
293 176
294 [destination unlockFocus]; 177 [destination unlockFocus];
295 178
296 return destination.autorelease(); 179 return destination.autorelease();
297 } 180 }
298 181
299 // Updates the avatar information from the profile cache. 182 // Updates the avatar information from the profile cache.
300 - (void)updateAvatar { 183 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent {
301 ProfileInfoCache& cache = 184 ProfileInfoCache& cache =
302 g_browser_process->profile_manager()->GetProfileInfoCache(); 185 g_browser_process->profile_manager()->GetProfileInfoCache();
303 size_t index = 186 size_t index =
304 cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath()); 187 cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath());
305 if (index == std::string::npos) 188 if (index == std::string::npos)
306 return; 189 return;
190
307 BOOL is_gaia_picture = 191 BOOL is_gaia_picture =
308 cache.IsUsingGAIAPictureOfProfileAtIndex(index) && 192 cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
309 cache.GetGAIAPictureOfProfileAtIndex(index); 193 cache.GetGAIAPictureOfProfileAtIndex(index);
310 gfx::Image icon = profiles::GetAvatarIconForTitleBar( 194 gfx::Image icon = profiles::GetAvatarIconForTitleBar(
311 cache.GetAvatarIconOfProfileAtIndex(index), is_gaia_picture, 195 cache.GetAvatarIconOfProfileAtIndex(index), is_gaia_picture,
312 profiles::kAvatarIconWidth, profiles::kAvatarIconHeight); 196 profiles::kAvatarIconWidth, profiles::kAvatarIconHeight);
313 [self setImage:icon.ToNSImage()]; 197 [self setImage:icon.ToNSImage()];
314 198
315 const base::string16& name = cache.GetNameOfProfileAtIndex(index); 199 const base::string16& name = cache.GetNameOfProfileAtIndex(index);
316 NSString* nsName = base::SysUTF16ToNSString(name); 200 NSString* nsName = base::SysUTF16ToNSString(name);
317 [button_ setToolTip:nsName]; 201 [button_ setToolTip:nsName];
318 [[button_ cell] 202 [[button_ cell]
319 accessibilitySetOverrideValue:nsName 203 accessibilitySetOverrideValue:nsName
320 forAttribute:NSAccessibilityValueAttribute]; 204 forAttribute:NSAccessibilityValueAttribute];
205 if (layoutParent)
206 [self addOrRemoveButtonIfNecessary];
321 } 207 }
322 208
323 // If the second-to-last profile was removed or a second profile was added, 209 // If the second-to-last profile was removed or a second profile was added,
324 // show or hide the avatar button from the window frame. 210 // show or hide the avatar button from the window frame.
325 - (void)addOrRemoveButtonIfNecessary { 211 - (void)addOrRemoveButtonIfNecessary {
326 if (browser_->profile()->IsOffTheRecord()) 212 if (browser_->profile()->IsOffTheRecord())
327 return; 213 return;
328 214
329 NSWindowController* wc = 215 NSWindowController* wc =
330 [browser_->window()->GetNativeWindow() windowController]; 216 [browser_->window()->GetNativeWindow() windowController];
331 if (![wc isKindOfClass:[BrowserWindowController class]]) 217 if (![wc isKindOfClass:[BrowserWindowController class]])
332 return; 218 return;
333 219
334 size_t count = g_browser_process->profile_manager()->GetNumberOfProfiles(); 220 size_t count = g_browser_process->profile_manager()->GetNumberOfProfiles();
335 [self.view setHidden:count < 2]; 221 [self.view setHidden:count < 2];
336 222
337 [static_cast<BrowserWindowController*>(wc) layoutSubviews]; 223 [static_cast<BrowserWindowController*>(wc) layoutSubviews];
338 224
339 // If the avatar is being added or removed, then the Lion fullscreen button 225 // If the avatar is being added or removed, then the Lion fullscreen button
340 // needs to be adjusted. Since the fullscreen button is positioned by 226 // needs to be adjusted. Since the fullscreen button is positioned by
341 // FramedBrowserWindow using private APIs, the easiest way to update the 227 // FramedBrowserWindow using private APIs, the easiest way to update the
342 // position of the button is through this private API. Resizing the window 228 // position of the button is through this private API. Resizing the window
343 // also works, but invoking |-display| does not. 229 // also works, but invoking |-display| does not.
344 NSView* themeFrame = [[[wc window] contentView] superview]; 230 NSView* themeFrame = [[[wc window] contentView] superview];
345 if ([themeFrame respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) 231 if ([themeFrame respondsToSelector:@selector(_tileTitlebarAndRedisplay:)])
346 [themeFrame _tileTitlebarAndRedisplay:YES]; 232 [themeFrame _tileTitlebarAndRedisplay:YES];
347 } 233 }
348 234
349 // Testing /////////////////////////////////////////////////////////////////////
350
351 - (BaseBubbleController*)menuController {
352 return menuController_;
353 }
354
355 @end 235 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698