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 |