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

Unified 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, 12 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
new file mode 100644
index 0000000000000000000000000000000000000000..c56ee0e0983ec89d6f14ceb2459d7fe34d688d51
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h"
+
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_mac.h"
+#include "grit/ui_resources.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+
+#pragma mark -
+#pragma mark Private methods
+
+@interface AutofillPopupViewCocoa ()
+
+// Draws a thin separator in the popup UI.
+- (void)drawSeparatorWithBounds:(NSRect)bounds;
+
+// Draws an Autofill suggestion in the given |bounds|, labeled with the given
+// |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn
+// with a highlight. Some suggestions -- such as for credit cards -- might also
+// include an |icon| -- e.g. for the card type. Finally, if |canDelete| is
+// true, a delete icon is also drawn.
+- (void)drawSuggestionWithName:(NSString*)name
+ subtext:(NSString*)subtext
+ icon:(NSImage*)icon
+ bounds:(NSRect)bounds
+ selected:(BOOL)isSelected
+ canDelete:(BOOL)canDelete;
+
+// Returns the icon for the row with the given |index|, or |nil| if there is
+// none.
+- (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.
+
+// Flips the given |point|'s y coordinate to match Chrome's screen coordinate
+// system.
+- (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
+
+@end
+
+@implementation AutofillPopupViewCocoa
+
+#pragma mark -
+#pragma mark Initialisers
+
+- (id)initWithFrame:(NSRect)frame {
+ NOTREACHED();
+ return [self initWithController:NULL frame:frame];
+}
+
+- (id)initWithController:(AutofillPopupController*)controller
+ frame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ if (self)
+ controller_ = controller;
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark NSView implementation:
+
+// A slight optimization for drawing:
+// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/Optimizing/Optimizing.html
+- (BOOL)isOpaque {
+ return YES;
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ // If the view is in the process of being destroyed, don't bother drawing.
+ if (!controller_)
+ return;
+
+ // TODO(isherman): Is there a better way to leave room for the border?
+ // TODO(isherman): Drawing the border as part of the content view means that
+ // the rest of the content has to be careful not to overlap the border.
+ // Should the border be part of the window instead? If not, should the rest
+ // of the view be a subview? Or should I just draw the window content
+ // carefully?
+ NSRect borderRect = NSInsetRect([self bounds], 0.5, 0.5);
+ NSBezierPath* border = [NSBezierPath bezierPathWithRect:borderRect];
+
+ // TODO(isherman): Should I just make the window have a white background
+ // instead? Is there any reason to prefer clearColor for the window
+ // background color? I ask because most of the Chromium code that I've found
+ // 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
+ // TODO(isherman): Should I be calling [NSColor
+ // 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.
+ [[NSColor whiteColor] set];
+ [border fill];
+
+ // TODO(isherman): Device or calibrated? Is there shared code I should use to
+ // simplify this? Is there a way to extract the constants into a named color
+ // constant local to this file?
+ // TODO(isherman): This color does not match the other platforms, but it
+ // matches what the existing UI on Mac has as the color. The other platforms
+ // have a strange color: the RGB values are almost, but not quite, identical
+ // 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
+ [[NSColor colorWithDeviceRed:127/255.0
+ green:157/255.0
+ blue:185/255.0
+ alpha:1.0] set];
+ [border stroke];
+
+ for (size_t i = 0; i < controller_->names().size(); ++i) {
+ // Skip rows outside of the dirty rect.
+ NSRect rowBounds = [self flipRectToNSRect:controller_->GetRowBounds(i)];
+ if (!NSIntersectsRect(rowBounds, dirtyRect))
+ continue;
+
+ if (controller_->identifiers()[i] ==
+ WebKit::WebAutofillClient::MenuItemIDSeparator) {
+ [self drawSeparatorWithBounds:rowBounds];
+ } else {
+ NSString* name = SysUTF16ToNSString(controller_->names()[i]);
+ NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]);
+ BOOL isSelected = static_cast<int>(i) == controller_->selected_line();
+ [self drawSuggestionWithName:name
+ subtext:subtext
+ icon:[self iconAtIndex:i]
+ bounds:rowBounds
+ selected:isSelected
+ canDelete:controller_->CanDelete(i)];
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark BaseView implementation:
+
+- (void)mouseEvent:(NSEvent *)theEvent {
+ // If the view is in the process of being destroyed, abort.
+ if (!controller_)
+ return;
+
+ NSEventType event_type = [theEvent type];
+ NSPoint location = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+
+ // Convert to Chrome's screen coordinates.
+ gfx::Point screen_location = [self flipNSPointToPoint:location];
+
+ if (event_type == NSLeftMouseUp && NSPointInRect(location, [self bounds]))
+ controller_->MouseClicked(screen_location.x(), screen_location.y());
+ else if (event_type == NSMouseExited)
+ controller_->MouseExitedPopup();
+ else if (event_type == NSMouseMoved || event_type == NSLeftMouseDragged)
+ controller_->MouseHovered(screen_location.x(), screen_location.y());
+}
+
+#pragma mark -
+#pragma mark Public API:
+
+- (void)controllerDestroyed {
+ controller_ = NULL;
+}
+
+#pragma mark -
+#pragma mark Private API:
+
+- (void)drawSeparatorWithBounds:(NSRect)bounds {
+ // TODO(isherman): Device or calibrated? Is there shared code I should use to
+ // simplify this?
+ [[NSColor colorWithDeviceRed:220/255.0
+ green:220/255.0
+ 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.
+ alpha:1] set];
+ [NSBezierPath fillRect:bounds];
+}
+
+- (void)drawSuggestionWithName:(NSString*)name
+ subtext:(NSString*)subtext
+ icon:(NSImage*)icon
+ bounds:(NSRect)bounds
+ selected:(BOOL)isSelected
+ canDelete:(BOOL)canDelete {
+ // If this row is selected, highlight it.
+ if (isSelected) {
+ // TODO(isherman): The highlight color should match the system highlight
+ // 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.
+ [[NSColor colorWithDeviceRed:(0xCD / 255.0)
+ green:(0xCD / 255.0)
+ blue:(0xCD / 255.0)
+ alpha:1] set];
+ [NSBezierPath fillRect:bounds];
+ }
+
+ BOOL isRTL = base::i18n::IsRTL();
+
+ // 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
+ NSSize nameSize = [name sizeWithAttributes:nil];
+ CGFloat x = bounds.origin.x +
+ (isRTL ?
+ bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width:
+ AutofillPopupView::kEndPadding);
+ CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2;
+
+ [name drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
+
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+
+ // The x-coordinate will be updated as each element is drawn.
+ x = bounds.origin.x +
+ (isRTL ?
+ AutofillPopupView::kEndPadding :
+ bounds.size.width - AutofillPopupView::kEndPadding);
+
+ // Draw the delete icon, if one is needed.
+ if (canDelete) {
+ // TODO(csharp): Create a custom resource for the delete icon.
+ // http://crbug.com/131801
+ NSImage* deleteIcon;
+ if (isSelected && controller_->delete_icon_hovered())
+ deleteIcon = rb.GetImageNamed(IDR_CLOSE_BAR_H).ToNSImage();
+ else
+ deleteIcon = rb.GetImageNamed(IDR_CLOSE_BAR).ToNSImage();
+
+ NSSize iconSize = [deleteIcon size];
+ x += isRTL ? 0 : -iconSize.width;
+ y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
+ [deleteIcon drawAtPoint:NSMakePoint(x, y)
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+
+ x += isRTL ?
+ iconSize.width + AutofillPopupView::kIconPadding :
+ -AutofillPopupView::kIconPadding;
+ }
+
+ // Draw the Autofill icon, if one exists.
+ if (icon) {
+ NSSize iconSize = [icon size];
+ x += isRTL ? 0 : -iconSize.width;
+ 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
+ [icon drawAtPoint:NSMakePoint(x, y)
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+
+ x += isRTL ?
+ iconSize.width + AutofillPopupView::kIconPadding :
+ -AutofillPopupView::kIconPadding;
+ }
+
+ // Draw the subtext.
+ NSSize subtextSize = [subtext sizeWithAttributes:nil];
+ x += isRTL ? 0 : -subtextSize.width;
+ y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2;
+
+ [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:nil];
+}
+
+- (NSImage*)iconAtIndex:(int)index {
+ if (controller_->icons()[index].empty())
+ return nil;
+
+ int iconId = controller_->GetIconResourceID(controller_->icons()[index]);
+ DCHECK_NE(-1, iconId);
+ return
+ ui::ResourceBundle::GetSharedInstance().GetImageNamed(iconId).ToNSImage();
+}
+
+- (gfx::Point)flipNSPointToPoint:(NSPoint)point {
+ NSRect rect;
+ rect.origin = point;
+ rect.size = NSZeroSize;
+ return [self flipNSRectToRect:rect].origin();
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698