OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #import "chrome/browser/ui/cocoa/extensions/extension_toolbar_icon_surfacing_bub
ble_mac.h" | |
6 | |
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/GTMUILocalizerAndLayoutTw
eaker.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" | |
20 | |
21 @interface ExtensionToolbarIconSurfacingBubbleMac () | |
22 | |
23 // Handles the notification that the window will close. | |
24 - (void)windowWillClose:(NSNotification*)notification; | |
25 | |
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; | |
31 | |
32 // Creates an NSTextField with the given string, and adds it to the window. | |
33 - (NSTextField*)addTextFieldWithString:(NSAttributedString*)attributedString; | |
34 | |
35 // Initializes the bubble's content. | |
36 - (void)layout; | |
37 | |
38 // Handles the "ok" button being clicked. | |
39 - (void)onButtonClicked:(id)sender; | |
40 | |
41 @end | |
42 | |
43 @interface ExtensionToolbarIconSurfacingBubbleButton : HoverButton | |
44 // Draws with a blue background and white text. | |
45 - (void)drawRect:(NSRect)rect; | |
46 @end | |
47 | |
48 @implementation ExtensionToolbarIconSurfacingBubbleMac | |
49 | |
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]; | |
65 | |
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))]; | |
72 | |
73 [self layout]; | |
74 | |
75 delegate_->OnToolbarActionsBarBubbleShown(); | |
76 } | |
77 return self; | |
78 } | |
79 | |
80 // Private ///////////////////////////////////////////////////////////////////// | |
81 | |
82 - (void)windowWillClose:(NSNotification*)notification { | |
83 if (!acknowledged_) { | |
84 delegate_->OnToolbarActionsBarBubbleClosed( | |
85 ToolbarActionsBarBubbleDelegate::DISMISSED); | |
86 acknowledged_ = YES; | |
87 } | |
88 [super windowWillClose:notification]; | |
89 } | |
90 | |
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]; | |
106 } | |
107 | |
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(); | |
117 } | |
118 | |
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; | |
129 | |
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]); | |
141 | |
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); | |
158 | |
159 const CGFloat kHorizontalPadding = 15.0; | |
160 const CGFloat kVerticalPadding = 10.0; | |
161 | |
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; | |
165 | |
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)]; | |
181 | |
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]; | |
194 } | |
195 | |
196 - (void)onButtonClicked:(id)sender { | |
197 if (!acknowledged_) { | |
198 delegate_->OnToolbarActionsBarBubbleClosed( | |
199 ToolbarActionsBarBubbleDelegate::ACKNOWLEDGED); | |
200 acknowledged_ = YES; | |
201 [self close]; | |
202 } | |
203 } | |
204 | |
205 @end | |
206 | |
207 @implementation ExtensionToolbarIconSurfacingBubbleButton | |
208 | |
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]; | |
215 | |
216 [gfx::SkColorToCalibratedNSColor(buttonColor) set]; | |
217 NSRectFillUsingOperation(bounds, NSCompositeSourceOver); | |
218 | |
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])]; | |
226 | |
227 [[self cell] drawTitle:selectedTitle.get() | |
228 withFrame:bounds | |
229 inView:self]; | |
230 } | |
231 | |
232 @end | |
OLD | NEW |