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

Side by Side Diff: chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm

Issue 303463010: [Mac] Show a warning in the new avatar button/menu if there's an auth error (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix warning icon location and account eliding Created 6 years, 6 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 2014 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/profiles/avatar_button_controller.h" 5 #import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h"
6 6
7 #include "base/mac/foundation_util.h" 7 #include "base/mac/foundation_util.h"
8 #include "base/strings/sys_string_conversions.h" 8 #include "base/strings/sys_string_conversions.h"
9 #include "chrome/browser/profiles/profiles_state.h" 9 #include "chrome/browser/profiles/profiles_state.h"
10 #include "chrome/browser/themes/theme_service.h" 10 #include "chrome/browser/themes/theme_service.h"
11 #include "chrome/browser/themes/theme_service_factory.h" 11 #include "chrome/browser/themes/theme_service_factory.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_window.h" 13 #include "chrome/browser/ui/browser_window.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #include "components/signin/core/browser/signin_error_controller.h"
15 #include "grit/generated_resources.h" 16 #include "grit/generated_resources.h"
16 #include "grit/theme_resources.h" 17 #include "grit/theme_resources.h"
17 #import "ui/base/cocoa/appkit_utils.h" 18 #import "ui/base/cocoa/appkit_utils.h"
18 #import "ui/base/cocoa/hover_image_button.h" 19 #import "ui/base/cocoa/hover_image_button.h"
19 #include "ui/base/l10n/l10n_util_mac.h" 20 #include "ui/base/l10n/l10n_util_mac.h"
20 #include "ui/base/nine_image_painter_factory.h" 21 #include "ui/base/nine_image_painter_factory.h"
21 #include "ui/base/resource/resource_bundle.h" 22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/gfx/image/image_skia_operations.h"
24 #include "ui/gfx/image/image_skia_util_mac.h"
22 #include "ui/gfx/text_elider.h" 25 #include "ui/gfx/text_elider.h"
23 26
24 namespace { 27 namespace {
25 28
26 const CGFloat kButtonPadding = 12; 29 const CGFloat kButtonPadding = 12;
27 const CGFloat kButtonDefaultPadding = 5; 30 const CGFloat kButtonDefaultPadding = 5;
28 const CGFloat kButtonHeight = 27; 31 const CGFloat kButtonHeight = 27;
29 const CGFloat kButtonTitleImageSpacing = 10; 32 const CGFloat kButtonTitleImageSpacing = 10;
30 const CGFloat kMaxButtonContentWidth = 100; 33 const CGFloat kMaxButtonContentWidth = 100;
34 const CGFloat kAuthErrorIconWidth = 13;
35 const CGFloat kAuthErrorIconHeight = 11;
31 36
32 const ui::NinePartImageIds kNormalBorderImageIds = 37 const ui::NinePartImageIds kNormalBorderImageIds =
33 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_NORMAL); 38 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_NORMAL);
34 const ui::NinePartImageIds kHoverBorderImageIds = 39 const ui::NinePartImageIds kHoverBorderImageIds =
35 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_HOVER); 40 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_HOVER);
36 const ui::NinePartImageIds kPressedBorderImageIds = 41 const ui::NinePartImageIds kPressedBorderImageIds =
37 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_PRESSED); 42 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_PRESSED);
38 const ui::NinePartImageIds kThemedBorderImageIds = 43 const ui::NinePartImageIds kThemedBorderImageIds =
39 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL); 44 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL);
40 45
41 NSImage* GetImageFromResourceID(int resourceId) { 46 NSImage* GetImageFromResourceID(int resourceId) {
42 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( 47 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
43 resourceId).ToNSImage(); 48 resourceId).ToNSImage();
44 } 49 }
45 50
46 } // namespace 51 } // namespace
47 52
48 // Button cell with a custom border given by a set of nine-patch image grids. 53 // Button cell with a custom border given by a set of nine-patch image grids.
49 @interface CustomThemeButtonCell : NSButtonCell { 54 @interface CustomThemeButtonCell : NSButtonCell {
50 @private 55 @private
51 BOOL isThemedWindow_; 56 BOOL isThemedWindow_;
57 BOOL hasError_;
58 base::scoped_nsobject<NSImage> authErrorImage_;
groby-ooo-7-16 2014/06/10 19:28:14 authenticationErrorImage_, please. (This is Cocoa.
noms (inactive) 2014/06/17 17:07:32 Done.
52 } 59 }
53 - (void)setIsThemedWindow:(BOOL)isThemedWindow; 60 - (void)setIsThemedWindow:(BOOL)isThemedWindow;
61 - (void)setHasError:(BOOL)hasError;
62
54 @end 63 @end
55 64
56 @implementation CustomThemeButtonCell 65 @implementation CustomThemeButtonCell
57 - (id)initWithThemedWindow:(BOOL)isThemedWindow { 66 - (id)initWithThemedWindow:(BOOL)isThemedWindow {
58 if ((self = [super init])) { 67 if ((self = [super init])) {
59 isThemedWindow_ = isThemedWindow; 68 isThemedWindow_ = isThemedWindow;
69 hasError_ = NO;
70
71 gfx::ImageSkia icon = gfx::ImageSkiaOperations::CreateResizedImage(
groby-ooo-7-16 2014/06/10 19:28:14 Why are we resizing a static resource? Can we inst
noms (inactive) 2014/06/11 15:12:46 Mike didn't want me to check in duplicate, just re
msw 2014/06/11 16:42:36 Don't block this CL on that, you can use the dupli
groby-ooo-7-16 2014/06/11 17:19:09 Not a blocking issue for me, either - I'm just sad
msw 2014/06/11 17:33:59 My concern wasn't entirely about binary size, we h
noms (inactive) 2014/06/17 17:07:32 Done.
72 *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
73 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia(),
74 skia::ImageOperations::RESIZE_BEST,
75 gfx::Size(kAuthErrorIconWidth, kAuthErrorIconHeight));
76 authErrorImage_.reset([gfx::NSImageFromImageSkia(icon) retain]);
60 } 77 }
61 return self; 78 return self;
62 } 79 }
63 80
64 - (NSSize)cellSize { 81 - (NSSize)cellSize {
65 NSSize buttonSize = [super cellSize]; 82 NSSize buttonSize = [super cellSize];
66 buttonSize.width += 2 * kButtonPadding - 2 * kButtonDefaultPadding; 83 CGFloat errorWidth = hasError_ ? kAuthErrorIconWidth : 0;
84 buttonSize.width += 2 * (kButtonPadding - kButtonDefaultPadding) + errorWidth;
67 buttonSize.height = kButtonHeight; 85 buttonSize.height = kButtonHeight;
68 return buttonSize; 86 return buttonSize;
69 } 87 }
70 88
71 - (NSRect)drawTitle:(NSAttributedString*)title 89 - (NSRect)drawTitle:(NSAttributedString*)title
72 withFrame:(NSRect)frame 90 withFrame:(NSRect)frame
73 inView:(NSView*)controlView { 91 inView:(NSView*)controlView {
74 frame.origin.x = kButtonPadding; 92 frame.origin.x = kButtonPadding;
75 // Ensure there's always a padding between the text and the image. 93 // Ensure there's always a padding between the text and the image.
76 frame.size.width -= kButtonTitleImageSpacing; 94 frame.size.width -= hasError_ ? 2 * kButtonTitleImageSpacing :
95 kButtonTitleImageSpacing;
77 return [super drawTitle:title withFrame:frame inView:controlView]; 96 return [super drawTitle:title withFrame:frame inView:controlView];
78 } 97 }
79 98
80 - (void)drawImage:(NSImage*)image 99 - (void)drawImage:(NSImage*)image
81 withFrame:(NSRect)frame 100 withFrame:(NSRect)frame
82 inView:(NSView*)controlView { 101 inView:(NSView*)controlView {
102 // If there's an auth error, draw a warning icon before the cell image.
103 if (hasError_) {
104 NSSize imageSize = [authErrorImage_ size];
105 NSRect rect = NSMakeRect(
106 frame.origin.x - imageSize.width - kButtonTitleImageSpacing,
groby-ooo-7-16 2014/06/10 19:28:14 Am I misreading this, or are you planning to draw
noms (inactive) 2014/06/17 17:07:32 Hmm, so the layout of the button is: [padding][ti
groby-ooo-7-16 2014/06/17 17:16:41 It looked at first glance... let me recheck
107 (kButtonHeight - imageSize.height) / 2,
108 imageSize.width,
109 imageSize.height);
110 [authErrorImage_ drawInRect:rect
111 fromRect:NSZeroRect
112 operation:NSCompositeSourceOver
113 fraction:1.0
114 respectFlipped:YES
115 hints:nil];
116 }
83 // For the x-offset, we need to undo the default padding and apply the 117 // For the x-offset, we need to undo the default padding and apply the
84 // new one. For the y-offset, increasing the button height means we need 118 // new one. For the y-offset, increasing the button height means we need
85 // to move the image a little down to align it nicely with the text; this 119 // to move the image a little down to align it nicely with the text; this
86 // was chosen by visual inspection. 120 // was chosen by visual inspection.
87 frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2); 121 frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2);
88 [super drawImage:image withFrame:frame inView:controlView]; 122 [super drawImage:image withFrame:frame inView:controlView];
89 } 123 }
90 124
91 - (void)drawBezelWithFrame:(NSRect)frame 125 - (void)drawBezelWithFrame:(NSRect)frame
92 inView:(NSView*)controlView { 126 inView:(NSView*)controlView {
93 HoverState hoverState = 127 HoverState hoverState =
94 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState]; 128 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState];
95 ui::NinePartImageIds imageIds = kNormalBorderImageIds; 129 ui::NinePartImageIds imageIds = kNormalBorderImageIds;
96 if (isThemedWindow_) 130 if (isThemedWindow_)
97 imageIds = kThemedBorderImageIds; 131 imageIds = kThemedBorderImageIds;
98 132
99 if (hoverState == kHoverStateMouseDown) 133 if (hoverState == kHoverStateMouseDown)
100 imageIds = kPressedBorderImageIds; 134 imageIds = kPressedBorderImageIds;
101 else if (hoverState == kHoverStateMouseOver) 135 else if (hoverState == kHoverStateMouseOver)
102 imageIds = kHoverBorderImageIds; 136 imageIds = kHoverBorderImageIds;
103 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); 137 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true);
104 } 138 }
105 139
106 - (void)setIsThemedWindow:(BOOL)isThemedWindow { 140 - (void)setIsThemedWindow:(BOOL)isThemedWindow {
107 isThemedWindow_ = isThemedWindow; 141 isThemedWindow_ = isThemedWindow;
108 } 142 }
143
144 - (void)setHasError:(BOOL)hasError {
groby-ooo-7-16 2014/06/10 19:28:14 Assuming that having an error on an account is rar
noms (inactive) 2014/06/17 17:07:32 Done.
145 hasError_ = hasError;
146 }
147
109 @end 148 @end
110 149
111 @interface AvatarButtonController (Private) 150 @interface AvatarButtonController (Private)
112 - (base::string16)getElidedAvatarName; 151 - (base::string16)getElidedAvatarName;
113 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; 152 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
153 - (void)updateErrorStatus:(BOOL)hasError;
114 - (void)dealloc; 154 - (void)dealloc;
115 - (void)themeDidChangeNotification:(NSNotification*)aNotification; 155 - (void)themeDidChangeNotification:(NSNotification*)aNotification;
116 @end 156 @end
117 157
118 @implementation AvatarButtonController 158 @implementation AvatarButtonController
119 159
120 - (id)initWithBrowser:(Browser*)browser { 160 - (id)initWithBrowser:(Browser*)browser {
121 if ((self = [super initWithBrowser:browser])) { 161 if ((self = [super initWithBrowser:browser])) {
122 ThemeService* themeService = 162 ThemeService* themeService =
123 ThemeServiceFactory::GetForProfile(browser->profile()); 163 ThemeServiceFactory::GetForProfile(browser->profile());
124 isThemedWindow_ = !themeService->UsingSystemTheme(); 164 isThemedWindow_ = !themeService->UsingSystemTheme();
125 165
126 HoverImageButton* hoverButton = 166 HoverImageButton* hoverButton =
127 [[HoverImageButton alloc] initWithFrame:NSZeroRect]; 167 [[HoverImageButton alloc] initWithFrame:NSZeroRect];
128 [hoverButton setDefaultImage:GetImageFromResourceID( 168 [hoverButton setDefaultImage:GetImageFromResourceID(
129 IDR_AVATAR_MAC_BUTTON_DROPARROW)]; 169 IDR_AVATAR_MAC_BUTTON_DROPARROW)];
130 [hoverButton setHoverImage:GetImageFromResourceID( 170 [hoverButton setHoverImage:GetImageFromResourceID(
131 IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)]; 171 IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)];
132 [hoverButton setPressedImage:GetImageFromResourceID( 172 [hoverButton setPressedImage:GetImageFromResourceID(
133 IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)]; 173 IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)];
134 174
135 button_.reset(hoverButton); 175 button_.reset(hoverButton);
136 base::scoped_nsobject<CustomThemeButtonCell> cell( 176 base::scoped_nsobject<CustomThemeButtonCell> cell(
137 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); 177 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]);
178 SigninErrorController* error =
179 profiles::GetSigninErrorController(browser->profile());
180 if (error)
181 [cell setHasError:error->HasError()];
groby-ooo-7-16 2014/06/10 19:28:14 I'd actually remove this - it gets rid of the depe
noms (inactive) 2014/06/17 17:07:32 Hmm, but then it adds that dependency to the Brows
138 [button_ setCell:cell.get()]; 182 [button_ setCell:cell.get()];
139 [self setView:button_]; 183 [self setView:button_];
140 184
141 [button_ setBezelStyle:NSShadowlessSquareBezelStyle]; 185 [button_ setBezelStyle:NSShadowlessSquareBezelStyle];
142 [button_ setButtonType:NSMomentaryChangeButton]; 186 [button_ setButtonType:NSMomentaryChangeButton];
143 [button_ setBordered:YES]; 187 [button_ setBordered:YES];
144 // This is a workaround for an issue in the HoverImageButton where the 188 // This is a workaround for an issue in the HoverImageButton where the
145 // button is initially sized incorrectly unless a default image is provided. 189 // button is initially sized incorrectly unless a default image is provided.
146 [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)]; 190 [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)];
147 [button_ setImagePosition:NSImageRight]; 191 [button_ setImagePosition:NSImageRight];
148 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; 192 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
149 [button_ setTarget:self]; 193 [button_ setTarget:self];
150 [button_ setAction:@selector(buttonClicked:)]; 194 [button_ setAction:@selector(buttonClicked:)];
151 195
152 [self updateAvatarButtonAndLayoutParent:NO]; 196 [self updateAvatarButtonAndLayoutParent:NO];
153 197
154 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 198 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
155 [center addObserver:self 199 [center addObserver:self
156 selector:@selector(themeDidChangeNotification:) 200 selector:@selector(themeDidChangeNotification:)
157 name:kBrowserThemeDidChangeNotification 201 name:kBrowserThemeDidChangeNotification
158 object:nil]; 202 object:nil];
159
160 } 203 }
161 return self; 204 return self;
162 } 205 }
163 206
164 - (void)dealloc { 207 - (void)dealloc {
165 [[NSNotificationCenter defaultCenter] removeObserver:self]; 208 [[NSNotificationCenter defaultCenter] removeObserver:self];
166 [super dealloc]; 209 [super dealloc];
167 } 210 }
168 211
169 - (void)themeDidChangeNotification:(NSNotification*)aNotification { 212 - (void)themeDidChangeNotification:(NSNotification*)aNotification {
(...skipping 12 matching lines...) Expand all
182 base::string16 name = profiles::GetAvatarNameForProfile(browser_->profile()); 225 base::string16 name = profiles::GetAvatarNameForProfile(browser_->profile());
183 int maxTextWidth = kMaxButtonContentWidth - [[button_ image] size].width; 226 int maxTextWidth = kMaxButtonContentWidth - [[button_ image] size].width;
184 return gfx::ElideText(name, gfx::FontList(gfx::Font([button_ font])), 227 return gfx::ElideText(name, gfx::FontList(gfx::Font([button_ font])),
185 maxTextWidth, gfx::ELIDE_TAIL); 228 maxTextWidth, gfx::ELIDE_TAIL);
186 } 229 }
187 230
188 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent { 231 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent {
189 // The button text has a black foreground and a white drop shadow for regular 232 // The button text has a black foreground and a white drop shadow for regular
190 // windows, and a light text with a dark drop shadow for guest windows 233 // windows, and a light text with a dark drop shadow for guest windows
191 // which are themed with a dark background. 234 // which are themed with a dark background.
192 // TODO(noms): Figure out something similar for themed windows, if possible.
193 base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); 235 base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
194 [shadow setShadowOffset:NSMakeSize(0, -1)]; 236 [shadow setShadowOffset:NSMakeSize(0, -1)];
195 [shadow setShadowBlurRadius:0]; 237 [shadow setShadowBlurRadius:0];
196 238
197 NSColor* foregroundColor; 239 NSColor* foregroundColor;
198 if (browser_->profile()->IsGuestSession()) { 240 if (browser_->profile()->IsGuestSession()) {
199 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9]; 241 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9];
200 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]]; 242 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]];
201 } else if (!isThemedWindow_) { 243 } else if (!isThemedWindow_) {
202 foregroundColor = [NSColor blackColor]; 244 foregroundColor = [NSColor blackColor];
(...skipping 29 matching lines...) Expand all
232 274
233 if (layoutParent) { 275 if (layoutParent) {
234 // Because the width of the button might have changed, the parent browser 276 // Because the width of the button might have changed, the parent browser
235 // frame needs to recalculate the button bounds and redraw it. 277 // frame needs to recalculate the button bounds and redraw it.
236 [[BrowserWindowController 278 [[BrowserWindowController
237 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] 279 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()]
238 layoutSubviews]; 280 layoutSubviews];
239 } 281 }
240 } 282 }
241 283
284 - (void)updateErrorStatus:(BOOL)hasError {
285 [[button_ cell] setHasError:hasError];
286 [self updateAvatarButtonAndLayoutParent:YES];
287 }
288
242 @end 289 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698