| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" | 5 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" |
| 6 | 6 |
| 7 #include "base/sys_string_conversions.h" | 7 #include "base/sys_string_conversions.h" |
| 8 #include "chrome/browser/autocomplete/autocomplete_edit.h" | 8 #include "chrome/browser/autocomplete/autocomplete_edit.h" |
| 9 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" | 9 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" |
| 10 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | 10 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 static const NSColor* ContentTextColor() { | 29 static const NSColor* ContentTextColor() { |
| 30 return [NSColor blackColor]; | 30 return [NSColor blackColor]; |
| 31 } | 31 } |
| 32 static const NSColor* URLTextColor() { | 32 static const NSColor* URLTextColor() { |
| 33 return [NSColor colorWithCalibratedRed:0.0 green:0.55 blue:0.0 alpha:1.0]; | 33 return [NSColor colorWithCalibratedRed:0.0 green:0.55 blue:0.0 alpha:1.0]; |
| 34 } | 34 } |
| 35 static const NSColor* DescriptionTextColor() { | 35 static const NSColor* DescriptionTextColor() { |
| 36 return [NSColor darkGrayColor]; | 36 return [NSColor darkGrayColor]; |
| 37 } | 37 } |
| 38 | 38 |
| 39 // TODO(shess): As with colors, there are a dozen ways to phrase this, | |
| 40 // all of them probably wrong. Circle back with a ui-oriented | |
| 41 // resource later. | |
| 42 static const NSFont* NormalFont() { | |
| 43 return [NSFont userFontOfSize:12]; | |
| 44 } | |
| 45 static const NSFont* BoldFont() { | |
| 46 return [NSFont boldSystemFontOfSize:12]; | |
| 47 } | |
| 48 | |
| 49 // Return the appropriate icon for the given match. Derived from the | 39 // Return the appropriate icon for the given match. Derived from the |
| 50 // gtk code. | 40 // gtk code. |
| 51 NSImage* MatchIcon(const AutocompleteMatch& match) { | 41 NSImage* MatchIcon(const AutocompleteMatch& match) { |
| 52 if (match.starred) { | 42 if (match.starred) { |
| 53 return [NSImage imageNamed:@"o2_star.png"]; | 43 return [NSImage imageNamed:@"o2_star.png"]; |
| 54 } | 44 } |
| 55 | 45 |
| 56 switch (match.type) { | 46 switch (match.type) { |
| 57 case AutocompleteMatch::URL_WHAT_YOU_TYPED: | 47 case AutocompleteMatch::URL_WHAT_YOU_TYPED: |
| 58 case AutocompleteMatch::NAVSUGGEST: { | 48 case AutocompleteMatch::NAVSUGGEST: { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 82 } | 72 } |
| 83 | 73 |
| 84 } // namespace | 74 } // namespace |
| 85 | 75 |
| 86 // Helper for MatchText() to allow sharing code between the contents | 76 // Helper for MatchText() to allow sharing code between the contents |
| 87 // and description cases. Returns NSMutableAttributedString as a | 77 // and description cases. Returns NSMutableAttributedString as a |
| 88 // convenience for MatchText(). | 78 // convenience for MatchText(). |
| 89 NSMutableAttributedString* AutocompletePopupViewMac::DecorateMatchedString( | 79 NSMutableAttributedString* AutocompletePopupViewMac::DecorateMatchedString( |
| 90 const std::wstring &matchString, | 80 const std::wstring &matchString, |
| 91 const AutocompleteMatch::ACMatchClassifications &classifications, | 81 const AutocompleteMatch::ACMatchClassifications &classifications, |
| 92 NSColor* textColor) { | 82 NSColor* textColor, NSFont* font) { |
| 83 // Cache for on-demand computation of the bold version of |font|. |
| 84 NSFont* boldFont = nil; |
| 93 | 85 |
| 94 // Start out with a string using the default style info. | 86 // Start out with a string using the default style info. |
| 95 NSString* s = base::SysWideToNSString(matchString); | 87 NSString* s = base::SysWideToNSString(matchString); |
| 96 NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: | 88 NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: |
| 97 NormalFont(), NSFontAttributeName, | 89 font, NSFontAttributeName, |
| 98 textColor, NSForegroundColorAttributeName, | 90 textColor, NSForegroundColorAttributeName, |
| 99 nil]; | 91 nil]; |
| 100 NSMutableAttributedString* as = | 92 NSMutableAttributedString* as = |
| 101 [[[NSMutableAttributedString alloc] initWithString:s | 93 [[[NSMutableAttributedString alloc] initWithString:s |
| 102 attributes:attributes] | 94 attributes:attributes] |
| 103 autorelease]; | 95 autorelease]; |
| 104 | 96 |
| 105 // Mark up the runs which differ from the default. | 97 // Mark up the runs which differ from the default. |
| 106 for (ACMatchClassifications::const_iterator i = classifications.begin(); | 98 for (ACMatchClassifications::const_iterator i = classifications.begin(); |
| 107 i != classifications.end(); ++i) { | 99 i != classifications.end(); ++i) { |
| 108 const BOOL isLast = (i+1) == classifications.end(); | 100 const BOOL isLast = (i+1) == classifications.end(); |
| 109 const size_t nextOffset = (isLast ? matchString.length() : (i+1)->offset); | 101 const size_t nextOffset = (isLast ? matchString.length() : (i+1)->offset); |
| 110 const NSInteger location = static_cast<NSInteger>(i->offset); | 102 const NSInteger location = static_cast<NSInteger>(i->offset); |
| 111 const NSInteger length = static_cast<NSInteger>(nextOffset - i->offset); | 103 const NSInteger length = static_cast<NSInteger>(nextOffset - i->offset); |
| 112 const NSRange range = NSMakeRange(location, length); | 104 const NSRange range = NSMakeRange(location, length); |
| 113 | 105 |
| 114 if (0 != (i->style & ACMatchClassification::URL)) { | 106 if (0 != (i->style & ACMatchClassification::URL)) { |
| 115 [as addAttribute:NSForegroundColorAttributeName | 107 [as addAttribute:NSForegroundColorAttributeName |
| 116 value:URLTextColor() range:range]; | 108 value:URLTextColor() range:range]; |
| 117 } | 109 } |
| 118 | 110 |
| 119 if (0 != (i->style & ACMatchClassification::MATCH)) { | 111 if (0 != (i->style & ACMatchClassification::MATCH)) { |
| 120 [as addAttribute:NSFontAttributeName value:BoldFont() range:range]; | 112 if (!boldFont) { |
| 113 NSFontManager* fontManager = [NSFontManager sharedFontManager]; |
| 114 boldFont = [fontManager convertFont:font toHaveTrait:NSBoldFontMask]; |
| 115 } |
| 116 [as addAttribute:NSFontAttributeName value:boldFont range:range]; |
| 121 } | 117 } |
| 122 } | 118 } |
| 123 | 119 |
| 124 return as; | 120 return as; |
| 125 } | 121 } |
| 126 | 122 |
| 127 // Return the text to show for the match, based on the match's | 123 // Return the text to show for the match, based on the match's |
| 128 // contents and description. | 124 // contents and description. Result will be in |font|, with the |
| 129 NSMutableAttributedString* AutocompletePopupViewMac::MatchText( | 125 // boldfaced version used for matches. |
| 130 const AutocompleteMatch& match) { | 126 NSAttributedString* AutocompletePopupViewMac::MatchText( |
| 127 const AutocompleteMatch& match, NSFont* font) { |
| 131 NSMutableAttributedString *as = | 128 NSMutableAttributedString *as = |
| 132 DecorateMatchedString(match.contents, match.contents_class, | 129 DecorateMatchedString(match.contents, match.contents_class, |
| 133 ContentTextColor()); | 130 ContentTextColor(), font); |
| 134 | 131 |
| 135 // If there is a description, append it, separated from the contents | 132 // If there is a description, append it, separated from the contents |
| 136 // with an em dash, and decorated with a distinct color. | 133 // with an em dash, and decorated with a distinct color. |
| 137 if (!match.description.empty()) { | 134 if (!match.description.empty()) { |
| 138 NSDictionary* attributes = | 135 NSDictionary* attributes = |
| 139 [NSDictionary dictionaryWithObjectsAndKeys: | 136 [NSDictionary dictionaryWithObjectsAndKeys: |
| 140 NormalFont(), NSFontAttributeName, | 137 font, NSFontAttributeName, |
| 141 ContentTextColor(), NSForegroundColorAttributeName, | 138 ContentTextColor(), NSForegroundColorAttributeName, |
| 142 nil]; | 139 nil]; |
| 143 NSString* rawEmDash = [NSString stringWithFormat:@" %C ", 0x2014]; | 140 NSString* rawEmDash = [NSString stringWithFormat:@" %C ", 0x2014]; |
| 144 NSAttributedString* emDash = | 141 NSAttributedString* emDash = |
| 145 [[[NSAttributedString alloc] initWithString:rawEmDash | 142 [[[NSAttributedString alloc] initWithString:rawEmDash |
| 146 attributes:attributes] autorelease]; | 143 attributes:attributes] autorelease]; |
| 147 | 144 |
| 148 NSAttributedString* description = | 145 NSAttributedString* description = |
| 149 DecorateMatchedString(match.description, match.description_class, | 146 DecorateMatchedString(match.description, match.description_class, |
| 150 DescriptionTextColor()); | 147 DescriptionTextColor(), font); |
| 151 | 148 |
| 152 [as appendAttributedString:emDash]; | 149 [as appendAttributedString:emDash]; |
| 153 [as appendAttributedString:description]; | 150 [as appendAttributedString:description]; |
| 154 } | 151 } |
| 155 | 152 |
| 156 NSMutableParagraphStyle* style = | 153 NSMutableParagraphStyle* style = |
| 157 [[[NSMutableParagraphStyle alloc] init] autorelease]; | 154 [[[NSMutableParagraphStyle alloc] init] autorelease]; |
| 158 [style setLineBreakMode:NSLineBreakByTruncatingTail]; | 155 [style setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 159 [as addAttribute:NSParagraphStyleAttributeName value:style | 156 [as addAttribute:NSParagraphStyleAttributeName value:style |
| 160 range:NSMakeRange(0, [as length])]; | 157 range:NSMakeRange(0, [as length])]; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 NSMatrix* matrix = [popup_ contentView]; | 253 NSMatrix* matrix = [popup_ contentView]; |
| 257 [matrix setTarget:nil]; | 254 [matrix setTarget:nil]; |
| 258 | 255 |
| 259 popup_.reset(nil); | 256 popup_.reset(nil); |
| 260 | 257 |
| 261 return; | 258 return; |
| 262 } | 259 } |
| 263 | 260 |
| 264 CreatePopupIfNeeded(); | 261 CreatePopupIfNeeded(); |
| 265 | 262 |
| 263 // Load the results into the popup's matrix. |
| 264 AutocompleteMatrix* matrix = [popup_ contentView]; |
| 265 const size_t rows = model_->result().size(); |
| 266 DCHECK_GT(rows, 0U); |
| 267 [matrix renewRows:rows columns:1]; |
| 268 for (size_t ii = 0; ii < rows; ++ii) { |
| 269 AutocompleteButtonCell* cell = [matrix cellAtRow:ii column:0]; |
| 270 const AutocompleteMatch& match = model_->result().match_at(ii); |
| 271 [cell setImage:MatchIcon(match)]; |
| 272 [cell setAttributedTitle:MatchText(match, [field_ font])]; |
| 273 } |
| 274 |
| 266 // Layout the popup and size it to land underneath the field. | 275 // Layout the popup and size it to land underneath the field. |
| 267 // TODO(shess) Consider refactoring to remove this depenency, | 276 // TODO(shess) Consider refactoring to remove this depenency, |
| 268 // because the popup doesn't need any of the field-like aspects of | 277 // because the popup doesn't need any of the field-like aspects of |
| 269 // field_. The edit view could expose helper methods for attaching | 278 // field_. The edit view could expose helper methods for attaching |
| 270 // the window to the field. | 279 // the window to the field. |
| 271 NSRect r = [field_ bounds]; | 280 NSRect r = [field_ bounds]; |
| 272 r = [field_ convertRectToBase:r]; | 281 r = [field_ convertRectToBase:r]; |
| 273 r.origin = [[field_ window] convertBaseToScreen:r.origin]; | 282 r.origin = [[field_ window] convertBaseToScreen:r.origin]; |
| 274 | 283 |
| 275 AutocompleteMatrix* matrix = [popup_ contentView]; | 284 // Set the cell size to fit a line of text in the cell's font. All |
| 276 [matrix setCellSize:NSMakeSize(r.size.width, [matrix cellSize].height)]; | 285 // cells should use the same font and layout to one line. |
| 286 NSRect bigRect = [matrix bounds]; |
| 287 // TODO(shess): Why 1000.0? Because it's "big enough". Find |
| 288 // something better. |
| 289 bigRect.size.height = 1000.0; |
| 290 NSSize cellSize = [[matrix cellAtRow:0 column:0] cellSizeForBounds:bigRect]; |
| 291 [matrix setCellSize:NSMakeSize(r.size.width, cellSize.height)]; |
| 292 |
| 293 // Make the matrix big enough to hold all the cells. |
| 294 [matrix sizeToCells]; |
| 277 [matrix setFrameSize:NSMakeSize(r.size.width, [matrix frame].size.height)]; | 295 [matrix setFrameSize:NSMakeSize(r.size.width, [matrix frame].size.height)]; |
| 278 | 296 |
| 279 size_t rows = model_->result().size(); | 297 // Make the window just as big. |
| 280 [matrix renewRows:rows columns:1]; | |
| 281 [matrix sizeToCells]; | |
| 282 r.size.height = [matrix frame].size.height; | 298 r.size.height = [matrix frame].size.height; |
| 283 r.origin.y -= r.size.height + 2; | 299 r.origin.y -= r.size.height + 2; |
| 284 | 300 |
| 285 for (size_t ii = 0; ii < rows; ++ii) { | |
| 286 AutocompleteButtonCell* cell = [matrix cellAtRow:ii column:0]; | |
| 287 const AutocompleteMatch& match = model_->result().match_at(ii); | |
| 288 [cell setImage:MatchIcon(match)]; | |
| 289 [cell setAttributedTitle:MatchText(match)]; | |
| 290 } | |
| 291 | |
| 292 // Update the selection. | 301 // Update the selection. |
| 293 PaintUpdatesNow(); | 302 PaintUpdatesNow(); |
| 294 | 303 |
| 295 [popup_ setFrame:r display:YES]; | 304 [popup_ setFrame:r display:YES]; |
| 296 | 305 |
| 297 if (!IsOpen()) { | 306 if (!IsOpen()) { |
| 298 [[field_ window] addChildWindow:popup_ ordered:NSWindowAbove]; | 307 [[field_ window] addChildWindow:popup_ ordered:NSWindowAbove]; |
| 299 } | 308 } |
| 300 } | 309 } |
| 301 | 310 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 } | 441 } |
| 433 return self; | 442 return self; |
| 434 } | 443 } |
| 435 | 444 |
| 436 - (void)select:sender { | 445 - (void)select:sender { |
| 437 DCHECK(popup_view_); | 446 DCHECK(popup_view_); |
| 438 popup_view_->AcceptInput(); | 447 popup_view_->AcceptInput(); |
| 439 } | 448 } |
| 440 | 449 |
| 441 @end | 450 @end |
| OLD | NEW |