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" | 9 #include "chrome/browser/browser_process.h" |
10 #include "chrome/browser/profiles/profile_attributes_entry.h" | 10 #include "chrome/browser/profiles/profile_attributes_entry.h" |
11 #include "chrome/browser/profiles/profile_attributes_storage.h" | 11 #include "chrome/browser/profiles/profile_attributes_storage.h" |
12 #include "chrome/browser/profiles/profile_manager.h" | 12 #include "chrome/browser/profiles/profile_manager.h" |
13 #include "chrome/browser/profiles/profiles_state.h" | 13 #include "chrome/browser/profiles/profiles_state.h" |
14 #include "chrome/browser/themes/theme_service.h" | 14 #include "chrome/browser/themes/theme_service.h" |
15 #include "chrome/browser/themes/theme_service_factory.h" | 15 #include "chrome/browser/themes/theme_service_factory.h" |
16 #include "chrome/browser/ui/browser.h" | 16 #include "chrome/browser/ui/browser.h" |
17 #include "chrome/browser/ui/browser_window.h" | 17 #include "chrome/browser/ui/browser_window.h" |
18 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 18 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
19 #import "chrome/browser/ui/cocoa/profiles/avatar_button.h" | 19 #import "chrome/browser/ui/cocoa/profiles/avatar_button.h" |
20 #include "chrome/grit/generated_resources.h" | 20 #include "chrome/grit/generated_resources.h" |
21 #include "chrome/grit/theme_resources.h" | 21 #include "chrome/grit/theme_resources.h" |
22 #include "components/signin/core/common/profile_management_switches.h" | 22 #include "components/signin/core/common/profile_management_switches.h" |
| 23 #include "skia/ext/skia_utils_mac.h" |
23 #import "ui/base/cocoa/appkit_utils.h" | 24 #import "ui/base/cocoa/appkit_utils.h" |
24 #include "ui/base/l10n/l10n_util_mac.h" | 25 #include "ui/base/l10n/l10n_util_mac.h" |
25 #include "ui/base/material_design/material_design_controller.h" | 26 #include "ui/base/material_design/material_design_controller.h" |
26 #include "ui/base/nine_image_painter_factory.h" | 27 #include "ui/base/nine_image_painter_factory.h" |
27 #include "ui/base/resource/resource_bundle.h" | 28 #include "ui/base/resource/resource_bundle.h" |
28 #include "ui/gfx/color_palette.h" | 29 #include "ui/gfx/color_palette.h" |
29 #include "ui/gfx/image/image_skia_operations.h" | 30 #include "ui/gfx/image/image_skia_operations.h" |
30 #include "ui/gfx/image/image_skia_util_mac.h" | 31 #include "ui/gfx/image/image_skia_util_mac.h" |
31 #include "ui/gfx/paint_vector_icon.h" | 32 #include "ui/gfx/paint_vector_icon.h" |
32 #include "ui/gfx/vector_icons_public.h" | 33 #include "ui/gfx/vector_icons_public.h" |
33 | 34 |
34 namespace { | 35 namespace { |
35 | 36 |
36 // NSButtons have a default padding of 5px. This button should have a padding | |
37 // of 8px. | |
38 const CGFloat kButtonExtraPadding = 8 - 5; | |
39 const CGFloat kButtonHeight = 28; | |
40 | |
41 const ui::NinePartImageIds kNormalBorderImageIds = | 37 const ui::NinePartImageIds kNormalBorderImageIds = |
42 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_NORMAL); | 38 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_NORMAL); |
43 const ui::NinePartImageIds kHoverBorderImageIds = | 39 const ui::NinePartImageIds kHoverBorderImageIds = |
44 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_HOVER); | 40 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_HOVER); |
45 const ui::NinePartImageIds kPressedBorderImageIds = | 41 const ui::NinePartImageIds kPressedBorderImageIds = |
46 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_PRESSED); | 42 IMAGE_GRID(IDR_AVATAR_NATIVE_BUTTON_PRESSED); |
47 const ui::NinePartImageIds kThemedBorderImageIds = | 43 const ui::NinePartImageIds kThemedBorderImageIds = |
48 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL); | 44 IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL); |
49 | 45 |
50 NSImage* GetImageFromResourceID(int resourceId) { | 46 NSImage* GetImageFromResourceID(int resourceId) { |
51 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( | 47 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
52 resourceId).ToNSImage(); | 48 resourceId).ToNSImage(); |
53 } | 49 } |
54 | 50 |
| 51 const SkColor kMaterialButtonHoverColor = SkColorSetARGB(20, 0, 0, 0); |
| 52 const SkColor kMaterialButtonPressedColor = SkColorSetARGB(31, 0, 0, 0); |
| 53 const SkColor kMaterialAvatarIconColor = SkColorSetRGB(0x5a, 0x5a, 0x5a); |
| 54 |
| 55 CGFloat ButtonHeight() { |
| 56 const CGFloat kButtonHeight = 28; |
| 57 const CGFloat kMaterialButtonHeight = 24; |
| 58 return ui::MaterialDesignController::IsModeMaterial() ? kMaterialButtonHeight |
| 59 : kButtonHeight; |
| 60 } |
| 61 |
| 62 // NSButtons have a default padding of 5px. Non-MD buttons should have a |
| 63 // padding of 8px. Meanwhile, MD buttons should have a padding of 6px. |
| 64 CGFloat ButtonExtraPadding() { |
| 65 const CGFloat kDefaultPadding = 5; |
| 66 const CGFloat kButtonExtraPadding = 8 - kDefaultPadding; |
| 67 const CGFloat kMaterialButtonExtraPadding = 6 - kDefaultPadding; |
| 68 |
| 69 return ui::MaterialDesignController::IsModeMaterial() |
| 70 ? kMaterialButtonExtraPadding |
| 71 : kButtonExtraPadding; |
| 72 } |
| 73 |
| 74 // Extra padding for the MD signed out avatar button. |
| 75 const CGFloat kMaterialSignedOutWidthPadding = 2; |
| 76 |
55 } // namespace | 77 } // namespace |
56 | 78 |
57 // Button cell with a custom border given by a set of nine-patch image grids. | 79 // Button cell with a custom border given by a set of nine-patch image grids. |
58 @interface CustomThemeButtonCell : NSButtonCell { | 80 @interface CustomThemeButtonCell : NSButtonCell { |
59 @private | 81 @private |
60 BOOL isThemedWindow_; | 82 BOOL isThemedWindow_; |
61 BOOL hasError_; | 83 BOOL hasError_; |
62 } | 84 } |
63 - (void)setIsThemedWindow:(BOOL)isThemedWindow; | 85 - (void)setIsThemedWindow:(BOOL)isThemedWindow; |
64 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title; | 86 - (void)setHasError:(BOOL)hasError withTitle:(NSString*)title; |
65 | 87 |
66 @end | 88 @end |
67 | 89 |
68 @implementation CustomThemeButtonCell | 90 @implementation CustomThemeButtonCell |
69 - (id)initWithThemedWindow:(BOOL)isThemedWindow { | 91 - (id)initWithThemedWindow:(BOOL)isThemedWindow { |
70 if ((self = [super init])) { | 92 if ((self = [super init])) { |
71 isThemedWindow_ = isThemedWindow; | 93 isThemedWindow_ = isThemedWindow; |
72 hasError_ = false; | 94 hasError_ = false; |
73 } | 95 } |
74 return self; | 96 return self; |
75 } | 97 } |
76 | 98 |
77 - (NSSize)cellSize { | 99 - (NSSize)cellSize { |
78 NSSize buttonSize = [super cellSize]; | 100 NSSize buttonSize = [super cellSize]; |
79 | 101 |
80 // An image and no error means we are drawing the generic button, which | 102 // An image and no error means we are drawing the generic button, which |
81 // is square. Otherwise, we are displaying the profile's name and an | 103 // is square. Otherwise, we are displaying the profile's name and an |
82 // optional authentication error icon. | 104 // optional authentication error icon. |
83 if ([self image] && !hasError_) { | 105 if ([self image] && !hasError_) { |
84 buttonSize.width = kButtonHeight; | 106 buttonSize.width = ButtonHeight(); |
| 107 if (ui::MaterialDesignController::IsModeMaterial()) |
| 108 buttonSize.width += kMaterialSignedOutWidthPadding; |
85 } else { | 109 } else { |
86 buttonSize.width += 2 * kButtonExtraPadding; | 110 buttonSize.width += 2 * ButtonExtraPadding(); |
87 } | 111 } |
88 buttonSize.height = kButtonHeight; | 112 buttonSize.height = ButtonHeight(); |
89 return buttonSize; | 113 return buttonSize; |
90 } | 114 } |
91 | 115 |
92 - (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)controlView { | 116 - (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)controlView { |
93 NSRect frameAfterPadding = NSInsetRect(frame, kButtonExtraPadding, 0); | 117 NSRect frameAfterPadding = NSInsetRect(frame, ButtonExtraPadding(), 0); |
94 [super drawInteriorWithFrame:frameAfterPadding inView:controlView]; | 118 [super drawInteriorWithFrame:frameAfterPadding inView:controlView]; |
95 } | 119 } |
96 | 120 |
97 - (void)drawImage:(NSImage*)image | 121 - (void)drawImage:(NSImage*)image |
98 withFrame:(NSRect)frame | 122 withFrame:(NSRect)frame |
99 inView:(NSView*)controlView { | 123 inView:(NSView*)controlView { |
100 // The image used in the generic button case as well as the material-designed | 124 // The image used in the generic button case as well as the material-designed |
101 // error icon both need to be shifted down slightly to be centered correctly. | 125 // error icon both need to be shifted down slightly to be centered correctly. |
102 // TODO(noms): When the assets are fixed, remove this latter offset. | 126 // TODO(noms): When the assets are fixed, remove this latter offset. |
103 if (!hasError_ || switches::IsMaterialDesignUserMenu()) | 127 if (!hasError_ || switches::IsMaterialDesignUserMenu()) |
104 frame = NSOffsetRect(frame, 0, 1); | 128 frame = NSOffsetRect(frame, 0, 1); |
105 [super drawImage:image withFrame:frame inView:controlView]; | 129 [super drawImage:image withFrame:frame inView:controlView]; |
106 } | 130 } |
107 | 131 |
108 - (void)drawBezelWithFrame:(NSRect)frame | 132 - (void)drawBezelWithFrame:(NSRect)frame |
109 inView:(NSView*)controlView { | 133 inView:(NSView*)controlView { |
110 HoverState hoverState = | 134 HoverState hoverState = |
111 [base::mac::ObjCCastStrict<AvatarButton>(controlView) hoverState]; | 135 [base::mac::ObjCCastStrict<AvatarButton>(controlView) hoverState]; |
112 ui::NinePartImageIds imageIds = kNormalBorderImageIds; | |
113 if (isThemedWindow_) | |
114 imageIds = kThemedBorderImageIds; | |
115 | 136 |
116 if (hoverState == kHoverStateMouseDown) | 137 if (ui::MaterialDesignController::IsModeMaterial()) { |
117 imageIds = kPressedBorderImageIds; | 138 NSColor* backgroundColor = nil; |
118 else if (hoverState == kHoverStateMouseOver) | 139 if (hoverState == kHoverStateMouseDown) { |
119 imageIds = kHoverBorderImageIds; | 140 backgroundColor = skia::SkColorToSRGBNSColor(kMaterialButtonPressedColor); |
120 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); | 141 } else if (hoverState == kHoverStateMouseOver) { |
| 142 backgroundColor = skia::SkColorToSRGBNSColor(kMaterialButtonHoverColor); |
| 143 } |
| 144 |
| 145 if (backgroundColor) { |
| 146 [backgroundColor set]; |
| 147 NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:frame |
| 148 xRadius:2.0f |
| 149 yRadius:2.0f]; |
| 150 [path fill]; |
| 151 } |
| 152 } else { |
| 153 ui::NinePartImageIds imageIds = kNormalBorderImageIds; |
| 154 if (isThemedWindow_) |
| 155 imageIds = kThemedBorderImageIds; |
| 156 |
| 157 if (hoverState == kHoverStateMouseDown) |
| 158 imageIds = kPressedBorderImageIds; |
| 159 else if (hoverState == kHoverStateMouseOver) |
| 160 imageIds = kHoverBorderImageIds; |
| 161 ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true); |
| 162 } |
121 } | 163 } |
122 | 164 |
123 - (void)drawFocusRingMaskWithFrame:(NSRect)frame inView:(NSView*)view { | 165 - (void)drawFocusRingMaskWithFrame:(NSRect)frame inView:(NSView*)view { |
124 // Match the bezel's shape. | 166 // Match the bezel's shape. |
125 [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2, 2) | 167 [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2, 2) |
126 xRadius:2 | 168 xRadius:2 |
127 yRadius:2] fill]; | 169 yRadius:2] fill]; |
128 } | 170 } |
129 | 171 |
130 - (void)setIsThemedWindow:(BOOL)isThemedWindow { | 172 - (void)setIsThemedWindow:(BOOL)isThemedWindow { |
(...skipping 24 matching lines...) Expand all Loading... |
155 | 197 |
156 - (id)initWithBrowser:(Browser*)browser { | 198 - (id)initWithBrowser:(Browser*)browser { |
157 if ((self = [super initWithBrowser:browser])) { | 199 if ((self = [super initWithBrowser:browser])) { |
158 ThemeService* themeService = | 200 ThemeService* themeService = |
159 ThemeServiceFactory::GetForProfile(browser->profile()); | 201 ThemeServiceFactory::GetForProfile(browser->profile()); |
160 isThemedWindow_ = !themeService->UsingSystemTheme(); | 202 isThemedWindow_ = !themeService->UsingSystemTheme(); |
161 | 203 |
162 AvatarButton* avatarButton = | 204 AvatarButton* avatarButton = |
163 [[AvatarButton alloc] initWithFrame:NSZeroRect]; | 205 [[AvatarButton alloc] initWithFrame:NSZeroRect]; |
164 button_.reset(avatarButton); | 206 button_.reset(avatarButton); |
165 base::scoped_nsobject<CustomThemeButtonCell> cell( | 207 |
| 208 base::scoped_nsobject<NSButtonCell> cell( |
166 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); | 209 [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); |
| 210 |
167 [avatarButton setCell:cell.get()]; | 211 [avatarButton setCell:cell.get()]; |
168 | 212 |
169 [avatarButton setWantsLayer:YES]; | 213 [avatarButton setWantsLayer:YES]; |
170 [self setView:avatarButton]; | 214 [self setView:avatarButton]; |
171 | 215 |
172 [avatarButton setBezelStyle:NSShadowlessSquareBezelStyle]; | 216 [avatarButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
173 [avatarButton setButtonType:NSMomentaryChangeButton]; | 217 [avatarButton setButtonType:NSMomentaryChangeButton]; |
174 if (switches::IsMaterialDesignUserMenu()) | 218 if (switches::IsMaterialDesignUserMenu()) |
175 [[avatarButton cell] setHighlightsBy:NSNoCellMask]; | 219 [[avatarButton cell] setHighlightsBy:NSNoCellMask]; |
176 [avatarButton setBordered:YES]; | 220 [avatarButton setBordered:YES]; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 !storage.GetAllProfilesAttributes().front()->IsAuthenticated(); | 287 !storage.GetAllProfilesAttributes().front()->IsAuthenticated(); |
244 | 288 |
245 | 289 |
246 NSString* buttonTitle = base::SysUTF16ToNSString(useGenericButton ? | 290 NSString* buttonTitle = base::SysUTF16ToNSString(useGenericButton ? |
247 base::string16() : | 291 base::string16() : |
248 profiles::GetAvatarButtonTextForProfile(browser_->profile())); | 292 profiles::GetAvatarButtonTextForProfile(browser_->profile())); |
249 [[button_ cell] setHasError:hasError_ withTitle:buttonTitle]; | 293 [[button_ cell] setHasError:hasError_ withTitle:buttonTitle]; |
250 | 294 |
251 AvatarButton* button = | 295 AvatarButton* button = |
252 base::mac::ObjCCastStrict<AvatarButton>(button_); | 296 base::mac::ObjCCastStrict<AvatarButton>(button_); |
| 297 |
253 if (useGenericButton) { | 298 if (useGenericButton) { |
254 [button setDefaultImage:GetImageFromResourceID( | 299 if (ui::MaterialDesignController::IsModeMaterial()) { |
255 IDR_AVATAR_NATIVE_BUTTON_AVATAR)]; | 300 NSImage* avatarIcon = NSImageFromImageSkia( |
256 [button setHoverImage:GetImageFromResourceID( | 301 gfx::CreateVectorIcon(gfx::VectorIconId::USER_ACCOUNT_AVATAR, 18, |
257 IDR_AVATAR_NATIVE_BUTTON_AVATAR_HOVER)]; | 302 kMaterialAvatarIconColor)); |
258 [button setPressedImage:GetImageFromResourceID( | 303 [button setDefaultImage:avatarIcon]; |
259 IDR_AVATAR_NATIVE_BUTTON_AVATAR_PRESSED)]; | 304 [button setHoverImage:nil]; |
260 // This is a workaround for an issue in the HoverImageButton where the | 305 [button setPressedImage:nil]; |
261 // button is initially sized incorrectly unless a default image is provided. | 306 } else { |
262 // See crbug.com/298501. | 307 [button setDefaultImage:GetImageFromResourceID( |
263 [button setImage:GetImageFromResourceID(IDR_AVATAR_NATIVE_BUTTON_AVATAR)]; | 308 IDR_AVATAR_NATIVE_BUTTON_AVATAR)]; |
| 309 [button setHoverImage:GetImageFromResourceID( |
| 310 IDR_AVATAR_NATIVE_BUTTON_AVATAR_HOVER)]; |
| 311 [button setPressedImage:GetImageFromResourceID( |
| 312 IDR_AVATAR_NATIVE_BUTTON_AVATAR_PRESSED)]; |
| 313 // This is a workaround for an issue in the HoverImageButton where the |
| 314 // button is initially sized incorrectly unless a default image is |
| 315 // provided. |
| 316 // See crbug.com/298501. |
| 317 [button setImage:GetImageFromResourceID(IDR_AVATAR_NATIVE_BUTTON_AVATAR)]; |
| 318 } |
264 [button setImagePosition:NSImageOnly]; | 319 [button setImagePosition:NSImageOnly]; |
265 } else if (hasError_) { | 320 } else if (hasError_) { |
| 321 BOOL isMaterial = ui::MaterialDesignController::IsModeMaterial(); |
266 NSImage* errorIcon = | 322 NSImage* errorIcon = |
267 switches::IsMaterialDesignUserMenu() | 323 isMaterial |
268 ? NSImageFromImageSkia(gfx::CreateVectorIcon( | 324 ? NSImageFromImageSkia(gfx::CreateVectorIcon( |
269 gfx::VectorIconId::SYNC_PROBLEM, 16, gfx::kGoogleRed700)) | 325 gfx::VectorIconId::SYNC_PROBLEM, 16, gfx::kGoogleRed700)) |
270 : GetImageFromResourceID(IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR); | 326 : GetImageFromResourceID(IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR); |
271 [button setDefaultImage:errorIcon]; | 327 [button setDefaultImage:errorIcon]; |
272 [button setHoverImage:nil]; | 328 [button setHoverImage:nil]; |
273 [button setPressedImage:nil]; | 329 [button setPressedImage:nil]; |
274 [button setImage:errorIcon]; | 330 [button setImage:errorIcon]; |
275 [button setImagePosition:switches::IsMaterialDesignUserMenu() | 331 [button setImagePosition:isMaterial ? NSImageLeft : NSImageRight]; |
276 ? NSImageLeft | |
277 : NSImageRight]; | |
278 } else { | 332 } else { |
279 [button setDefaultImage:nil]; | 333 [button setDefaultImage:nil]; |
280 [button setHoverImage:nil]; | 334 [button setHoverImage:nil]; |
281 [button setPressedImage:nil]; | 335 [button setPressedImage:nil]; |
282 [button setImagePosition:NSNoImage]; | 336 [button setImagePosition:NSNoImage]; |
283 } | 337 } |
284 | 338 |
285 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | 339 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( |
286 [[NSMutableParagraphStyle alloc] init]); | 340 [[NSMutableParagraphStyle alloc] init]); |
287 [paragraphStyle setAlignment:NSLeftTextAlignment]; | 341 [paragraphStyle setAlignment:NSLeftTextAlignment]; |
(...skipping 15 matching lines...) Expand all Loading... |
303 layoutSubviews]; | 357 layoutSubviews]; |
304 } | 358 } |
305 } | 359 } |
306 | 360 |
307 - (void)setErrorStatus:(BOOL)hasError { | 361 - (void)setErrorStatus:(BOOL)hasError { |
308 hasError_ = hasError; | 362 hasError_ = hasError; |
309 [self updateAvatarButtonAndLayoutParent:YES]; | 363 [self updateAvatarButtonAndLayoutParent:YES]; |
310 } | 364 } |
311 | 365 |
312 @end | 366 @end |
OLD | NEW |