| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h" | 5 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
| 9 #include "chrome/browser/ui/autofill/autofill_popup_controller.h" | 9 #include "chrome/browser/ui/autofill/autofill_popup_controller.h" |
| 10 #include "chrome/browser/ui/autofill/popup_constants.h" | 10 #include "chrome/browser/ui/autofill/popup_constants.h" |
| 11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h" | 11 #include "chrome/browser/ui/cocoa/autofill/autofill_popup_view_bridge.h" |
| 12 #include "components/autofill/core/browser/popup_item_ids.h" | 12 #include "components/autofill/core/browser/popup_item_ids.h" |
| 13 #include "grit/ui_resources.h" | 13 #include "grit/ui_resources.h" |
| 14 #include "ui/base/cocoa/window_size_constants.h" |
| 14 #include "ui/base/resource/resource_bundle.h" | 15 #include "ui/base/resource/resource_bundle.h" |
| 15 #include "ui/gfx/font_list.h" | 16 #include "ui/gfx/font_list.h" |
| 16 #include "ui/gfx/image/image.h" | 17 #include "ui/gfx/image/image.h" |
| 17 #include "ui/gfx/point.h" | 18 #include "ui/gfx/point.h" |
| 18 #include "ui/gfx/rect.h" | 19 #include "ui/gfx/rect.h" |
| 19 | 20 |
| 20 using autofill::AutofillPopupView; | 21 using autofill::AutofillPopupView; |
| 21 | 22 |
| 22 namespace { | 23 @implementation AutofillPopupBaseViewCocoa |
| 23 | 24 |
| 24 NSColor* BackgroundColor() { | 25 #pragma mark - |
| 26 #pragma mark Colors |
| 27 |
| 28 - (NSColor*)backgroundColor { |
| 25 return [NSColor whiteColor]; | 29 return [NSColor whiteColor]; |
| 26 } | 30 } |
| 27 | 31 |
| 28 // The color of the border around the popup. | 32 - (NSColor*)borderColor { |
| 29 NSColor* BorderColor() { | |
| 30 return [NSColor colorForControlTint:[NSColor currentControlTint]]; | 33 return [NSColor colorForControlTint:[NSColor currentControlTint]]; |
| 31 } | 34 } |
| 32 | 35 |
| 33 NSColor* SeparatorColor() { | 36 - (NSColor*)separatorColor { |
| 34 return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; | 37 return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; |
| 35 } | 38 } |
| 36 | 39 |
| 37 NSColor* HighlightColor() { | 40 - (NSColor*)highlightColor { |
| 38 return [NSColor selectedControlColor]; | 41 return [NSColor selectedControlColor]; |
| 39 } | 42 } |
| 40 | 43 |
| 41 NSColor* NameColor() { | 44 - (NSColor*)nameColor { |
| 42 return [NSColor blackColor]; | 45 return [NSColor blackColor]; |
| 43 } | 46 } |
| 44 | 47 |
| 45 NSColor* WarningColor() { | 48 - (NSColor*)warningColor { |
| 46 return [NSColor grayColor]; | 49 return [NSColor grayColor]; |
| 47 } | 50 } |
| 48 | 51 |
| 49 NSColor* SubtextColor() { | 52 - (NSColor*)subtextColor { |
| 50 return [NSColor grayColor]; | 53 return [NSColor grayColor]; |
| 51 } | 54 } |
| 52 | 55 |
| 53 } // namespace | 56 #pragma mark - |
| 57 #pragma mark Public methods |
| 58 |
| 59 - (id)initWithAutofillPopupViewDelegate: |
| 60 (autofill::AutofillPopupViewDelegate*)delegate frame:(NSRect)frame { |
| 61 self = [super initWithFrame:frame]; |
| 62 if (self) |
| 63 delegate_ = delegate; |
| 64 |
| 65 return self; |
| 66 } |
| 67 |
| 68 - (void)controllerDestroyed { |
| 69 delegate_ = NULL; |
| 70 } |
| 71 |
| 72 - (void)drawSeparatorWithBounds:(NSRect)bounds { |
| 73 [[self separatorColor] set]; |
| 74 [NSBezierPath fillRect:bounds]; |
| 75 } |
| 76 |
| 77 // A slight optimization for drawing: |
| 78 // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa
ViewsGuide/Optimizing/Optimizing.html |
| 79 - (BOOL)isOpaque { |
| 80 return YES; |
| 81 } |
| 82 |
| 83 - (BOOL)isFlipped { |
| 84 // Flipped so that it's easier to share controller logic with other OSes. |
| 85 return YES; |
| 86 } |
| 87 |
| 88 - (void)drawBackgroundAndBorderInRect:(NSRect)dirtyRect { |
| 89 // The inset is needed since the border is centered on the |path|. |
| 90 // TODO(isherman): We should consider using asset-based drawing for the |
| 91 // border, creating simple bitmaps for the view's border and background, and |
| 92 // drawing them using NSDrawNinePartImage(). |
| 93 CGFloat inset = autofill::kPopupBorderThickness / 2.0; |
| 94 NSRect borderRect = NSInsetRect([self bounds], inset, inset); |
| 95 NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; |
| 96 [[self backgroundColor] setFill]; |
| 97 [path fill]; |
| 98 [path setLineWidth:autofill::kPopupBorderThickness]; |
| 99 [[self borderColor] setStroke]; |
| 100 [path stroke]; |
| 101 } |
| 102 |
| 103 #pragma mark - |
| 104 #pragma mark Messages from AutofillPopupViewBridge: |
| 105 |
| 106 - (void)updateBoundsAndRedrawPopup { |
| 107 NSRect frame = NSRectFromCGRect(delegate_->popup_bounds().ToCGRect()); |
| 108 |
| 109 // Flip coordinates back into Cocoa-land. The controller's platform-neutral |
| 110 // coordinate space places the origin at the top-left of the first screen, |
| 111 // whereas Cocoa's coordinate space expects the origin to be at the |
| 112 // bottom-left of this same screen. |
| 113 NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; |
| 114 frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame); |
| 115 |
| 116 // TODO(isherman): The view should support scrolling if the popup gets too |
| 117 // big to fit on the screen. |
| 118 [[self window] setFrame:frame display:YES]; |
| 119 [self setNeedsDisplay:YES]; |
| 120 } |
| 121 |
| 122 - (void)showPopup { |
| 123 NSWindow* window = |
| 124 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater |
| 125 styleMask:NSBorderlessWindowMask |
| 126 backing:NSBackingStoreBuffered |
| 127 defer:YES]; |
| 128 [window setContentView:self]; |
| 129 |
| 130 // Telling Cocoa that the window is opaque enables some drawing optimizations. |
| 131 [window setOpaque:YES]; |
| 132 |
| 133 [self updateBoundsAndRedrawPopup]; |
| 134 [[delegate_->container_view() window] addChildWindow:window |
| 135 ordered:NSWindowAbove]; |
| 136 } |
| 137 |
| 138 - (void)hidePopup { |
| 139 [self controllerDestroyed]; |
| 140 |
| 141 // Remove the child window before closing, otherwise it can mess up |
| 142 // display ordering. |
| 143 NSWindow* window = [self window]; |
| 144 [[window parentWindow] removeChildWindow:window]; |
| 145 [window close]; |
| 146 } |
| 147 |
| 148 @end |
| 54 | 149 |
| 55 #pragma mark - | 150 #pragma mark - |
| 56 #pragma mark Private methods | 151 #pragma mark Private methods |
| 57 | 152 |
| 58 @interface AutofillPopupViewCocoa () | 153 @interface AutofillPopupViewCocoa () |
| 59 | 154 |
| 60 // Draws a thin separator in the popup UI. | |
| 61 - (void)drawSeparatorWithBounds:(NSRect)bounds; | |
| 62 | |
| 63 // Draws an Autofill suggestion in the given |bounds|, labeled with the given | 155 // Draws an Autofill suggestion in the given |bounds|, labeled with the given |
| 64 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn | 156 // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn |
| 65 // with a highlight. |index| determines the font to use, as well as the icon, | 157 // with a highlight. |index| determines the font to use, as well as the icon, |
| 66 // if the row requires it -- such as for credit cards. | 158 // if the row requires it -- such as for credit cards. |
| 67 - (void)drawSuggestionWithName:(NSString*)name | 159 - (void)drawSuggestionWithName:(NSString*)name |
| 68 subtext:(NSString*)subtext | 160 subtext:(NSString*)subtext |
| 69 index:(size_t)index | 161 index:(size_t)index |
| 70 bounds:(NSRect)bounds | 162 bounds:(NSRect)bounds |
| 71 selected:(BOOL)isSelected; | 163 selected:(BOOL)isSelected; |
| 72 | 164 |
| 73 // Returns the icon for the row with the given |index|, or |nil| if there is | 165 // Returns the icon for the row with the given |index|, or |nil| if there is |
| 74 // none. | 166 // none. |
| 75 - (NSImage*)iconAtIndex:(size_t)index; | 167 - (NSImage*)iconAtIndex:(size_t)index; |
| 76 | 168 |
| 77 @end | 169 @end |
| 78 | 170 |
| 79 @implementation AutofillPopupViewCocoa | 171 @implementation AutofillPopupViewCocoa |
| 80 | 172 |
| 81 #pragma mark - | 173 #pragma mark - |
| 82 #pragma mark Initialisers | 174 #pragma mark Initialisers |
| 83 | 175 |
| 84 - (id)initWithFrame:(NSRect)frame { | 176 - (id)initWithFrame:(NSRect)frame { |
| 85 NOTREACHED(); | 177 NOTREACHED(); |
| 86 return [self initWithController:NULL frame:frame]; | 178 return [self initWithController:NULL frame:frame]; |
| 87 } | 179 } |
| 88 | 180 |
| 89 - (id)initWithController:(autofill::AutofillPopupController*)controller | 181 - (id)initWithController:(autofill::AutofillPopupController*)controller |
| 90 frame:(NSRect)frame { | 182 frame:(NSRect)frame { |
| 91 self = [super initWithFrame:frame]; | 183 self = [super initWithAutofillPopupViewDelegate:controller frame:frame]; |
| 92 if (self) | 184 if (self) |
| 93 controller_ = controller; | 185 controller_ = controller; |
| 94 | 186 |
| 95 return self; | 187 return self; |
| 96 } | 188 } |
| 97 | 189 |
| 98 #pragma mark - | 190 #pragma mark - |
| 99 #pragma mark NSView implementation: | 191 #pragma mark NSView implementation: |
| 100 | 192 |
| 101 // A slight optimization for drawing: | |
| 102 // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Cocoa
ViewsGuide/Optimizing/Optimizing.html | |
| 103 - (BOOL)isOpaque { | |
| 104 return YES; | |
| 105 } | |
| 106 | |
| 107 - (BOOL)isFlipped { | |
| 108 // Flipped so that it's easier to share controller logic with other OSes. | |
| 109 return YES; | |
| 110 } | |
| 111 | |
| 112 - (void)drawRect:(NSRect)dirtyRect { | 193 - (void)drawRect:(NSRect)dirtyRect { |
| 113 // If the view is in the process of being destroyed, don't bother drawing. | 194 // If the view is in the process of being destroyed, don't bother drawing. |
| 114 if (!controller_) | 195 if (!controller_) |
| 115 return; | 196 return; |
| 116 | 197 |
| 117 // Draw the popup's background and border. | 198 [self drawBackgroundAndBorderInRect:dirtyRect]; |
| 118 // The inset is needed since the border is centered on the |path|. | |
| 119 // TODO(isherman): We should consider using asset-based drawing for the | |
| 120 // border, creating simple bitmaps for the view's border and background, and | |
| 121 // drawing them using NSDrawNinePartImage(). | |
| 122 CGFloat inset = autofill::kPopupBorderThickness / 2.0; | |
| 123 NSRect borderRect = NSInsetRect([self bounds], inset, inset); | |
| 124 NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; | |
| 125 [BackgroundColor() setFill]; | |
| 126 [path fill]; | |
| 127 [path setLineWidth:autofill::kPopupBorderThickness]; | |
| 128 [BorderColor() setStroke]; | |
| 129 [path stroke]; | |
| 130 | 199 |
| 131 for (size_t i = 0; i < controller_->names().size(); ++i) { | 200 for (size_t i = 0; i < controller_->names().size(); ++i) { |
| 132 // Skip rows outside of the dirty rect. | 201 // Skip rows outside of the dirty rect. |
| 133 NSRect rowBounds = | 202 NSRect rowBounds = |
| 134 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect()); | 203 NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect()); |
| 135 if (!NSIntersectsRect(rowBounds, dirtyRect)) | 204 if (!NSIntersectsRect(rowBounds, dirtyRect)) |
| 136 continue; | 205 continue; |
| 137 | 206 |
| 138 if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { | 207 if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { |
| 139 [self drawSeparatorWithBounds:rowBounds]; | 208 [self drawSeparatorWithBounds:rowBounds]; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 | 258 |
| 190 #pragma mark - | 259 #pragma mark - |
| 191 #pragma mark Public API: | 260 #pragma mark Public API: |
| 192 | 261 |
| 193 - (void)controllerDestroyed { | 262 - (void)controllerDestroyed { |
| 194 // Since the |controller_| either already has been destroyed or is about to | 263 // Since the |controller_| either already has been destroyed or is about to |
| 195 // be, about the only thing we can safely do with it is to null it out. | 264 // be, about the only thing we can safely do with it is to null it out. |
| 196 controller_ = NULL; | 265 controller_ = NULL; |
| 197 } | 266 } |
| 198 | 267 |
| 268 - (void)invalidateRow:(size_t)row { |
| 269 NSRect dirty_rect = |
| 270 NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect()); |
| 271 [self setNeedsDisplayInRect:dirty_rect]; |
| 272 } |
| 273 |
| 199 #pragma mark - | 274 #pragma mark - |
| 200 #pragma mark Private API: | 275 #pragma mark Private API: |
| 201 | 276 |
| 202 - (void)drawSeparatorWithBounds:(NSRect)bounds { | |
| 203 [SeparatorColor() set]; | |
| 204 [NSBezierPath fillRect:bounds]; | |
| 205 } | |
| 206 | |
| 207 - (void)drawSuggestionWithName:(NSString*)name | 277 - (void)drawSuggestionWithName:(NSString*)name |
| 208 subtext:(NSString*)subtext | 278 subtext:(NSString*)subtext |
| 209 index:(size_t)index | 279 index:(size_t)index |
| 210 bounds:(NSRect)bounds | 280 bounds:(NSRect)bounds |
| 211 selected:(BOOL)isSelected { | 281 selected:(BOOL)isSelected { |
| 212 // If this row is selected, highlight it. | 282 // If this row is selected, highlight it. |
| 213 if (isSelected) { | 283 if (isSelected) { |
| 214 [HighlightColor() set]; | 284 [[self highlightColor] set]; |
| 215 [NSBezierPath fillRect:bounds]; | 285 [NSBezierPath fillRect:bounds]; |
| 216 } | 286 } |
| 217 | 287 |
| 218 BOOL isRTL = controller_->IsRTL(); | 288 BOOL isRTL = controller_->IsRTL(); |
| 219 | 289 |
| 220 NSColor* nameColor = | 290 NSColor* nameColor = |
| 221 controller_->IsWarning(index) ? WarningColor() : NameColor(); | 291 controller_->IsWarning(index) ? [self warningColor] : [self nameColor]; |
| 222 NSDictionary* nameAttributes = | 292 NSDictionary* nameAttributes = |
| 223 [NSDictionary dictionaryWithObjectsAndKeys: | 293 [NSDictionary dictionaryWithObjectsAndKeys: |
| 224 controller_->GetNameFontListForRow(index).GetPrimaryFont(). | 294 controller_->GetNameFontListForRow(index).GetPrimaryFont(). |
| 225 GetNativeFont(), | 295 GetNativeFont(), |
| 226 NSFontAttributeName, nameColor, NSForegroundColorAttributeName, | 296 NSFontAttributeName, nameColor, NSForegroundColorAttributeName, |
| 227 nil]; | 297 nil]; |
| 228 NSSize nameSize = [name sizeWithAttributes:nameAttributes]; | 298 NSSize nameSize = [name sizeWithAttributes:nameAttributes]; |
| 229 CGFloat x = bounds.origin.x + | 299 CGFloat x = bounds.origin.x + |
| 230 (isRTL ? | 300 (isRTL ? |
| 231 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : | 301 bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : |
| (...skipping 23 matching lines...) Expand all Loading... |
| 255 | 325 |
| 256 x += isRTL ? | 326 x += isRTL ? |
| 257 iconSize.width + AutofillPopupView::kIconPadding : | 327 iconSize.width + AutofillPopupView::kIconPadding : |
| 258 -AutofillPopupView::kIconPadding; | 328 -AutofillPopupView::kIconPadding; |
| 259 } | 329 } |
| 260 | 330 |
| 261 // Draw the subtext. | 331 // Draw the subtext. |
| 262 NSDictionary* subtextAttributes = | 332 NSDictionary* subtextAttributes = |
| 263 [NSDictionary dictionaryWithObjectsAndKeys: | 333 [NSDictionary dictionaryWithObjectsAndKeys: |
| 264 controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), | 334 controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), |
| 265 NSFontAttributeName, SubtextColor(), NSForegroundColorAttributeName, | 335 NSFontAttributeName, |
| 336 [self subtextColor], |
| 337 NSForegroundColorAttributeName, |
| 266 nil]; | 338 nil]; |
| 267 NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; | 339 NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; |
| 268 x += isRTL ? 0 : -subtextSize.width; | 340 x += isRTL ? 0 : -subtextSize.width; |
| 269 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; | 341 y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; |
| 270 | 342 |
| 271 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; | 343 [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; |
| 272 } | 344 } |
| 273 | 345 |
| 274 - (NSImage*)iconAtIndex:(size_t)index { | 346 - (NSImage*)iconAtIndex:(size_t)index { |
| 275 if (controller_->icons()[index].empty()) | 347 if (controller_->icons()[index].empty()) |
| 276 return nil; | 348 return nil; |
| 277 | 349 |
| 278 int iconId = controller_->GetIconResourceID(controller_->icons()[index]); | 350 int iconId = controller_->GetIconResourceID(controller_->icons()[index]); |
| 279 DCHECK_NE(-1, iconId); | 351 DCHECK_NE(-1, iconId); |
| 280 | 352 |
| 281 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 353 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 282 return rb.GetNativeImageNamed(iconId).ToNSImage(); | 354 return rb.GetNativeImageNamed(iconId).ToNSImage(); |
| 283 } | 355 } |
| 284 | 356 |
| 285 @end | 357 @end |
| OLD | NEW |