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.
5 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h"
7 #include "base/logging.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
10 #include "chrome/browser/ui/autofill/popup_constants.h"
11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h"
12 #include "components/autofill/core/browser/popup_item_ids.h"
13 #include "components/autofill/core/browser/suggestion.h"
14 #include "ui/base/cocoa/window_size_constants.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/gfx/font_list.h"
17 #include "ui/gfx/geometry/point.h"
18 #include "ui/gfx/geometry/rect.h"
19 #include "ui/gfx/image/image.h"
21 using autofill::AutofillPopupView;
23 @interface AutofillPopupViewCocoa ()
26 #pragma mark Private methods
28 // Draws an Autofill suggestion in the given |bounds|, labeled with the given
29 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn
30 // with a highlight. |index| determines the font to use, as well as the icon,
31 // if the row requires it -- such as for credit cards.
32 - (void)drawSuggestionWithName:(NSString*)name
33 subtext:(NSString*)subtext
36 selected:(BOOL)isSelected
37 textYOffset:(CGFloat)textYOffset;
39 // This comment block applies to all three draw* methods that follow.
40 // If |rightAlign| == YES.
41 // Draws the widget with right border aligned to |x|.
42 // Returns the x value of left border of the widget.
43 // If |rightAlign| == NO.
44 // Draws the widget with left border aligned to |x|.
45 // Returns the x value of right border of the widget.
46 - (CGFloat)drawName:(NSString*)name
49 rightAlign:(BOOL)rightAlign
51 textYOffset:(CGFloat)textYOffset;
52 - (CGFloat)drawIconAtIndex:(size_t)index
54 rightAlign:(BOOL)rightAlign
55 bounds:(NSRect)bounds;
56 - (CGFloat)drawSubtext:(NSString*)subtext
58 rightAlign:(BOOL)rightAlign
60 textYOffset:(CGFloat)textYOffset;
62 // Returns the icon for the row with the given |index|, or |nil| if there is
64 - (NSImage*)iconAtIndex:(size_t)index;
68 @implementation AutofillPopupViewCocoa
71 #pragma mark Initialisers
73 - (id)initWithFrame:(NSRect)frame {
75 return [self initWithController:NULL frame:frame];
78 - (id)initWithController:(autofill::AutofillPopupController*)controller
80 self = [super initWithDelegate:controller frame:frame];
82 controller_ = controller;
88 #pragma mark NSView implementation:
90 - (void)drawRect:(NSRect)dirtyRect {
91 // If the view is in the process of being destroyed, don't bother drawing.
95 [self drawBackgroundAndBorder];
97 for (size_t i = 0; i < controller_->GetLineCount(); ++i) {
98 // Skip rows outside of the dirty rect.
100 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect());
101 if (!NSIntersectsRect(rowBounds, dirtyRect))
103 const autofill::Suggestion& suggestion = controller_->GetSuggestionAt(i);
105 if (suggestion.frontend_id == autofill::POPUP_ITEM_ID_SEPARATOR) {
106 [self drawSeparatorWithBounds:rowBounds];
110 // Additional offset applied to the text in the vertical direction.
111 CGFloat textYOffset = 0;
113 NSString* value = SysUTF16ToNSString(controller_->GetElidedValueAt(i));
114 NSString* label = SysUTF16ToNSString(controller_->GetElidedLabelAt(i));
115 BOOL isSelected = static_cast<int>(i) == controller_->selected_line();
116 [self drawSuggestionWithName:value
121 textYOffset:textYOffset];
126 #pragma mark Public API:
128 - (void)controllerDestroyed {
129 // Since the |controller_| either already has been destroyed or is about to
130 // be, about the only thing we can safely do with it is to null it out.
132 [super delegateDestroyed];
135 - (void)invalidateRow:(size_t)row {
137 NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect());
138 [self setNeedsDisplayInRect:dirty_rect];
142 #pragma mark Private API:
144 - (void)drawSuggestionWithName:(NSString*)name
145 subtext:(NSString*)subtext
147 bounds:(NSRect)bounds
148 selected:(BOOL)isSelected
149 textYOffset:(CGFloat)textYOffset {
150 // If this row is selected, highlight it.
152 [[self highlightColor] set];
153 [NSBezierPath fillRect:bounds];
156 BOOL isRTL = controller_->IsRTL();
158 // The X values of the left and right borders of the autofill widget.
159 CGFloat leftX = NSMinX(bounds) + AutofillPopupView::kEndPadding;
160 CGFloat rightX = NSMaxX(bounds) - AutofillPopupView::kEndPadding;
162 // Draw left side if isRTL == NO, right side if isRTL == YES.
163 CGFloat x = isRTL ? rightX : leftX;
169 textYOffset:textYOffset];
171 // Draw right side if isRTL == NO, left side if isRTL == YES.
172 x = isRTL ? leftX : rightX;
173 x = [self drawIconAtIndex:index atX:x rightAlign:!isRTL bounds:bounds];
174 [self drawSubtext:subtext
178 textYOffset:textYOffset];
181 - (CGFloat)drawName:(NSString*)name
184 rightAlign:(BOOL)rightAlign
185 bounds:(NSRect)bounds
186 textYOffset:(CGFloat)textYOffset {
188 controller_->IsWarning(index) ? [self warningColor] : [self nameColor];
189 NSDictionary* nameAttributes =
190 [NSDictionary dictionaryWithObjectsAndKeys:
191 controller_->GetValueFontListForRow(index).GetPrimaryFont().
193 NSFontAttributeName, nameColor, NSForegroundColorAttributeName,
195 NSSize nameSize = [name sizeWithAttributes:nameAttributes];
196 x -= rightAlign ? nameSize.width : 0;
197 CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2;
200 [name drawAtPoint:NSMakePoint(x, y) withAttributes:nameAttributes];
202 x += rightAlign ? 0 : nameSize.width;
206 - (CGFloat)drawIconAtIndex:(size_t)index
208 rightAlign:(BOOL)rightAlign
209 bounds:(NSRect)bounds {
210 NSImage* icon = [self iconAtIndex:index];
213 NSSize iconSize = [icon size];
214 x -= rightAlign ? iconSize.width : 0;
215 CGFloat y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2;
216 [icon drawInRect:NSMakeRect(x, y, iconSize.width, iconSize.height)
218 operation:NSCompositeSourceOver
223 x += rightAlign ? -AutofillPopupView::kIconPadding
224 : iconSize.width + AutofillPopupView::kIconPadding;
228 - (CGFloat)drawSubtext:(NSString*)subtext
230 rightAlign:(BOOL)rightAlign
231 bounds:(NSRect)bounds
232 textYOffset:(CGFloat)textYOffset {
233 NSDictionary* subtextAttributes =
234 [NSDictionary dictionaryWithObjectsAndKeys:
235 controller_->GetLabelFontList().GetPrimaryFont().GetNativeFont(),
238 NSForegroundColorAttributeName,
240 NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes];
241 x -= rightAlign ? subtextSize.width : 0;
242 CGFloat y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2;
245 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes];
246 x += rightAlign ? 0 : subtextSize.width;
250 - (NSImage*)iconAtIndex:(size_t)index {
251 const base::string16& icon = controller_->GetSuggestionAt(index).icon;
255 int iconId = controller_->GetIconResourceID(icon);
256 DCHECK_NE(-1, iconId);
258 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
259 return rb.GetNativeImageNamed(iconId).ToNSImage();