Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / extensions / extension_toolbar_icon_surfacing_bubble_mac.mm
blob0151fe8e24131d162c641a4f06d14f30eed1df97
1 // Copyright 2015 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/extensions/extension_toolbar_icon_surfacing_bubble_mac.h"
7 #include "base/mac/foundation_util.h"
8 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
9 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
10 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
11 #include "grit/chromium_strings.h"
12 #include "grit/generated_resources.h"
13 #include "skia/ext/skia_utils_mac.h"
14 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
15 #include "third_party/skia/include/core/SkColor.h"
16 #import "ui/base/cocoa/hover_button.h"
17 #import "ui/base/cocoa/window_size_constants.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/native_theme/native_theme.h"
21 @interface ExtensionToolbarIconSurfacingBubbleMac ()
23 // Handles the notification that the window will close.
24 - (void)windowWillClose:(NSNotification*)notification;
26 // Creates and returns an NSAttributed string with the specified size and
27 // alignment.
28 - (NSAttributedString*)attributedStringWithString:(int)stringId
29                                          fontSize:(CGFloat)fontSize
30                                         alignment:(NSTextAlignment)alignment;
32 // Creates an NSTextField with the given string, and adds it to the window.
33 - (NSTextField*)addTextFieldWithString:(NSAttributedString*)attributedString;
35 // Initializes the bubble's content.
36 - (void)layout;
38 // Handles the "ok" button being clicked.
39 - (void)onButtonClicked:(id)sender;
41 @end
43 @interface ExtensionToolbarIconSurfacingBubbleButton : HoverButton
44 // Draws with a blue background and white text.
45 - (void)drawRect:(NSRect)rect;
46 @end
48 @implementation ExtensionToolbarIconSurfacingBubbleMac
50 - (id)initWithParentWindow:(NSWindow*)parentWindow
51                anchorPoint:(NSPoint)anchorPoint
52                   delegate:(ToolbarActionsBarBubbleDelegate*)delegate {
53   base::scoped_nsobject<InfoBubbleWindow> window(
54       [[InfoBubbleWindow alloc]
55           initWithContentRect:ui::kWindowSizeDeterminedLater
56                     styleMask:NSBorderlessWindowMask
57                       backing:NSBackingStoreBuffered
58                         defer:NO]);
59   if ((self = [super initWithWindow:window
60                        parentWindow:parentWindow
61                          anchoredAt:anchorPoint])) {
62     delegate_ = delegate;
63     acknowledged_ = NO;
64     [window setCanBecomeKeyWindow:NO];
66     ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
67     [[self bubble] setAlignment:info_bubble::kAlignRightEdgeToAnchorEdge];
68     [[self bubble] setArrowLocation:info_bubble::kNoArrow];
69     [[self bubble] setBackgroundColor:
70         gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
71             ui::NativeTheme::kColorId_DialogBackground))];
73     [self layout];
75     delegate_->OnToolbarActionsBarBubbleShown();
76   }
77   return self;
80 // Private /////////////////////////////////////////////////////////////////////
82 - (void)windowWillClose:(NSNotification*)notification {
83   if (!acknowledged_) {
84     delegate_->OnToolbarActionsBarBubbleClosed(
85         ToolbarActionsBarBubbleDelegate::DISMISSED);
86     acknowledged_ = YES;
87   }
88   [super windowWillClose:notification];
91 - (NSAttributedString*)attributedStringWithString:(int)stringId
92                                          fontSize:(CGFloat)fontSize
93                                         alignment:(NSTextAlignment)alignment {
94   NSString* string = l10n_util::GetNSString(stringId);
95   base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
96       [[NSMutableParagraphStyle alloc] init]);
97   [paragraphStyle setAlignment:alignment];
98   NSDictionary* attributes = @{
99     NSFontAttributeName : [NSFont systemFontOfSize:fontSize],
100     NSForegroundColorAttributeName :
101         [NSColor colorWithCalibratedWhite:0.2 alpha:1.0],
102     NSParagraphStyleAttributeName : paragraphStyle.get()
103   };
104   return [[[NSAttributedString alloc] initWithString:string
105                                           attributes:attributes] autorelease];
108 - (NSTextField*)addTextFieldWithString:(NSAttributedString*)attributedString {
109   base::scoped_nsobject<NSTextField> textField(
110       [[NSTextField alloc] initWithFrame:NSZeroRect]);
111   [textField setEditable:NO];
112   [textField setBordered:NO];
113   [textField setDrawsBackground:NO];
114   [textField setAttributedStringValue:attributedString];
115   [[[self window] contentView] addSubview:textField];
116   return textField.autorelease();
119 - (void)layout {
120   // We first construct the different pieces of the bubble (the heading, the
121   // content, and the button), and size them appropriately.
122   NSAttributedString* headingString =
123       [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_HEADING
124                               fontSize:13.0
125                              alignment:NSLeftTextAlignment];
126   NSTextField* heading = [self addTextFieldWithString:headingString];
127   [heading sizeToFit];
128   NSSize headingSize = [heading frame].size;
130   NSAttributedString* contentString =
131       [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_CONTENT
132                               fontSize:12.0
133                              alignment:NSLeftTextAlignment];
134   NSTextField* content = [self addTextFieldWithString:contentString];
135   [content setFrame:NSMakeRect(0, 0, headingSize.width, 0)];
136   // The content should have the same (max) width as the heading, which means
137   // the text will most likely wrap.
138   NSSize contentSize = NSMakeSize(headingSize.width,
139                                   [GTMUILocalizerAndLayoutTweaker
140                                        sizeToFitFixedWidthTextField:content]);
142   NSButton* button = [[ExtensionToolbarIconSurfacingBubbleButton alloc]
143                          initWithFrame:NSZeroRect];
144   NSAttributedString* buttonString =
145       [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_OK
146                               fontSize:13.0
147                              alignment:NSCenterTextAlignment];
148   [button setAttributedTitle:buttonString];
149   [[button cell] setBordered:NO];
150   [button setTarget:self];
151   [button setAction:@selector(onButtonClicked:)];
152   [[[self window] contentView] addSubview:button];
153   [button sizeToFit];
154   // The button's size will only account for the text by default, so pad it a
155   // bit to make it look good.
156   NSSize buttonSize = NSMakeSize(NSWidth([button frame]) + 40.0,
157                                  NSHeight([button frame]) + 20.0);
159   const CGFloat kHorizontalPadding = 15.0;
160   const CGFloat kVerticalPadding = 10.0;
162   // Next, we set frame for all the different pieces of the bubble, from bottom
163   // to top.
164   CGFloat windowWidth = headingSize.width + kHorizontalPadding * 2;
166   CGFloat currentHeight = 0;
167   [button setFrame:NSMakeRect(windowWidth - buttonSize.width,
168                               currentHeight,
169                               buttonSize.width,
170                               buttonSize.height)];
171   currentHeight += buttonSize.height + kVerticalPadding;
172   [content setFrame:NSMakeRect(kHorizontalPadding,
173                                currentHeight,
174                                contentSize.width,
175                                contentSize.height)];
176   currentHeight += contentSize.height + kVerticalPadding;
177   [heading setFrame:NSMakeRect(kHorizontalPadding,
178                                currentHeight,
179                                headingSize.width,
180                                headingSize.height)];
182   // Update window frame.
183   NSRect windowFrame = [[self window] frame];
184   NSSize windowSize =
185       NSMakeSize(windowWidth,
186                  currentHeight + headingSize.height + kVerticalPadding);
187   // We need to convert the size to be in the window's coordinate system. Since
188   // all we're doing is converting a size, and all views within a window share
189   // the same size metrics, it's okay that the size calculation came from
190   // multiple different views. Pick a view to convert it.
191   windowSize = [heading convertSize:windowSize toView:nil];
192   windowFrame.size = windowSize;
193   [[self window] setFrame:windowFrame display:YES];
196 - (void)onButtonClicked:(id)sender {
197   if (!acknowledged_) {
198     delegate_->OnToolbarActionsBarBubbleClosed(
199         ToolbarActionsBarBubbleDelegate::ACKNOWLEDGED);
200     acknowledged_ = YES;
201     [self close];
202   }
205 @end
207 @implementation ExtensionToolbarIconSurfacingBubbleButton
209 - (void)drawRect:(NSRect)rect {
210   SkColor buttonColor = SkColorSetRGB(66, 133, 244);
211   SkColor textColor = [self hoverState] == kHoverStateNone ?
212       SkColorSetARGB(230, 255, 255, 255) : SK_ColorWHITE;
213   NSRect bounds = [self bounds];
214   NSAttributedString* title = [self attributedTitle];
216   [gfx::SkColorToCalibratedNSColor(buttonColor) set];
217   NSRectFillUsingOperation(bounds, NSCompositeSourceOver);
219   base::scoped_nsobject<NSMutableAttributedString> selectedTitle(
220       [[NSMutableAttributedString alloc] initWithAttributedString:title]);
221   NSColor* selectedTitleColor =
222       gfx::SkColorToCalibratedNSColor(textColor);
223   [selectedTitle addAttribute:NSForegroundColorAttributeName
224                         value:selectedTitleColor
225                         range:NSMakeRange(0, [title length])];
227   [[self cell] drawTitle:selectedTitle.get()
228                withFrame:bounds
229                   inView:self];
232 @end