Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/browser_process.h" | |
| 10 #include "chrome/browser/profiles/profile_manager.h" | |
| 9 #include "chrome/browser/profiles/profiles_state.h" | 11 #include "chrome/browser/profiles/profiles_state.h" |
| 10 #include "chrome/browser/themes/theme_service.h" | 12 #include "chrome/browser/themes/theme_service.h" |
| 11 #include "chrome/browser/themes/theme_service_factory.h" | 13 #include "chrome/browser/themes/theme_service_factory.h" |
| 12 #include "chrome/browser/ui/browser.h" | 14 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/browser_window.h" | 15 #include "chrome/browser/ui/browser_window.h" |
| 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 16 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 15 #include "chrome/grit/generated_resources.h" | 17 #include "chrome/grit/generated_resources.h" |
| 16 #include "components/signin/core/browser/signin_error_controller.h" | 18 #include "components/signin/core/browser/signin_error_controller.h" |
| 17 #include "grit/theme_resources.h" | 19 #include "grit/theme_resources.h" |
| 18 #import "ui/base/cocoa/appkit_utils.h" | 20 #import "ui/base/cocoa/appkit_utils.h" |
| 19 #import "ui/base/cocoa/hover_image_button.h" | 21 #import "ui/base/cocoa/hover_image_button.h" |
| 20 #include "ui/base/l10n/l10n_util_mac.h" | 22 #include "ui/base/l10n/l10n_util_mac.h" |
| 21 #include "ui/base/nine_image_painter_factory.h" | 23 #include "ui/base/nine_image_painter_factory.h" |
| 22 #include "ui/base/resource/resource_bundle.h" | 24 #include "ui/base/resource/resource_bundle.h" |
| 23 #include "ui/gfx/image/image_skia_operations.h" | 25 #include "ui/gfx/image/image_skia_operations.h" |
| 24 #include "ui/gfx/image/image_skia_util_mac.h" | 26 #include "ui/gfx/image/image_skia_util_mac.h" |
| 25 | 27 |
| 26 namespace { | 28 namespace { |
| 27 | 29 |
| 28 const CGFloat kButtonPadding = 12; | 30 // NSButtons have a default padding of 5px. This button should have a padding |
| 29 const CGFloat kButtonDefaultPadding = 5; | 31 // of 8px. |
|
groby-ooo-7-16
2014/09/29 17:55:43
Would you terribly mind writing "3" as "8 - 5", so
noms (inactive)
2014/09/29 19:21:57
Done.
| |
| 30 const CGFloat kButtonHeight = 27; | 32 const CGFloat kButtonExtraPadding = 3; |
| 31 const CGFloat kButtonTitleImageSpacing = 10; | 33 const CGFloat kButtonHeight = 28; |
| 32 | 34 |
| 33 const ui::NinePartImageIds kNormalBorderImageIds = | 35 const ui::NinePartImageIds kNormalBorderImageIds = |
| 34 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_NORMAL); | 36 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_NORMAL); |
| 35 const ui::NinePartImageIds kHoverBorderImageIds = | 37 const ui::NinePartImageIds kHoverBorderImageIds = |
| 36 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_HOVER); | 38 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_HOVER); |
| 37 const ui::NinePartImageIds kPressedBorderImageIds = | 39 const ui::NinePartImageIds kPressedBorderImageIds = |
| 38 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_PRESSED); | 40 IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_PRESSED); |
| 39 const ui::NinePartImageIds kThemedBorderImageIds = | 41 const ui::NinePartImageIds kThemedBorderImageIds = |
| 40 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL); | 42 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL); |
| 41 | 43 |
| 42 NSImage* GetImageFromResourceID(int resourceId) { | 44 NSImage* GetImageFromResourceID(int resourceId) { |
| 43 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( | 45 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
| 44 resourceId).ToNSImage(); | 46 resourceId).ToNSImage(); |
| 45 } | 47 } |
| 46 | 48 |
| 47 } // namespace | 49 } // namespace |
| 48 | 50 |
| 49 // Button cell with a custom border given by a set of nine-patch image grids. | 51 // Button cell with a custom border given by a set of nine-patch image grids. |
| 50 @interface CustomThemeButtonCell : NSButtonCell { | 52 @interface CustomThemeButtonCell : NSButtonCell { |
| 51 @private | 53 @private |
| 52 BOOL isThemedWindow_; | 54 BOOL isThemedWindow_; |
| 53 base::scoped_nsobject<NSImage> authenticationErrorImage_; | 55 BOOL hasError_; |
| 54 } | 56 } |
| 55 - (void)setIsThemedWindow:(BOOL)isThemedWindow; | 57 - (void)setIsThemedWindow:(BOOL)isThemedWindow; |
| 56 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title; | 58 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title; |
| 57 | 59 |
| 58 @end | 60 @end |
| 59 | 61 |
| 60 @implementation CustomThemeButtonCell | 62 @implementation CustomThemeButtonCell |
| 61 - (id)initWithThemedWindow:(BOOL)isThemedWindow { | 63 - (id)initWithThemedWindow:(BOOL)isThemedWindow { |
| 62 if ((self = [super init])) { | 64 if ((self = [super init])) { |
| 63 isThemedWindow_ = isThemedWindow; | 65 isThemedWindow_ = isThemedWindow; |
| 64 authenticationErrorImage_.reset(); | 66 hasError_ = false; |
| 65 } | 67 } |
| 66 return self; | 68 return self; |
| 67 } | 69 } |
| 68 | 70 |
| 69 - (NSSize)cellSize { | 71 - (NSSize)cellSize { |
| 70 NSSize buttonSize = [super cellSize]; | 72 NSSize buttonSize = [super cellSize]; |
| 71 CGFloat errorWidth = [authenticationErrorImage_ size].width; | 73 |
| 72 buttonSize.width += 2 * (kButtonPadding - kButtonDefaultPadding) + errorWidth; | 74 // An image and no error means we are drawing the generic button, which |
| 75 // is square. Otherwise, we are displaying the profile's name and an | |
| 76 // optional authentication error icon. | |
| 77 if ([self image] && !hasError_) { | |
| 78 buttonSize.width = kButtonHeight; | |
| 79 } else { | |
| 80 buttonSize.width += 2 * kButtonExtraPadding; | |
| 81 } | |
| 73 buttonSize.height = kButtonHeight; | 82 buttonSize.height = kButtonHeight; |
| 74 return buttonSize; | 83 return buttonSize; |
| 75 } | 84 } |
| 76 | 85 |
| 77 - (NSRect)drawTitle:(NSAttributedString*)title | 86 - (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)controlView { |
| 78 withFrame:(NSRect)frame | 87 NSRect frameAfterPadding = NSInsetRect(frame, kButtonExtraPadding, 0); |
| 79 inView:(NSView*)controlView { | 88 [super drawInteriorWithFrame:frameAfterPadding inView:controlView]; |
| 80 frame.origin.x = kButtonPadding; | |
| 81 | |
| 82 // If there's an auth error, draw a warning icon before the cell image. | |
| 83 if (authenticationErrorImage_) { | |
| 84 NSSize imageSize = [authenticationErrorImage_ size]; | |
| 85 NSRect rect = NSMakeRect( | |
| 86 frame.size.width - imageSize.width, | |
| 87 (kButtonHeight - imageSize.height) / 2, | |
| 88 imageSize.width, | |
| 89 imageSize.height); | |
| 90 [authenticationErrorImage_ drawInRect:rect | |
| 91 fromRect:NSZeroRect | |
| 92 operation:NSCompositeSourceOver | |
| 93 fraction:1.0 | |
| 94 respectFlipped:YES | |
| 95 hints:nil]; | |
| 96 // Padding between the title and the error image. | |
| 97 frame.size.width -= kButtonTitleImageSpacing; | |
| 98 } | |
| 99 | |
| 100 // Padding between the title (or error image, if it exists) and the | |
| 101 // button's drop down image. | |
| 102 frame.size.width -= kButtonTitleImageSpacing; | |
| 103 return [super drawTitle:title withFrame:frame inView:controlView]; | |
| 104 } | 89 } |
| 105 | 90 |
| 106 - (void)drawImage:(NSImage*)image | 91 - (void)drawImage:(NSImage*)image |
| 107 withFrame:(NSRect)frame | 92 withFrame:(NSRect)frame |
| 108 inView:(NSView*)controlView { | 93 inView:(NSView*)controlView { |
| 109 // For the x-offset, we need to undo the default padding and apply the | 94 // The image used in the generic button case needs to be shifted down |
| 110 // new one. For the y-offset, increasing the button height means we need | 95 // slightly to be centered correctly. |
| 111 // to move the image a little down to align it nicely with the text; this | 96 // TODO(noms): When the assets are fixed, remove this latter offset. |
| 112 // was chosen by visual inspection. | 97 if (!hasError_) |
| 113 frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2); | 98 frame = NSOffsetRect(frame, 0, 1); |
| 114 [super drawImage:image withFrame:frame inView:controlView]; | 99 [super drawImage:image withFrame:frame inView:controlView]; |
| 115 } | 100 } |
| 116 | 101 |
| 117 - (void)drawBezelWithFrame:(NSRect)frame | 102 - (void)drawBezelWithFrame:(NSRect)frame |
| 118 inView:(NSView*)controlView { | 103 inView:(NSView*)controlView { |
| 119 HoverState hoverState = | 104 HoverState hoverState = |
| 120 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState]; | 105 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState]; |
| 121 ui::NinePartImageIds imageIds = kNormalBorderImageIds; | 106 ui::NinePartImageIds imageIds = kNormalBorderImageIds; |
| 122 if (isThemedWindow_) | 107 if (isThemedWindow_) |
| 123 imageIds = kThemedBorderImageIds; | 108 imageIds = kThemedBorderImageIds; |
| 124 | 109 |
| 125 if (hoverState == kHoverStateMouseDown) | 110 if (hoverState == kHoverStateMouseDown) |
| 126 imageIds = kPressedBorderImageIds; | 111 imageIds = kPressedBorderImageIds; |
| 127 else if (hoverState == kHoverStateMouseOver) | 112 else if (hoverState == kHoverStateMouseOver) |
| 128 imageIds = kHoverBorderImageIds; | 113 imageIds = kHoverBorderImageIds; |
| 129 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); | 114 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); |
| 130 } | 115 } |
| 131 | 116 |
| 132 - (void)setIsThemedWindow:(BOOL)isThemedWindow { | 117 - (void)setIsThemedWindow:(BOOL)isThemedWindow { |
| 133 isThemedWindow_ = isThemedWindow; | 118 isThemedWindow_ = isThemedWindow; |
| 134 } | 119 } |
| 135 | 120 |
| 136 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title { | 121 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title { |
| 122 hasError_ = hasError; | |
| 137 if (hasError) { | 123 if (hasError) { |
| 138 authenticationErrorImage_.reset( | |
| 139 [ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
| 140 IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR).ToNSImage() retain]); | |
| 141 [self accessibilitySetOverrideValue:l10n_util::GetNSStringF( | 124 [self accessibilitySetOverrideValue:l10n_util::GetNSStringF( |
| 142 IDS_PROFILES_ACCOUNT_BUTTON_AUTH_ERROR_ACCESSIBLE_NAME, | 125 IDS_PROFILES_ACCOUNT_BUTTON_AUTH_ERROR_ACCESSIBLE_NAME, |
| 143 base::SysNSStringToUTF16(title)) | 126 base::SysNSStringToUTF16(title)) |
| 144 forAttribute:NSAccessibilityTitleAttribute]; | 127 forAttribute:NSAccessibilityTitleAttribute]; |
| 145 } else { | 128 } else { |
| 146 authenticationErrorImage_.reset(); | |
| 147 [self accessibilitySetOverrideValue:title | 129 [self accessibilitySetOverrideValue:title |
| 148 forAttribute:NSAccessibilityTitleAttribute]; | 130 forAttribute:NSAccessibilityTitleAttribute]; |
| 149 } | 131 } |
| 150 } | 132 } |
| 151 | 133 |
| 152 @end | 134 @end |
| 153 | 135 |
| 154 @interface AvatarButtonController (Private) | 136 @interface AvatarButtonController (Private) |
| 155 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; | 137 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; |
| 156 - (void)updateErrorStatus:(BOOL)hasError; | 138 - (void)updateErrorStatus:(BOOL)hasError; |
| 157 - (void)dealloc; | 139 - (void)dealloc; |
| 158 - (void)themeDidChangeNotification:(NSNotification*)aNotification; | 140 - (void)themeDidChangeNotification:(NSNotification*)aNotification; |
| 159 @end | 141 @end |
| 160 | 142 |
| 161 @implementation AvatarButtonController | 143 @implementation AvatarButtonController |
| 162 | 144 |
| 163 - (id)initWithBrowser:(Browser*)browser { | 145 - (id)initWithBrowser:(Browser*)browser { |
| 164 if ((self = [super initWithBrowser:browser])) { | 146 if ((self = [super initWithBrowser:browser])) { |
| 165 ThemeService* themeService = | 147 ThemeService* themeService = |
| 166 ThemeServiceFactory::GetForProfile(browser->profile()); | 148 ThemeServiceFactory::GetForProfile(browser->profile()); |
| 167 isThemedWindow_ = !themeService->UsingSystemTheme(); | 149 isThemedWindow_ = !themeService->UsingSystemTheme(); |
| 168 | 150 |
| 169 HoverImageButton* hoverButton = | 151 HoverImageButton* hoverButton = |
| 170 [[HoverImageButton alloc] initWithFrame:NSZeroRect]; | 152 [[HoverImageButton alloc] initWithFrame:NSZeroRect]; |
| 171 [hoverButton setDefaultImage:GetImageFromResourceID( | |
| 172 IDR_AVATAR_MAC_BUTTON_DROPARROW)]; | |
| 173 [hoverButton setHoverImage:GetImageFromResourceID( | |
| 174 IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)]; | |
| 175 [hoverButton setPressedImage:GetImageFromResourceID( | |
| 176 IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)]; | |
| 177 | |
| 178 button_.reset(hoverButton); | 153 button_.reset(hoverButton); |
| 179 base::scoped_nsobject<CustomThemeButtonCell> cell( | 154 base::scoped_nsobject<CustomThemeButtonCell> cell( |
| 180 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); | 155 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); |
| 156 [button_ setCell:cell.get()]; | |
| 157 | |
| 158 // Check if the account already has an authentication error. | |
| 181 SigninErrorController* errorController = | 159 SigninErrorController* errorController = |
| 182 profiles::GetSigninErrorController(browser->profile()); | 160 profiles::GetSigninErrorController(browser->profile()); |
| 183 | 161 hasError_ = errorController && errorController->HasError(); |
| 184 [button_ setCell:cell.get()]; | 162 [cell setHasError:hasError_ withTitle:nil]; |
| 185 | |
| 186 if (errorController) | |
| 187 [cell setHasError:errorController->HasError() withTitle:[button_ title]]; | |
| 188 | 163 |
| 189 [button_ setWantsLayer:YES]; | 164 [button_ setWantsLayer:YES]; |
| 190 [self setView:button_]; | 165 [self setView:button_]; |
| 191 | 166 |
| 192 [button_ setBezelStyle:NSShadowlessSquareBezelStyle]; | 167 [button_ setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 193 [button_ setButtonType:NSMomentaryChangeButton]; | 168 [button_ setButtonType:NSMomentaryChangeButton]; |
| 194 [button_ setBordered:YES]; | 169 [button_ setBordered:YES]; |
| 195 // This is a workaround for an issue in the HoverImageButton where the | 170 |
| 196 // button is initially sized incorrectly unless a default image is provided. | |
| 197 [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)]; | |
| 198 [button_ setImagePosition:NSImageRight]; | |
| 199 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; | 171 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; |
| 200 [button_ setTarget:self]; | 172 [button_ setTarget:self]; |
| 201 [button_ setAction:@selector(buttonClicked:)]; | 173 [button_ setAction:@selector(buttonClicked:)]; |
| 202 | 174 |
| 203 [self updateAvatarButtonAndLayoutParent:NO]; | 175 [self updateAvatarButtonAndLayoutParent:NO]; |
| 204 | 176 |
| 205 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | 177 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| 206 [center addObserver:self | 178 [center addObserver:self |
| 207 selector:@selector(themeDidChangeNotification:) | 179 selector:@selector(themeDidChangeNotification:) |
| 208 name:kBrowserThemeDidChangeNotification | 180 name:kBrowserThemeDidChangeNotification |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9]; | 213 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9]; |
| 242 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]]; | 214 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]]; |
| 243 } else if (!isThemedWindow_) { | 215 } else if (!isThemedWindow_) { |
| 244 foregroundColor = [NSColor blackColor]; | 216 foregroundColor = [NSColor blackColor]; |
| 245 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.7]]; | 217 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.7]]; |
| 246 } else { | 218 } else { |
| 247 foregroundColor = [NSColor blackColor]; | 219 foregroundColor = [NSColor blackColor]; |
| 248 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.4]]; | 220 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.4]]; |
| 249 } | 221 } |
| 250 | 222 |
| 251 NSString* buttonTitle = base::SysUTF16ToNSString( | 223 const ProfileInfoCache& cache = |
| 224 g_browser_process->profile_manager()->GetProfileInfoCache(); | |
| 225 // If we have a single local profile, then use the generic avatar | |
|
groby-ooo-7-16
2014/09/29 17:55:43
Tiny nit: "If there is a single...". "we" is some
noms (inactive)
2014/09/29 19:21:57
Done.
| |
| 226 // button instead of the profile name. Never use the generic button if | |
| 227 // the active profile is Guest. | |
| 228 bool useGenericButton = (!browser_->profile()->IsGuestSession() && | |
| 229 cache.GetNumberOfProfiles() == 1 && | |
| 230 cache.GetUserNameOfProfileAtIndex(0).empty()); | |
|
groby-ooo-7-16
2014/09/29 17:55:43
Question: Does it make sense to move this entire l
noms (inactive)
2014/09/29 19:21:57
Eeeek, it doesn't. Profile doesn't really know/spe
| |
| 231 | |
| 232 | |
| 233 NSString* buttonTitle = base::SysUTF16ToNSString(useGenericButton ? | |
| 234 base::string16() : | |
| 252 profiles::GetAvatarButtonTextForProfile(browser_->profile())); | 235 profiles::GetAvatarButtonTextForProfile(browser_->profile())); |
| 253 | 236 |
| 237 HoverImageButton* button = base::mac::ObjCCast<HoverImageButton>(button_); | |
| 238 if (useGenericButton) { | |
| 239 [button setDefaultImage:GetImageFromResourceID( | |
| 240 IDR_AVATAR_MAC_BUTTON_AVATAR)]; | |
| 241 [button setHoverImage:GetImageFromResourceID( | |
| 242 IDR_AVATAR_MAC_BUTTON_AVATAR_HOVER)]; | |
| 243 [button setPressedImage:GetImageFromResourceID( | |
| 244 IDR_AVATAR_MAC_BUTTON_AVATAR_PRESSED)]; | |
| 245 // This is a workaround for an issue in the HoverImageButton where the | |
| 246 // button is initially sized incorrectly unless a default image is provided. | |
| 247 // See crbug.com/298501. | |
| 248 [button setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_AVATAR)]; | |
| 249 [button setImagePosition:NSImageOnly]; | |
| 250 } else if (hasError_) { | |
| 251 [button setDefaultImage:GetImageFromResourceID( | |
| 252 IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR)]; | |
| 253 [button setHoverImage:nil]; | |
| 254 [button setPressedImage:nil]; | |
| 255 [button setImage:GetImageFromResourceID( | |
| 256 IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR)]; | |
| 257 [button setImagePosition:NSImageRight]; | |
| 258 } else { | |
| 259 [button setDefaultImage:nil]; | |
| 260 [button setHoverImage:nil]; | |
| 261 [button setPressedImage:nil]; | |
| 262 [button setImagePosition:NSNoImage]; | |
| 263 } | |
| 264 | |
| 254 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | 265 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( |
| 255 [[NSMutableParagraphStyle alloc] init]); | 266 [[NSMutableParagraphStyle alloc] init]); |
| 256 [paragraphStyle setAlignment:NSLeftTextAlignment]; | 267 [paragraphStyle setAlignment:NSLeftTextAlignment]; |
| 257 | 268 |
| 258 base::scoped_nsobject<NSAttributedString> attributedTitle( | 269 base::scoped_nsobject<NSAttributedString> attributedTitle( |
| 259 [[NSAttributedString alloc] | 270 [[NSAttributedString alloc] |
| 260 initWithString:buttonTitle | 271 initWithString:buttonTitle |
| 261 attributes:@{ NSShadowAttributeName : shadow.get(), | 272 attributes:@{ NSShadowAttributeName : shadow.get(), |
| 262 NSForegroundColorAttributeName : foregroundColor, | 273 NSForegroundColorAttributeName : foregroundColor, |
| 263 NSParagraphStyleAttributeName : paragraphStyle }]); | 274 NSParagraphStyleAttributeName : paragraphStyle }]); |
| 264 [button_ setAttributedTitle:attributedTitle]; | 275 [button_ setAttributedTitle:attributedTitle]; |
| 265 [button_ sizeToFit]; | 276 [button_ sizeToFit]; |
| 266 | 277 |
| 267 if (layoutParent) { | 278 if (layoutParent) { |
| 268 // Because the width of the button might have changed, the parent browser | 279 // Because the width of the button might have changed, the parent browser |
| 269 // frame needs to recalculate the button bounds and redraw it. | 280 // frame needs to recalculate the button bounds and redraw it. |
| 270 [[BrowserWindowController | 281 [[BrowserWindowController |
| 271 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] | 282 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] |
| 272 layoutSubviews]; | 283 layoutSubviews]; |
| 273 } | 284 } |
| 274 } | 285 } |
| 275 | 286 |
| 276 - (void)updateErrorStatus:(BOOL)hasError { | 287 - (void)updateErrorStatus:(BOOL)hasError { |
| 288 hasError_ = hasError; | |
| 277 [[button_ cell] setHasError:hasError withTitle:[button_ title]]; | 289 [[button_ cell] setHasError:hasError withTitle:[button_ title]]; |
| 278 [self updateAvatarButtonAndLayoutParent:YES]; | 290 [self updateAvatarButtonAndLayoutParent:YES]; |
| 279 } | 291 } |
| 280 | 292 |
| 281 @end | 293 @end |
| OLD | NEW |