OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/autofill/autofill_popup_view_cocoa.h" | 5 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
9 #include "chrome/browser/ui/autofill/autofill_popup_controller.h" | 9 #include "chrome/browser/ui/autofill/autofill_popup_controller.h" |
10 #include "chrome/browser/ui/autofill/popup_constants.h" | 10 #include "chrome/browser/ui/autofill/popup_constants.h" |
11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h" | 11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h" |
12 #include "components/autofill/core/browser/popup_item_ids.h" | 12 #include "components/autofill/core/browser/popup_item_ids.h" |
13 #include "grit/ui_resources.h" | 13 #include "grit/ui_resources.h" |
| 14 #include "ui/base/cocoa/window_size_constants.h" |
14 #include "ui/base/resource/resource_bundle.h" | 15 #include "ui/base/resource/resource_bundle.h" |
15 #include "ui/gfx/font_list.h" | 16 #include "ui/gfx/font_list.h" |
16 #include "ui/gfx/image/image.h" | 17 #include "ui/gfx/image/image.h" |
17 #include "ui/gfx/point.h" | 18 #include "ui/gfx/point.h" |
18 #include "ui/gfx/rect.h" | 19 #include "ui/gfx/rect.h" |
19 | 20 |
20 using autofill::AutofillPopupView; | 21 using autofill::AutofillPopupView; |
21 | 22 |
22 namespace { | 23 @interface AutofillPopupViewCocoa () |
23 | |
24 NSColor* BackgroundColor() { | |
25 return [NSColor whiteColor]; | |
26 } | |
27 | |
28 // The color of the border around the popup. | |
29 NSColor* BorderColor() { | |
30 return [NSColor colorForControlTint:[NSColor currentControlTint]]; | |
31 } | |
32 | |
33 NSColor* SeparatorColor() { | |
34 return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; | |
35 } | |
36 | |
37 NSColor* HighlightColor() { | |
38 return [NSColor selectedControlColor]; | |
39 } | |
40 | |
41 NSColor* NameColor() { | |
42 return [NSColor blackColor]; | |
43 } | |
44 | |
45 NSColor* WarningColor() { | |
46 return [NSColor grayColor]; | |
47 } | |
48 | |
49 NSColor* SubtextColor() { | |
50 return [NSColor grayColor]; | |
51 } | |
52 | |
53 } // namespace | |
54 | 24 |
55 #pragma mark - | 25 #pragma mark - |
56 #pragma mark Private methods | 26 #pragma mark Private methods |
57 | 27 |
58 @interface AutofillPopupViewCocoa () | |
59 | |
60 // Draws a thin separator in the popup UI. | |
61 - (void)drawSeparatorWithBounds:(NSRect)bounds; | |
62 | |
63 // Draws an Autofill suggestion in the given |bounds|, labeled with the given | 28 // Draws an Autofill suggestion in the given |bounds|, labeled with the given |
64 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn | 29 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn |
65 // with a highlight. |index| determines the font to use, as well as the icon, | 30 // with a highlight. |index| determines the font to use, as well as the icon, |
66 // if the row requires it -- such as for credit cards. | 31 // if the row requires it -- such as for credit cards. |
67 - (void)drawSuggestionWithName:(NSString*)name | 32 - (void)drawSuggestionWithName:(NSString*)name |
68 subtext:(NSString*)subtext | 33 subtext:(NSString*)subtext |
69 index:(size_t)index | 34 index:(size_t)index |
70 bounds:(NSRect)bounds | 35 bounds:(NSRect)bounds |
71 selected:(BOOL)isSelected; | 36 selected:(BOOL)isSelected; |
72 | 37 |
73 // Returns the icon for the row with the given |index|, or |nil| if there is | 38 // Returns the icon for the row with the given |index|, or |nil| if there is |
74 // none. | 39 // none. |
75 - (NSImage*)iconAtIndex:(size_t)index; | 40 - (NSImage*)iconAtIndex:(size_t)index; |
76 | 41 |
77 @end | 42 @end |
78 | 43 |
79 @implementation AutofillPopupViewCocoa | 44 @implementation AutofillPopupViewCocoa |
80 | 45 |
81 #pragma mark - | 46 #pragma mark - |
82 #pragma mark Initialisers | 47 #pragma mark Initialisers |
83 | 48 |
84 - (id)initWithFrame:(NSRect)frame { | 49 - (id)initWithFrame:(NSRect)frame { |
85 NOTREACHED(); | 50 NOTREACHED(); |
86 return [self initWithController:NULL frame:frame]; | 51 return [self initWithController:NULL frame:frame]; |
87 } | 52 } |
88 | 53 |
89 - (id)initWithController:(autofill::AutofillPopupController*)controller | 54 - (id)initWithController:(autofill::AutofillPopupController*)controller |
90 frame:(NSRect)frame { | 55 frame:(NSRect)frame { |
91 self = [super initWithFrame:frame]; | 56 self = [super initWithDelegate:controller frame:frame]; |
92 if (self) | 57 if (self) |
93 controller_ = controller; | 58 controller_ = controller; |
94 | 59 |
95 return self; | 60 return self; |
96 } | 61 } |
97 | 62 |
98 #pragma mark - | 63 #pragma mark - |
99 #pragma mark NSView implementation: | 64 #pragma mark NSView implementation: |
100 | 65 |
101 // A slight optimization for drawing: | |
102 // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa
ViewsGuide/Optimizing/Optimizing.html | |
103 - (BOOL)isOpaque { | |
104 return YES; | |
105 } | |
106 | |
107 - (BOOL)isFlipped { | |
108 // Flipped so that it's easier to share controller logic with other OSes. | |
109 return YES; | |
110 } | |
111 | |
112 - (void)drawRect:(NSRect)dirtyRect { | 66 - (void)drawRect:(NSRect)dirtyRect { |
113 // If the view is in the process of being destroyed, don't bother drawing. | 67 // If the view is in the process of being destroyed, don't bother drawing. |
114 if (!controller_) | 68 if (!controller_) |
115 return; | 69 return; |
116 | 70 |
117 // Draw the popup's background and border. | 71 [self drawBackgroundAndBorder]; |
118 // The inset is needed since the border is centered on the |path|. | |
119 // TODO(isherman): We should consider using asset-based drawing for the | |
120 // border, creating simple bitmaps for the view's border and background, and | |
121 // drawing them using NSDrawNinePartImage(). | |
122 CGFloat inset = autofill::kPopupBorderThickness / 2.0; | |
123 NSRect borderRect = NSInsetRect([self bounds], inset, inset); | |
124 NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; | |
125 [BackgroundColor() setFill]; | |
126 [path fill]; | |
127 [path setLineWidth:autofill::kPopupBorderThickness]; | |
128 [BorderColor() setStroke]; | |
129 [path stroke]; | |
130 | 72 |
131 for (size_t i = 0; i < controller_->names().size(); ++i) { | 73 for (size_t i = 0; i < controller_->names().size(); ++i) { |
132 // Skip rows outside of the dirty rect. | 74 // Skip rows outside of the dirty rect. |
133 NSRect rowBounds = | 75 NSRect rowBounds = |
134 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect()); | 76 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect()); |
135 if (!NSIntersectsRect(rowBounds, dirtyRect)) | 77 if (!NSIntersectsRect(rowBounds, dirtyRect)) |
136 continue; | 78 continue; |
137 | 79 |
138 if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { | 80 if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { |
139 [self drawSeparatorWithBounds:rowBounds]; | 81 [self drawSeparatorWithBounds:rowBounds]; |
140 } else { | 82 } else { |
141 NSString* name = SysUTF16ToNSString(controller_->names()[i]); | 83 NSString* name = SysUTF16ToNSString(controller_->names()[i]); |
142 NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]); | 84 NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]); |
143 BOOL isSelected = static_cast<int>(i) == controller_->selected_line(); | 85 BOOL isSelected = static_cast<int>(i) == controller_->selected_line(); |
144 [self drawSuggestionWithName:name | 86 [self drawSuggestionWithName:name |
145 subtext:subtext | 87 subtext:subtext |
146 index:i | 88 index:i |
147 bounds:rowBounds | 89 bounds:rowBounds |
148 selected:isSelected]; | 90 selected:isSelected]; |
149 } | 91 } |
150 } | 92 } |
151 } | 93 } |
152 | 94 |
153 - (void)mouseUp:(NSEvent*)theEvent { | |
154 // If the view is in the process of being destroyed, abort. | |
155 if (!controller_) | |
156 return; | |
157 | |
158 NSPoint location = [self convertPoint:[theEvent locationInWindow] | |
159 fromView:nil]; | |
160 | |
161 if (NSPointInRect(location, [self bounds])) { | |
162 controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); | |
163 controller_->AcceptSelectedLine(); | |
164 } | |
165 } | |
166 | |
167 - (void)mouseMoved:(NSEvent*)theEvent { | |
168 // If the view is in the process of being destroyed, abort. | |
169 if (!controller_) | |
170 return; | |
171 | |
172 NSPoint location = [self convertPoint:[theEvent locationInWindow] | |
173 fromView:nil]; | |
174 | |
175 controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); | |
176 } | |
177 | |
178 - (void)mouseDragged:(NSEvent*)theEvent { | |
179 [self mouseMoved:theEvent]; | |
180 } | |
181 | |
182 - (void)mouseExited:(NSEvent*)theEvent { | |
183 // If the view is in the process of being destroyed, abort. | |
184 if (!controller_) | |
185 return; | |
186 | |
187 controller_->SelectionCleared(); | |
188 } | |
189 | |
190 #pragma mark - | 95 #pragma mark - |
191 #pragma mark Public API: | 96 #pragma mark Public API: |
192 | 97 |
193 - (void)controllerDestroyed { | 98 - (void)controllerDestroyed { |
194 // Since the |controller_| either already has been destroyed or is about to | 99 // Since the |controller_| either already has been destroyed or is about to |
195 // be, about the only thing we can safely do with it is to null it out. | 100 // be, about the only thing we can safely do with it is to null it out. |
196 controller_ = NULL; | 101 controller_ = NULL; |
| 102 [super delegateDestroyed]; |
| 103 } |
| 104 |
| 105 - (void)invalidateRow:(size_t)row { |
| 106 NSRect dirty_rect = |
| 107 NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect()); |
| 108 [self setNeedsDisplayInRect:dirty_rect]; |
197 } | 109 } |
198 | 110 |
199 #pragma mark - | 111 #pragma mark - |
200 #pragma mark Private API: | 112 #pragma mark Private API: |
201 | 113 |
202 - (void)drawSeparatorWithBounds:(NSRect)bounds { | |
203 [SeparatorColor() set]; | |
204 [NSBezierPath fillRect:bounds]; | |
205 } | |
206 | |
207 - (void)drawSuggestionWithName:(NSString*)name | 114 - (void)drawSuggestionWithName:(NSString*)name |
208 subtext:(NSString*)subtext | 115 subtext:(NSString*)subtext |
209 index:(size_t)index | 116 index:(size_t)index |
210 bounds:(NSRect)bounds | 117 bounds:(NSRect)bounds |
211 selected:(BOOL)isSelected { | 118 selected:(BOOL)isSelected { |
212 // If this row is selected, highlight it. | 119 // If this row is selected, highlight it. |
213 if (isSelected) { | 120 if (isSelected) { |
214 [HighlightColor() set]; | 121 [[self highlightColor] set]; |
215 [NSBezierPath fillRect:bounds]; | 122 [NSBezierPath fillRect:bounds]; |
216 } | 123 } |
217 | 124 |
218 BOOL isRTL = controller_->IsRTL(); | 125 BOOL isRTL = controller_->IsRTL(); |
219 | 126 |
220 NSColor* nameColor = | 127 NSColor* nameColor = |
221 controller_->IsWarning(index) ? WarningColor() : NameColor(); | 128 controller_->IsWarning(index) ? [self warningColor] : [self nameColor]; |
222 NSDictionary* nameAttributes = | 129 NSDictionary* nameAttributes = |
223 [NSDictionary dictionaryWithObjectsAndKeys: | 130 [NSDictionary dictionaryWithObjectsAndKeys: |
224 controller_->GetNameFontListForRow(index).GetPrimaryFont(). | 131 controller_->GetNameFontListForRow(index).GetPrimaryFont(). |
225 GetNativeFont(), | 132 GetNativeFont(), |
226 NSFontAttributeName, nameColor, NSForegroundColorAttributeName, | 133 NSFontAttributeName, nameColor, NSForegroundColorAttributeName, |
227 nil]; | 134 nil]; |
228 NSSize nameSize = [name sizeWithAttributes:nameAttributes]; | 135 NSSize nameSize = [name sizeWithAttributes:nameAttributes]; |
229 CGFloat x = bounds.origin.x + | 136 CGFloat x = bounds.origin.x + |
230 (isRTL ? | 137 (isRTL ? |
231 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : | 138 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : |
(...skipping 23 matching lines...) Expand all Loading... |
255 | 162 |
256 x += isRTL ? | 163 x += isRTL ? |
257 iconSize.width + AutofillPopupView::kIconPadding : | 164 iconSize.width + AutofillPopupView::kIconPadding : |
258 -AutofillPopupView::kIconPadding; | 165 -AutofillPopupView::kIconPadding; |
259 } | 166 } |
260 | 167 |
261 // Draw the subtext. | 168 // Draw the subtext. |
262 NSDictionary* subtextAttributes = | 169 NSDictionary* subtextAttributes = |
263 [NSDictionary dictionaryWithObjectsAndKeys: | 170 [NSDictionary dictionaryWithObjectsAndKeys: |
264 controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), | 171 controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), |
265 NSFontAttributeName, SubtextColor(), NSForegroundColorAttributeName, | 172 NSFontAttributeName, |
| 173 [self subtextColor], |
| 174 NSForegroundColorAttributeName, |
266 nil]; | 175 nil]; |
267 NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; | 176 NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; |
268 x += isRTL ? 0 : -subtextSize.width; | 177 x += isRTL ? 0 : -subtextSize.width; |
269 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; | 178 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; |
270 | 179 |
271 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; | 180 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; |
272 } | 181 } |
273 | 182 |
274 - (NSImage*)iconAtIndex:(size_t)index { | 183 - (NSImage*)iconAtIndex:(size_t)index { |
275 if (controller_->icons()[index].empty()) | 184 if (controller_->icons()[index].empty()) |
276 return nil; | 185 return nil; |
277 | 186 |
278 int iconId = controller_->GetIconResourceID(controller_->icons()[index]); | 187 int iconId = controller_->GetIconResourceID(controller_->icons()[index]); |
279 DCHECK_NE(-1, iconId); | 188 DCHECK_NE(-1, iconId); |
280 | 189 |
281 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 190 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
282 return rb.GetNativeImageNamed(iconId).ToNSImage(); | 191 return rb.GetNativeImageNamed(iconId).ToNSImage(); |
283 } | 192 } |
284 | 193 |
285 @end | 194 @end |
OLD | NEW |