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/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_; | |
| 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( | |
| 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 errorImageWidth = hasError_ ? kAuthErrorIconWidth : 0; |
|
msw
2014/06/03 04:15:31
nit: errorWidth or imageWidth for a one-liner belo
noms (inactive)
2014/06/06 20:33:43
Done.
| |
| 84 buttonSize.width += | |
| 85 2 * (kButtonPadding - kButtonDefaultPadding) + errorImageWidth; | |
| 67 buttonSize.height = kButtonHeight; | 86 buttonSize.height = kButtonHeight; |
| 68 return buttonSize; | 87 return buttonSize; |
| 69 } | 88 } |
| 70 | 89 |
| 71 - (NSRect)drawTitle:(NSAttributedString*)title | 90 - (NSRect)drawTitle:(NSAttributedString*)title |
| 72 withFrame:(NSRect)frame | 91 withFrame:(NSRect)frame |
| 73 inView:(NSView*)controlView { | 92 inView:(NSView*)controlView { |
| 74 frame.origin.x = kButtonPadding; | 93 frame.origin.x = kButtonPadding; |
| 75 // Ensure there's always a padding between the text and the image. | 94 // Ensure there's always a padding between the text and the image. |
| 76 frame.size.width -= kButtonTitleImageSpacing; | 95 frame.size.width -= hasError_ ? 2 * kButtonTitleImageSpacing : |
| 96 kButtonTitleImageSpacing; | |
| 77 return [super drawTitle:title withFrame:frame inView:controlView]; | 97 return [super drawTitle:title withFrame:frame inView:controlView]; |
| 78 } | 98 } |
| 79 | 99 |
| 80 - (void)drawImage:(NSImage*)image | 100 - (void)drawImage:(NSImage*)image |
| 81 withFrame:(NSRect)frame | 101 withFrame:(NSRect)frame |
| 82 inView:(NSView*)controlView { | 102 inView:(NSView*)controlView { |
| 103 // If there's an auth error, draw a warning icon before the cell image. | |
| 104 if (hasError_) { | |
| 105 NSSize imageSize = [authErrorImage_ size]; | |
| 106 NSRect rect = NSMakeRect( | |
| 107 frame.origin.x - imageSize.width - kButtonTitleImageSpacing, | |
| 108 (kButtonHeight - imageSize.height) / 2, | |
| 109 imageSize.width, | |
| 110 imageSize.height); | |
| 111 [authErrorImage_ drawInRect:rect | |
| 112 fromRect:NSZeroRect | |
| 113 operation:NSCompositeSourceOver | |
| 114 fraction:1.0 | |
| 115 respectFlipped:YES | |
| 116 hints:nil]; | |
| 117 } | |
| 83 // For the x-offset, we need to undo the default padding and apply the | 118 // 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 | 119 // 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 | 120 // to move the image a little down to align it nicely with the text; this |
| 86 // was chosen by visual inspection. | 121 // was chosen by visual inspection. |
| 87 frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2); | 122 frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2); |
| 88 [super drawImage:image withFrame:frame inView:controlView]; | 123 [super drawImage:image withFrame:frame inView:controlView]; |
| 89 } | 124 } |
| 90 | 125 |
| 91 - (void)drawBezelWithFrame:(NSRect)frame | 126 - (void)drawBezelWithFrame:(NSRect)frame |
| 92 inView:(NSView*)controlView { | 127 inView:(NSView*)controlView { |
| 93 HoverState hoverState = | 128 HoverState hoverState = |
| 94 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState]; | 129 [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState]; |
| 95 ui::NinePartImageIds imageIds = kNormalBorderImageIds; | 130 ui::NinePartImageIds imageIds = kNormalBorderImageIds; |
| 96 if (isThemedWindow_) | 131 if (isThemedWindow_) |
| 97 imageIds = kThemedBorderImageIds; | 132 imageIds = kThemedBorderImageIds; |
| 98 | 133 |
| 99 if (hoverState == kHoverStateMouseDown) | 134 if (hoverState == kHoverStateMouseDown) |
| 100 imageIds = kPressedBorderImageIds; | 135 imageIds = kPressedBorderImageIds; |
| 101 else if (hoverState == kHoverStateMouseOver) | 136 else if (hoverState == kHoverStateMouseOver) |
| 102 imageIds = kHoverBorderImageIds; | 137 imageIds = kHoverBorderImageIds; |
| 103 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); | 138 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); |
| 104 } | 139 } |
| 105 | 140 |
| 106 - (void)setIsThemedWindow:(BOOL)isThemedWindow { | 141 - (void)setIsThemedWindow:(BOOL)isThemedWindow { |
| 107 isThemedWindow_ = isThemedWindow; | 142 isThemedWindow_ = isThemedWindow; |
| 108 } | 143 } |
| 144 | |
| 145 - (void)setHasError:(BOOL)hasError { | |
| 146 hasError_ = hasError; | |
| 147 } | |
| 148 | |
| 109 @end | 149 @end |
| 110 | 150 |
| 111 @interface AvatarButtonController (Private) | 151 @interface AvatarButtonController (Private) |
| 112 - (base::string16)getElidedAvatarName; | 152 - (base::string16)getElidedAvatarName; |
| 113 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; | 153 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; |
| 154 - (void)updateErrorStatus:(BOOL)hasError; | |
| 114 - (void)dealloc; | 155 - (void)dealloc; |
| 115 - (void)themeDidChangeNotification:(NSNotification*)aNotification; | 156 - (void)themeDidChangeNotification:(NSNotification*)aNotification; |
| 116 @end | 157 @end |
| 117 | 158 |
| 118 @implementation AvatarButtonController | 159 @implementation AvatarButtonController |
| 119 | 160 |
| 120 - (id)initWithBrowser:(Browser*)browser { | 161 - (id)initWithBrowser:(Browser*)browser { |
| 121 if ((self = [super initWithBrowser:browser])) { | 162 if ((self = [super initWithBrowser:browser])) { |
| 122 ThemeService* themeService = | 163 ThemeService* themeService = |
| 123 ThemeServiceFactory::GetForProfile(browser->profile()); | 164 ThemeServiceFactory::GetForProfile(browser->profile()); |
| 124 isThemedWindow_ = !themeService->UsingSystemTheme(); | 165 isThemedWindow_ = !themeService->UsingSystemTheme(); |
| 125 | 166 |
| 126 HoverImageButton* hoverButton = | 167 HoverImageButton* hoverButton = |
| 127 [[HoverImageButton alloc] initWithFrame:NSZeroRect]; | 168 [[HoverImageButton alloc] initWithFrame:NSZeroRect]; |
| 128 [hoverButton setDefaultImage:GetImageFromResourceID( | 169 [hoverButton setDefaultImage:GetImageFromResourceID( |
| 129 IDR_AVATAR_MAC_BUTTON_DROPARROW)]; | 170 IDR_AVATAR_MAC_BUTTON_DROPARROW)]; |
| 130 [hoverButton setHoverImage:GetImageFromResourceID( | 171 [hoverButton setHoverImage:GetImageFromResourceID( |
| 131 IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)]; | 172 IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)]; |
| 132 [hoverButton setPressedImage:GetImageFromResourceID( | 173 [hoverButton setPressedImage:GetImageFromResourceID( |
| 133 IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)]; | 174 IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)]; |
| 134 | 175 |
| 135 button_.reset(hoverButton); | 176 button_.reset(hoverButton); |
| 136 base::scoped_nsobject<CustomThemeButtonCell> cell( | 177 base::scoped_nsobject<CustomThemeButtonCell> cell( |
| 137 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); | 178 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); |
| 179 SigninErrorController* error = | |
| 180 profiles::GetSigninErrorController(browser->profile()); | |
| 181 if (error) | |
| 182 [cell setHasError:error->HasError()]; | |
|
msw
2014/06/03 04:15:31
ditto nit: should the button state be set if |erro
noms (inactive)
2014/06/06 20:33:43
As mentioned before, |error| can't be nil once, an
| |
| 138 [button_ setCell:cell.get()]; | 183 [button_ setCell:cell.get()]; |
| 139 [self setView:button_]; | 184 [self setView:button_]; |
| 140 | 185 |
| 141 [button_ setBezelStyle:NSShadowlessSquareBezelStyle]; | 186 [button_ setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 142 [button_ setButtonType:NSMomentaryChangeButton]; | 187 [button_ setButtonType:NSMomentaryChangeButton]; |
| 143 [button_ setBordered:YES]; | 188 [button_ setBordered:YES]; |
| 144 // This is a workaround for an issue in the HoverImageButton where the | 189 // This is a workaround for an issue in the HoverImageButton where the |
| 145 // button is initially sized incorrectly unless a default image is provided. | 190 // button is initially sized incorrectly unless a default image is provided. |
| 146 [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)]; | 191 [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)]; |
| 147 [button_ setImagePosition:NSImageRight]; | 192 [button_ setImagePosition:NSImageRight]; |
| 148 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; | 193 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; |
| 149 [button_ setTarget:self]; | 194 [button_ setTarget:self]; |
| 150 [button_ setAction:@selector(buttonClicked:)]; | 195 [button_ setAction:@selector(buttonClicked:)]; |
| 151 | 196 |
| 152 [self updateAvatarButtonAndLayoutParent:NO]; | 197 [self updateAvatarButtonAndLayoutParent:NO]; |
| 153 | 198 |
| 154 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | 199 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| 155 [center addObserver:self | 200 [center addObserver:self |
| 156 selector:@selector(themeDidChangeNotification:) | 201 selector:@selector(themeDidChangeNotification:) |
| 157 name:kBrowserThemeDidChangeNotification | 202 name:kBrowserThemeDidChangeNotification |
| 158 object:nil]; | 203 object:nil]; |
| 159 | |
| 160 } | 204 } |
| 161 return self; | 205 return self; |
| 162 } | 206 } |
| 163 | 207 |
| 164 - (void)dealloc { | 208 - (void)dealloc { |
| 165 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 209 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 166 [super dealloc]; | 210 [super dealloc]; |
| 167 } | 211 } |
| 168 | 212 |
| 169 - (void)themeDidChangeNotification:(NSNotification*)aNotification { | 213 - (void)themeDidChangeNotification:(NSNotification*)aNotification { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 185 return gfx::ElideText(avatarName, | 229 return gfx::ElideText(avatarName, |
| 186 gfx::FontList(gfx::Font([button_ font])), | 230 gfx::FontList(gfx::Font([button_ font])), |
| 187 maxTextWidth, | 231 maxTextWidth, |
| 188 gfx::ELIDE_AT_END); | 232 gfx::ELIDE_AT_END); |
| 189 } | 233 } |
| 190 | 234 |
| 191 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent { | 235 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent { |
| 192 // The button text has a black foreground and a white drop shadow for regular | 236 // The button text has a black foreground and a white drop shadow for regular |
| 193 // windows, and a light text with a dark drop shadow for guest windows | 237 // windows, and a light text with a dark drop shadow for guest windows |
| 194 // which are themed with a dark background. | 238 // which are themed with a dark background. |
| 195 // TODO(noms): Figure out something similar for themed windows, if possible. | |
|
msw
2014/06/03 04:15:31
Why is this no more applicable?
noms (inactive)
2014/06/06 20:33:43
Left over todo that never got updated :) The code
| |
| 196 base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); | 239 base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); |
| 197 [shadow setShadowOffset:NSMakeSize(0, -1)]; | 240 [shadow setShadowOffset:NSMakeSize(0, -1)]; |
| 198 [shadow setShadowBlurRadius:0]; | 241 [shadow setShadowBlurRadius:0]; |
| 199 | 242 |
| 200 NSColor* foregroundColor; | 243 NSColor* foregroundColor; |
| 201 if (browser_->profile()->IsGuestSession()) { | 244 if (browser_->profile()->IsGuestSession()) { |
| 202 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9]; | 245 foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9]; |
| 203 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]]; | 246 [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]]; |
| 204 } else if (!isThemedWindow_) { | 247 } else if (!isThemedWindow_) { |
| 205 foregroundColor = [NSColor blackColor]; | 248 foregroundColor = [NSColor blackColor]; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 235 | 278 |
| 236 if (layoutParent) { | 279 if (layoutParent) { |
| 237 // Because the width of the button might have changed, the parent browser | 280 // Because the width of the button might have changed, the parent browser |
| 238 // frame needs to recalculate the button bounds and redraw it. | 281 // frame needs to recalculate the button bounds and redraw it. |
| 239 [[BrowserWindowController | 282 [[BrowserWindowController |
| 240 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] | 283 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] |
| 241 layoutSubviews]; | 284 layoutSubviews]; |
| 242 } | 285 } |
| 243 } | 286 } |
| 244 | 287 |
| 288 - (void)updateErrorStatus:(BOOL)hasError { | |
| 289 [[button_ cell] setHasError:hasError]; | |
| 290 [self updateAvatarButtonAndLayoutParent:YES]; | |
| 291 } | |
| 292 | |
| 245 @end | 293 @end |
| OLD | NEW |