Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |