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

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: 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_mac.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 #pragma mark -
20 #pragma mark Private methods
21
22 @interface AutofillPopupViewCocoa ()
23
24 // Draws a thin separator in the popup UI.
25 - (void)drawSeparatorWithBounds:(NSRect)bounds;
26
27 // Draws an Autofill suggestion in the given |bounds|, labeled with the given
28 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn
29 // with a highlight. Some suggestions -- such as for credit cards -- might also
30 // include an |icon| -- e.g. for the card type. Finally, if |canDelete| is
31 // true, a delete icon is also drawn.
32 - (void)drawSuggestionWithName:(NSString*)name
33 subtext:(NSString*)subtext
34 icon:(NSImage*)icon
35 bounds:(NSRect)bounds
36 selected:(BOOL)isSelected
37 canDelete:(BOOL)canDelete;
38
39 // Returns the icon for the row with the given |index|, or |nil| if there is
40 // none.
41 - (NSImage*)iconAtIndex:(int)index;
Scott Hess - ex-Googler 2013/01/05 01:06:49 size_t to match the caller. Or NSUInteger, but I
Ilya Sherman 2013/01/05 03:14:10 Done.
42
43 // Flips the given |point|'s y coordinate to match Chrome's screen coordinate
44 // system.
45 - (gfx::Point)flipNSPointToPoint:(NSPoint)point;
Scott Hess - ex-Googler 2013/01/05 01:06:49 Rather than making explicit conversions, it might
Ilya Sherman 2013/01/05 03:14:10 I thought about that, but I think isFlipped just f
Scott Hess - ex-Googler 2013/01/09 21:36:17 If it returned YES to -isFlipped, then -convertPoi
Ilya Sherman 2013/01/10 02:21:21 You're right, I was misunderstanding what space ex
46
47 @end
48
49 @implementation AutofillPopupViewCocoa
50
51 #pragma mark -
52 #pragma mark Initialisers
53
54 - (id)initWithFrame:(NSRect)frame {
55 NOTREACHED();
56 return [self initWithController:NULL frame:frame];
57 }
58
59 - (id)initWithController:(AutofillPopupController*)controller
60 frame:(NSRect)frame {
61 self = [super initWithFrame:frame];
62 if (self)
63 controller_ = controller;
64
65 return self;
66 }
67
68 #pragma mark -
69 #pragma mark NSView implementation:
70
71 // A slight optimization for drawing:
72 // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa ViewsGuide/Optimizing/Optimizing.html
73 - (BOOL)isOpaque {
74 return YES;
75 }
76
77 - (void)drawRect:(NSRect)dirtyRect {
78 // If the view is in the process of being destroyed, don't bother drawing.
79 if (!controller_)
80 return;
81
82 // TODO(isherman): Is there a better way to leave room for the border?
83 // TODO(isherman): Drawing the border as part of the content view means that
84 // the rest of the content has to be careful not to overlap the border.
85 // Should the border be part of the window instead? If not, should the rest
86 // of the view be a subview? Or should I just draw the window content
87 // carefully?
88 NSRect borderRect = NSInsetRect([self bounds], 0.5, 0.5);
89 NSBezierPath* border = [NSBezierPath bezierPathWithRect:borderRect];
90
91 // TODO(isherman): Should I just make the window have a white background
92 // instead? Is there any reason to prefer clearColor for the window
93 // background color? I ask because most of the Chromium code that I've found
94 // sets clearColor for the window's background color...
Scott Hess - ex-Googler 2013/01/05 01:06:49 -clearColor will be transparent, I think.
Ilya Sherman 2013/01/05 03:14:10 I figured out why the view needs to set a backgrou
95 // TODO(isherman): Should I be calling [NSColor
96 // colorWithCalibratedWhite:alpha:] instead?
Scott Hess - ex-Googler 2013/01/05 01:06:49 I would prefer -whiteColor or comparable if it wor
Ilya Sherman 2013/01/05 03:14:10 Done.
97 [[NSColor whiteColor] set];
98 [border fill];
99
100 // TODO(isherman): Device or calibrated? Is there shared code I should use to
101 // simplify this? Is there a way to extract the constants into a named color
102 // constant local to this file?
103 // TODO(isherman): This color does not match the other platforms, but it
104 // matches what the existing UI on Mac has as the color. The other platforms
105 // have a strange color: the RGB values are almost, but not quite, identical
106 // to each other.
Scott Hess - ex-Googler 2013/01/05 01:06:49 What existing UI do you mean in this? Can you ste
Ilya Sherman 2013/01/05 03:14:10 Sorry, I should have provided more context for thi
107 [[NSColor colorWithDeviceRed:127/255.0
108 green:157/255.0
109 blue:185/255.0
110 alpha:1.0] set];
111 [border stroke];
112
113 for (size_t i = 0; i < controller_->names().size(); ++i) {
114 // Skip rows outside of the dirty rect.
115 NSRect rowBounds = [self flipRectToNSRect:controller_->GetRowBounds(i)];
116 if (!NSIntersectsRect(rowBounds, dirtyRect))
117 continue;
118
119 if (controller_->identifiers()[i] ==
120 WebKit::WebAutofillClient::MenuItemIDSeparator) {
121 [self drawSeparatorWithBounds:rowBounds];
122 } else {
123 NSString* name = SysUTF16ToNSString(controller_->names()[i]);
124 NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]);
125 BOOL isSelected = static_cast<int>(i) == controller_->selected_line();
126 [self drawSuggestionWithName:name
127 subtext:subtext
128 icon:[self iconAtIndex:i]
129 bounds:rowBounds
130 selected:isSelected
131 canDelete:controller_->CanDelete(i)];
132 }
133 }
134 }
135
136 #pragma mark -
137 #pragma mark BaseView implementation:
138
139 - (void)mouseEvent:(NSEvent *)theEvent {
140 // If the view is in the process of being destroyed, abort.
141 if (!controller_)
142 return;
143
144 NSEventType event_type = [theEvent type];
145 NSPoint location = [self convertPoint:[theEvent locationInWindow]
146 fromView:nil];
147
148 // Convert to Chrome's screen coordinates.
149 gfx::Point screen_location = [self flipNSPointToPoint:location];
150
151 if (event_type == NSLeftMouseUp && NSPointInRect(location, [self bounds]))
152 controller_->MouseClicked(screen_location.x(), screen_location.y());
153 else if (event_type == NSMouseExited)
154 controller_->MouseExitedPopup();
155 else if (event_type == NSMouseMoved || event_type == NSLeftMouseDragged)
156 controller_->MouseHovered(screen_location.x(), screen_location.y());
157 }
158
159 #pragma mark -
160 #pragma mark Public API:
161
162 - (void)controllerDestroyed {
163 controller_ = NULL;
164 }
165
166 #pragma mark -
167 #pragma mark Private API:
168
169 - (void)drawSeparatorWithBounds:(NSRect)bounds {
170 // TODO(isherman): Device or calibrated? Is there shared code I should use to
171 // simplify this?
172 [[NSColor colorWithDeviceRed:220/255.0
173 green:220/255.0
174 blue:220/255.0
Scott Hess - ex-Googler 2013/01/05 01:06:49 If they're all the same, -colorWithDeviceWhite: sh
Ilya Sherman 2013/01/05 03:14:10 Done.
175 alpha:1] set];
176 [NSBezierPath fillRect:bounds];
177 }
178
179 - (void)drawSuggestionWithName:(NSString*)name
180 subtext:(NSString*)subtext
181 icon:(NSImage*)icon
182 bounds:(NSRect)bounds
183 selected:(BOOL)isSelected
184 canDelete:(BOOL)canDelete {
185 // If this row is selected, highlight it.
186 if (isSelected) {
187 // TODO(isherman): The highlight color should match the system highlight
188 // color.
Scott Hess - ex-Googler 2013/01/05 01:06:49 What about one of +controlHighlighColor or +contro
Ilya Sherman 2013/01/05 03:14:10 The docs at [1] say not to use the "control" ones:
Scott Hess - ex-Googler 2013/01/09 21:36:17 In that case, I'll just quibble with the oddity of
Ilya Sherman 2013/01/10 02:21:21 Done.
189 [[NSColor colorWithDeviceRed:(0xCD / 255.0)
190 green:(0xCD / 255.0)
191 blue:(0xCD / 255.0)
192 alpha:1] set];
193 [NSBezierPath fillRect:bounds];
194 }
195
196 BOOL isRTL = base::i18n::IsRTL();
197
198 // TODO(isherman): Set font, colors, and any other appropriate attributes.
Ilya Sherman 2013/01/04 01:24:29 This is the only TODO(isherman) line in this file
199 NSSize nameSize = [name sizeWithAttributes:nil];
200 CGFloat x = bounds.origin.x +
201 (isRTL ?
202 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width:
203 AutofillPopupView::kEndPadding);
204 CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2;
205
206 [name drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
207
208 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
209
210 // The x-coordinate will be updated as each element is drawn.
211 x = bounds.origin.x +
212 (isRTL ?
213 AutofillPopupView::kEndPadding :
214 bounds.size.width - AutofillPopupView::kEndPadding);
215
216 // Draw the delete icon, if one is needed.
217 if (canDelete) {
218 // TODO(csharp): Create a custom resource for the delete icon.
219 // http://crbug.com/131801
220 NSImage* deleteIcon;
221 if (isSelected && controller_->delete_icon_hovered())
222 deleteIcon = rb.GetImageNamed(IDR_CLOSE_BAR_H).ToNSImage();
223 else
224 deleteIcon = rb.GetImageNamed(IDR_CLOSE_BAR).ToNSImage();
225
226 NSSize iconSize = [deleteIcon size];
227 x += isRTL ? 0 : -iconSize.width;
228 y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
229 [deleteIcon drawAtPoint:NSMakePoint(x, y)
230 fromRect:NSZeroRect
231 operation:NSCompositeSourceOver
232 fraction:1.0];
233
234 x += isRTL ?
235 iconSize.width + AutofillPopupView::kIconPadding :
236 -AutofillPopupView::kIconPadding;
237 }
238
239 // Draw the Autofill icon, if one exists.
240 if (icon) {
241 NSSize iconSize = [icon size];
242 x += isRTL ? 0 : -iconSize.width;
243 y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
Scott Hess - ex-Googler 2013/01/05 01:06:49 Depending on what the icon is, I'm not sure if dra
Ilya Sherman 2013/01/05 03:14:10 Hmm, what do you mean by drawing on a half boundar
Scott Hess - ex-Googler 2013/01/09 21:36:17 Basically, the image will be drawn at either floor
244 [icon drawAtPoint:NSMakePoint(x, y)
245 fromRect:NSZeroRect
246 operation:NSCompositeSourceOver
247 fraction:1.0];
248
249 x += isRTL ?
250 iconSize.width + AutofillPopupView::kIconPadding :
251 -AutofillPopupView::kIconPadding;
252 }
253
254 // Draw the subtext.
255 NSSize subtextSize = [subtext sizeWithAttributes:nil];
256 x += isRTL ? 0 : -subtextSize.width;
257 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2;
258
259 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
260 }
261
262 - (NSImage*)iconAtIndex:(int)index {
263 if (controller_->icons()[index].empty())
264 return nil;
265
266 int iconId = controller_->GetIconResourceID(controller_->icons()[index]);
267 DCHECK_NE(-1, iconId);
268 return
269 ui::ResourceBundle::GetSharedInstance().GetImageNamed(iconId).ToNSImage();
270 }
271
272 - (gfx::Point)flipNSPointToPoint:(NSPoint)point {
273 NSRect rect;
274 rect.origin = point;
275 rect.size = NSZeroSize;
276 return [self flipNSRectToRect:rect].origin();
277 }
278
279 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698