Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm

Issue 11740033: [Autofill] Add Mac implementation for the in-browser process popup view. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename _mac to _bridge, added TODOs for cleanup per Nico's comments. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h"
6
7 #include "base/i18n/rtl.h"
8 #include "base/logging.h"
9 #include "base/sys_string_conversions.h"
10 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h"
12 #include "grit/ui_resources.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/image/image.h"
16 #include "ui/gfx/point.h"
17 #include "ui/gfx/rect.h"
18
19 namespace {
20
21 NSColor* BorderColor() {
22 // TODO(isherman): This color does not match the other platforms, but it
23 // matches what the existing UI on Mac has as the color. The other platforms
24 // have a strange color: the RGB values are almost, but not quite, identical
25 // to each other.
26 // TODO(isherman): Maybe use a system color for this?
27 return [NSColor colorWithCalibratedRed:127 / 255.0
28 green:157 / 255.0
29 blue:185 / 255.0
30 alpha:1.0];
31 }
32
33 NSColor* SeparatorColor() {
34 return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1];
35 }
36
37 NSColor* HighlightColor() {
38 return [NSColor colorWithCalibratedWhite:205 / 255.0 alpha:1];
39 }
40
41 } // anonymous namespace
42
43 #pragma mark -
44 #pragma mark Private methods
45
46 @interface AutofillPopupViewCocoa ()
47
48 // Draws a thin separator in the popup UI.
49 - (void)drawSeparatorWithBounds:(NSRect)bounds;
50
51 // Draws an Autofill suggestion in the given |bounds|, labeled with the given
52 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn
53 // with a highlight. Some suggestions -- such as for credit cards -- might also
54 // include an |icon| -- e.g. for the card type. Finally, if |canDelete| is
55 // true, a delete icon is also drawn.
56 - (void)drawSuggestionWithName:(NSString*)name
57 subtext:(NSString*)subtext
58 icon:(NSImage*)icon
59 bounds:(NSRect)bounds
60 selected:(BOOL)isSelected
61 canDelete:(BOOL)canDelete;
62
63 // Returns the icon for the row with the given |index|, or |nil| if there is
64 // none.
65 - (NSImage*)iconAtIndex:(size_t)index;
66
67 @end
68
69 @implementation AutofillPopupViewCocoa
70
71 #pragma mark -
72 #pragma mark Initialisers
73
74 - (id)initWithFrame:(NSRect)frame {
75 NOTREACHED();
76 return [self initWithController:NULL frame:frame];
77 }
78
79 - (id)initWithController:(AutofillPopupController*)controller
80 frame:(NSRect)frame {
81 self = [super initWithFrame:frame];
82 if (self)
83 controller_ = controller;
84
85 return self;
86 }
87
88 #pragma mark -
89 #pragma mark NSView implementation:
90
91 // A slight optimization for drawing:
92 // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa ViewsGuide/Optimizing/Optimizing.html
93 - (BOOL)isOpaque {
94 return YES;
95 }
96
97 - (BOOL)isFlipped {
98 // Flipped so that it's easier to share controller logic with other OSes.
99 return YES;
100 }
101
102 - (void)drawRect:(NSRect)dirtyRect {
103 // If the view is in the process of being destroyed, don't bother drawing.
104 if (!controller_)
105 return;
106
107 // TODO(isherman): Is there a better way to leave room for the border?
108 // TODO(isherman): Drawing the border as part of the content view means that
109 // the rest of the content has to be careful not to overlap the border.
110 // Should the border be part of the window instead? If not, should the rest
111 // of the view be a subview? Or should I just draw the window content
112 // carefully?
113 // TODO(isherman): We should consider using asset-based drawing for the
114 // border, creating simple bitmaps for the view's border and background, and
115 // drawing them using NSDrawNinePartImage().
116 NSRect borderRect = NSInsetRect([self bounds], 0.5, 0.5);
117 NSBezierPath* border = [NSBezierPath bezierPathWithRect:borderRect];
118
119 [[NSColor whiteColor] set];
120 [border fill];
121
122 // TODO(isherman): This color does not match the other platforms, but it
123 // matches what the existing UI on Mac has as the color. The other platforms
124 // have a strange color: the RGB values are almost, but not quite, identical
125 // to each other.
126 // TODO(isherman): Maybe use a system color for this?
127 [BorderColor() set];
128 [border stroke];
129
130 for (size_t i = 0; i < controller_->names().size(); ++i) {
131 // Skip rows outside of the dirty rect.
132 NSRect rowBounds =
133 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect());
134 if (!NSIntersectsRect(rowBounds, dirtyRect))
135 continue;
136
137 if (controller_->identifiers()[i] ==
138 WebKit::WebAutofillClient::MenuItemIDSeparator) {
139 [self drawSeparatorWithBounds:rowBounds];
140 } else {
141 NSString* name = SysUTF16ToNSString(controller_->names()[i]);
142 NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]);
143 BOOL isSelected = static_cast<int>(i) == controller_->selected_line();
144 [self drawSuggestionWithName:name
145 subtext:subtext
146 icon:[self iconAtIndex:i]
147 bounds:rowBounds
148 selected:isSelected
149 canDelete:controller_->CanDelete(i)];
150 }
151 }
152 }
153
154 - (void)mouseUp:(NSEvent*)theEvent {
155 // If the view is in the process of being destroyed, abort.
156 if (!controller_)
157 return;
158
159 NSPoint location = [self convertPoint:[theEvent locationInWindow]
160 fromView:nil];
161
162 if (NSPointInRect(location, [self bounds])) {
163 controller_->MouseClicked(static_cast<int>(location.x),
164 static_cast<int>(location.y));
165 }
166 }
167
168 - (void)mouseMoved:(NSEvent*)theEvent {
169 // If the view is in the process of being destroyed, abort.
170 if (!controller_)
171 return;
172
173 NSPoint location = [self convertPoint:[theEvent locationInWindow]
174 fromView:nil];
175
176 controller_->MouseHovered(static_cast<int>(location.x),
177 static_cast<int>(location.y));
178 }
179
180 - (void)mouseDragged:(NSEvent*)theEvent {
181 [self mouseMoved:theEvent];
182 }
183
184 - (void)mouseExited:(NSEvent*)theEvent {
185 // If the view is in the process of being destroyed, abort.
186 if (!controller_)
187 return;
188
189 controller_->MouseExitedPopup();
190 }
191
192 #pragma mark -
193 #pragma mark Public API:
194
195 - (void)controllerDestroyed {
196 // Since the |controller_| either already has been destroyed or is about to
197 // be, about the only thing we can safely do with it is to null it out.
198 controller_ = NULL;
199 }
200
201 #pragma mark -
202 #pragma mark Private API:
203
204 - (void)drawSeparatorWithBounds:(NSRect)bounds {
205 [SeparatorColor() set];
206 [NSBezierPath fillRect:bounds];
207 }
208
209 - (void)drawSuggestionWithName:(NSString*)name
210 subtext:(NSString*)subtext
211 icon:(NSImage*)icon
212 bounds:(NSRect)bounds
213 selected:(BOOL)isSelected
214 canDelete:(BOOL)canDelete {
215 // If this row is selected, highlight it.
216 if (isSelected) {
217 // TODO(isherman): The highlight color should match the system highlight
218 // color. Maybe use controlHighlightColor or selectedTextBackgroundColor
219 // for this?
220 [HighlightColor() set];
221 [NSBezierPath fillRect:bounds];
222 }
223
224 BOOL isRTL = base::i18n::IsRTL();
225
226 // TODO(isherman): Set font, colors, and any other appropriate attributes.
227 NSSize nameSize = [name sizeWithAttributes:nil];
228 CGFloat x = bounds.origin.x +
229 (isRTL ?
230 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width:
231 AutofillPopupView::kEndPadding);
232 CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2;
233
234 [name drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
235
236 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
237
238 // The x-coordinate will be updated as each element is drawn.
239 x = bounds.origin.x +
240 (isRTL ?
241 AutofillPopupView::kEndPadding :
242 bounds.size.width - AutofillPopupView::kEndPadding);
243
244 // Draw the delete icon, if one is needed.
245 if (canDelete) {
246 // TODO(isherman): Refactor the cross-platform code so that the delete icon
247 // is a button implemented as a subview, rather than having all its logic be
248 // custom handled by the controller.
249 // TODO(csharp): Create a custom resource for the delete icon.
250 // http://crbug.com/131801
251 NSImage* deleteIcon;
252 if (isSelected && controller_->delete_icon_hovered())
253 deleteIcon = rb.GetNativeImageNamed(IDR_CLOSE_BAR_H).ToNSImage();
254 else
255 deleteIcon = rb.GetNativeImageNamed(IDR_CLOSE_BAR).ToNSImage();
256
257 NSSize iconSize = [deleteIcon size];
258 x += isRTL ? 0 : -iconSize.width;
259 y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
260 [deleteIcon drawInRect:NSMakeRect(x, y, iconSize.width, iconSize.height)
261 fromRect:NSZeroRect
262 operation:NSCompositeSourceOver
263 fraction:1.0
264 respectFlipped:YES
265 hints:nil];
266
267 x += isRTL ?
268 iconSize.width + AutofillPopupView::kIconPadding :
269 -AutofillPopupView::kIconPadding;
270 }
271
272 // Draw the Autofill icon, if one exists.
273 if (icon) {
274 NSSize iconSize = [icon size];
275 x += isRTL ? 0 : -iconSize.width;
276 y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
277 [icon drawInRect:NSMakeRect(x, y, iconSize.width, iconSize.height)
278 fromRect:NSZeroRect
279 operation:NSCompositeSourceOver
280 fraction:1.0
281 respectFlipped:YES
282 hints:nil];
283
284 x += isRTL ?
285 iconSize.width + AutofillPopupView::kIconPadding :
286 -AutofillPopupView::kIconPadding;
287 }
288
289 // Draw the subtext.
290 NSSize subtextSize = [subtext sizeWithAttributes:nil];
291 x += isRTL ? 0 : -subtextSize.width;
292 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2;
293
294 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
295 }
296
297 - (NSImage*)iconAtIndex:(size_t)index {
298 if (controller_->icons()[index].empty())
299 return nil;
300
301 int iconId = controller_->GetIconResourceID(controller_->icons()[index]);
302 DCHECK_NE(-1, iconId);
303
304 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
305 return rb.GetNativeImageNamed(iconId).ToNSImage();
306 }
307
308 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h ('k') | chrome/chrome_browser_ui.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698