[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / profiles / avatar_button_controller.mm
blob93810f3afe2b1c0b23f10836a811a60c807f3217
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
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h"
7 #include "base/mac/foundation_util.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "chrome/browser/profiles/profiles_state.h"
10 #include "chrome/browser/themes/theme_service.h"
11 #include "chrome/browser/themes/theme_service_factory.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_window.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #include "grit/generated_resources.h"
16 #include "grit/theme_resources.h"
17 #import "ui/base/cocoa/appkit_utils.h"
18 #import "ui/base/cocoa/hover_image_button.h"
19 #include "ui/base/l10n/l10n_util_mac.h"
20 #include "ui/base/nine_image_painter_factory.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/gfx/text_elider.h"
24 namespace {
26 const CGFloat kButtonPadding = 12;
27 const CGFloat kButtonDefaultPadding = 5;
28 const CGFloat kButtonHeight = 27;
29 const CGFloat kButtonTitleImageSpacing = 10;
30 const CGFloat kMaxButtonWidth = 120;
32 const ui::NinePartImageIds kNormalBorderImageIds =
33     IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_NORMAL);
34 const ui::NinePartImageIds kHoverBorderImageIds =
35     IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_HOVER);
36 const ui::NinePartImageIds kPressedBorderImageIds =
37     IMAGE_GRID(IDR_AVATAR_MAC_BUTTON_PRESSED);
38 const ui::NinePartImageIds kThemedBorderImageIds =
39     IMAGE_GRID(IDR_AVATAR_THEMED_MAC_BUTTON_NORMAL);
41 NSImage* GetImageFromResourceID(int resourceId) {
42   return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
43       resourceId).ToNSImage();
46 }  // namespace
48 // Button cell with a custom border given by a set of nine-patch image grids.
49 @interface CustomThemeButtonCell : NSButtonCell {
50  @private
51    BOOL isThemedWindow_;
53 - (void)setIsThemedWindow:(BOOL)isThemedWindow;
54 @end
56 @implementation CustomThemeButtonCell
57 - (id)initWithThemedWindow:(BOOL)isThemedWindow {
58   if ((self = [super init])) {
59     isThemedWindow_ = isThemedWindow;
60   }
61   return self;
64 - (NSSize)cellSize {
65   NSSize buttonSize = [super cellSize];
66   buttonSize.width += 2 * kButtonPadding - 2 * kButtonDefaultPadding;
67   buttonSize.height = kButtonHeight;
68   return buttonSize;
71 - (NSRect)drawTitle:(NSAttributedString*)title
72           withFrame:(NSRect)frame
73              inView:(NSView*)controlView {
74   frame.origin.x = kButtonPadding;
75   // Ensure there's always a padding between the text and the image.
76   frame.size.width -= kButtonTitleImageSpacing;
77   return [super drawTitle:title withFrame:frame inView:controlView];
80 - (void)drawImage:(NSImage*)image
81         withFrame:(NSRect)frame
82            inView:(NSView*)controlView {
83   // 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
85   // to move the image a little down to align it nicely with the text; this
86   // was chosen by visual inspection.
87   frame = NSOffsetRect(frame, kButtonDefaultPadding - kButtonPadding, 2);
88   [super drawImage:image withFrame:frame inView:controlView];
91 - (void)drawBezelWithFrame:(NSRect)frame
92                     inView:(NSView*)controlView {
93   HoverState hoverState =
94       [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState];
95   ui::NinePartImageIds imageIds = kNormalBorderImageIds;
96   if (isThemedWindow_)
97     imageIds = kThemedBorderImageIds;
99   if (hoverState == kHoverStateMouseDown)
100     imageIds = kPressedBorderImageIds;
101   else if (hoverState == kHoverStateMouseOver)
102     imageIds = kHoverBorderImageIds;
103   ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true);
106 - (void)setIsThemedWindow:(BOOL)isThemedWindow {
107   isThemedWindow_ = isThemedWindow;
109 @end
111 @interface AvatarButtonController (Private)
112 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
113 - (void)dealloc;
114 - (void)themeDidChangeNotification:(NSNotification*)aNotification;
115 @end
117 @implementation AvatarButtonController
119 - (id)initWithBrowser:(Browser*)browser {
120   if ((self = [super initWithBrowser:browser])) {
121     ThemeService* themeService =
122         ThemeServiceFactory::GetForProfile(browser->profile());
123     isThemedWindow_ = !themeService->UsingSystemTheme();
125     HoverImageButton* hoverButton =
126         [[HoverImageButton alloc] initWithFrame:NSZeroRect];
127     [hoverButton setDefaultImage:GetImageFromResourceID(
128         IDR_AVATAR_MAC_BUTTON_DROPARROW)];
129     [hoverButton setHoverImage:GetImageFromResourceID(
130         IDR_AVATAR_MAC_BUTTON_DROPARROW_HOVER)];
131     [hoverButton setPressedImage:GetImageFromResourceID(
132         IDR_AVATAR_MAC_BUTTON_DROPARROW_PRESSED)];
134     button_.reset(hoverButton);
135     base::scoped_nsobject<CustomThemeButtonCell> cell(
136         [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]);
137     [button_ setCell:cell.get()];
138     [self setView:button_];
140     [button_ setBezelStyle:NSShadowlessSquareBezelStyle];
141     [button_ setButtonType:NSMomentaryChangeButton];
142     [button_ setBordered:YES];
143     // This is a workaround for an issue in the HoverImageButton where the
144     // button is initially sized incorrectly unless a default image is provided.
145     [button_ setImage:GetImageFromResourceID(IDR_AVATAR_MAC_BUTTON_DROPARROW)];
146     [button_ setImagePosition:NSImageRight];
147     [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
148     [button_ setTarget:self];
149     [button_ setAction:@selector(buttonClicked:)];
151     [self updateAvatarButtonAndLayoutParent:NO];
153     NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
154     [center addObserver:self
155                selector:@selector(themeDidChangeNotification:)
156                    name:kBrowserThemeDidChangeNotification
157                  object:nil];
159   }
160   return self;
163 - (void)dealloc {
164   [[NSNotificationCenter defaultCenter] removeObserver:self];
165   [super dealloc];
168 - (void)themeDidChangeNotification:(NSNotification*)aNotification {
169   // Redraw the button if the window has switched between themed and native.
170   ThemeService* themeService =
171       ThemeServiceFactory::GetForProfile(browser_->profile());
172   BOOL updatedIsThemedWindow = !themeService->UsingSystemTheme();
173   if (isThemedWindow_ != updatedIsThemedWindow) {
174     isThemedWindow_ = updatedIsThemedWindow;
175     [[button_ cell] setIsThemedWindow:isThemedWindow_];
176     [self updateAvatarButtonAndLayoutParent:YES];
177   }
180 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent {
181   // The button text has a black foreground and a white drop shadow for regular
182   // windows, and a light text with a dark drop shadow for guest windows
183   // which are themed with a dark background.
184   // TODO(noms): Figure out something similar for themed windows, if possible.
185   base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
186   [shadow setShadowOffset:NSMakeSize(0, -1)];
187   [shadow setShadowBlurRadius:0];
189   NSColor* foregroundColor;
190   if (browser_->profile()->IsGuestSession()) {
191     foregroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.9];
192     [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.4]];
193   } else if (!isThemedWindow_) {
194     foregroundColor = [NSColor blackColor];
195     [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.7]];
196   } else {
197     foregroundColor = [NSColor blackColor];
198     [shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.4]];
199   }
201   base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
202       [[NSMutableParagraphStyle alloc] init]);
203   [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
204   [paragraphStyle setAlignment:NSLeftTextAlignment];
206   NSString* buttonTitle = base::SysUTF16ToNSString(
207       profiles::GetAvatarNameForProfile(browser_->profile()));
209   base::scoped_nsobject<NSAttributedString> attributedTitle(
210       [[NSAttributedString alloc]
211           initWithString:buttonTitle
212               attributes:@{ NSShadowAttributeName : shadow.get(),
213                             NSForegroundColorAttributeName : foregroundColor,
214                             NSParagraphStyleAttributeName : paragraphStyle }]);
215   [button_ setAttributedTitle:attributedTitle];
216   [button_ sizeToFit];
218   // Truncate the title if needed.
219   if (NSWidth([button_ bounds]) > kMaxButtonWidth)
220     [button_ setFrameSize:NSMakeSize(kMaxButtonWidth, kButtonHeight)];
222   if (layoutParent) {
223     // Because the width of the button might have changed, the parent browser
224     // frame needs to recalculate the button bounds and redraw it.
225     [[BrowserWindowController
226         browserWindowControllerForWindow:browser_->window()->GetNativeWindow()]
227         layoutSubviews];
228   }
231 @end