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

Side by Side Diff: chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm

Issue 2805070: [Mac] First part of Omnibox decoration refactor. Enable ev bubble. (Closed) Base URL: git://codf21.jail/chromium.git
Patch Set: comment clarification Created 10 years, 5 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/cocoa/location_bar/autocomplete_text_field_cell.h" 5 #import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
6 6
7 #include "app/resource_bundle.h"
8 #include "base/logging.h" 7 #include "base/logging.h"
9 #import "chrome/browser/cocoa/image_utils.h" 8 #import "chrome/browser/cocoa/image_utils.h"
10 #include "gfx/font.h" 9 #import "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
11 #include "grit/theme_resources.h"
12 10
13 @interface AutocompleteTextAttachmentCell : NSTextAttachmentCell { 11 @interface AutocompleteTextAttachmentCell : NSTextAttachmentCell {
14 } 12 }
15 13
16 // TODO(shess): 14 // TODO(shess):
17 // Override -cellBaselineOffset to allow the image to be shifted up or 15 // Override -cellBaselineOffset to allow the image to be shifted up or
18 // down relative to the containing text's baseline. 16 // down relative to the containing text's baseline.
19 17
20 // Draw the image using |DrawImageInRect()| helper function for 18 // Draw the image using |DrawImageInRect()| helper function for
21 // flipped consistency with other image drawing. 19 // flipped consistency with other image drawing.
22 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView; 20 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView;
23 21
24 @end 22 @end
25 23
26 namespace { 24 namespace {
27 25
28 const CGFloat kBaselineAdjust = 2.0; 26 const CGFloat kBaselineAdjust = 2.0;
29 27
30 // Matches the clipping radius of |GradientButtonCell|. 28 // Matches the clipping radius of |GradientButtonCell|.
31 const CGFloat kCornerRadius = 4.0; 29 const CGFloat kCornerRadius = 4.0;
32 30
33 // How far to offset the keyword token into the field.
34 const NSInteger kKeywordXOffset = 3;
35
36 // How much width (beyond text) to add to the keyword token on each
37 // side.
38 const NSInteger kKeywordTokenInset = 3;
39
40 // Gap to leave between hint and right-hand-side of cell. 31 // Gap to leave between hint and right-hand-side of cell.
41 const NSInteger kHintXOffset = 4; 32 const NSInteger kHintXOffset = 4;
42 33
43 // How far to shift bounding box of hint down from top of field. 34 // How far to shift bounding box of hint down from top of field.
44 // Assumes -setFlipped:YES. 35 // Assumes -setFlipped:YES.
45 const NSInteger kHintYOffset = 4; 36 const NSInteger kHintYOffset = 4;
46 37
47 // How far to inset the keywork token from sides.
48 const NSInteger kKeywordYInset = 4;
49
50 // TODO(shess): The keyword hint image wants to sit on the baseline. 38 // TODO(shess): The keyword hint image wants to sit on the baseline.
51 // This moves it down so that there is approximately as much image 39 // This moves it down so that there is approximately as much image
52 // above the lowercase ascender as below the baseline. A better 40 // above the lowercase ascender as below the baseline. A better
53 // technique would be nice to have, though. 41 // technique would be nice to have, though.
54 const NSInteger kKeywordHintImageBaseline = -6; 42 const NSInteger kKeywordHintImageBaseline = -6;
55 43
56 // Drops the magnifying glass icon so that it looks centered in the
57 // keyword-search bubble.
58 const NSInteger kKeywordSearchImageBaseline = -5;
59
60 // The amount of padding on either side reserved for drawing an icon.
61 const NSInteger kIconHorizontalPad = 3;
62
63 // How far to shift bounding box of hint icon label down from top of field. 44 // How far to shift bounding box of hint icon label down from top of field.
64 const NSInteger kIconLabelYOffset = 7; 45 const NSInteger kIconLabelYOffset = 7;
65 46
66 // How far the editor insets itself, for purposes of determining if 47 // How far the editor insets itself, for purposes of determining if
67 // decorations need to be trimmed. 48 // decorations need to be trimmed.
68 const CGFloat kEditorHorizontalInset = 3.0; 49 const CGFloat kEditorHorizontalInset = 3.0;
69 50
70 // Cause the location icon to line up above the icons in the popup. 51 // How far to inset the left-hand decorations from the field's bounds.
71 const CGFloat kLocationIconXOffset = 6.0; 52 const CGFloat kLeftDecorationXOffset = 3.0;
72 const CGFloat kLocationIconXPad = 1.0; 53
54 // The amount of padding on either side reserved for drawing decorations.
55 const NSInteger kDecorationHorizontalPad = 3;
73 56
74 // How long to wait for mouse-up on the location icon before assuming 57 // How long to wait for mouse-up on the location icon before assuming
75 // that the user wants to drag. 58 // that the user wants to drag.
76 const NSTimeInterval kLocationIconDragTimeout = 0.25; 59 const NSTimeInterval kLocationIconDragTimeout = 0.25;
77 60
78 // Conveniences to centralize width+offset calculations. 61 // Conveniences to centralize width+offset calculations.
79 CGFloat WidthForHint(NSAttributedString* hintString) { 62 CGFloat WidthForHint(NSAttributedString* hintString) {
80 return kHintXOffset + ceil([hintString size].width); 63 return kHintXOffset + ceil([hintString size].width);
81 } 64 }
82 CGFloat WidthForKeyword(NSAttributedString* keywordString) {
83 return kKeywordXOffset + ceil([keywordString size].width) +
84 2 * kKeywordTokenInset;
85 }
86 65
87 // Convenience to draw |image| in the |rect| portion of |view|. 66 // Convenience to draw |image| in the |rect| portion of |view|.
88 void DrawImageInRect(NSImage* image, NSView* view, const NSRect& rect) { 67 void DrawImageInRect(NSImage* image, NSView* view, const NSRect& rect) {
89 // If there is an image, make sure we calculated the target size 68 // If there is an image, make sure we calculated the target size
90 // correctly. 69 // correctly.
91 DCHECK(!image || NSEqualSizes([image size], rect.size)); 70 DCHECK(!image || NSEqualSizes([image size], rect.size));
92 [image drawInRect:rect 71 [image drawInRect:rect
93 fromRect:NSZeroRect // Entire image 72 fromRect:NSZeroRect // Entire image
94 operation:NSCompositeSourceOver 73 operation:NSCompositeSourceOver
95 fraction:1.0 74 fraction:1.0
(...skipping 15 matching lines...) Expand all
111 scoped_nsobject<NSMutableAttributedString> as( 90 scoped_nsobject<NSMutableAttributedString> as(
112 [[NSAttributedString attributedStringWithAttachment:attachment] 91 [[NSAttributedString attributedStringWithAttachment:attachment]
113 mutableCopy]); 92 mutableCopy]);
114 [as addAttribute:NSBaselineOffsetAttributeName 93 [as addAttribute:NSBaselineOffsetAttributeName
115 value:[NSNumber numberWithFloat:baselineAdjustment] 94 value:[NSNumber numberWithFloat:baselineAdjustment]
116 range:NSMakeRange(0, [as length])]; 95 range:NSMakeRange(0, [as length])];
117 96
118 return [[as copy] autorelease]; 97 return [[as copy] autorelease];
119 } 98 }
120 99
100 // Helper function for calculating placement of decorations w/in the
101 // cell. |frame| is the cell's boundary rectangle.
102 // |left_decorations| is a set of decorations for the left-hand side
103 // of the cell, before the text. |decorations| will contain the
104 // resulting visible decorations, and |decoration_frames| will contain
105 // their frames in the same coordinates as |frame|. |remaining_frame|
106 // will contain the frame left over for the field editor.
107 void CalculatePositionsInFrame(
108 const NSRect cell_frame,
109 const std::vector<LocationBarDecoration*>& left_decorations,
110 std::vector<LocationBarDecoration*>* decorations,
111 std::vector<NSRect>* decoration_frames,
112 NSRect* remaining_frame) {
113 NSRect frame = cell_frame;
114
115 // The left-most decoration will be inset a bit further from the edge.
116 CGFloat left_padding = kLeftDecorationXOffset;
117
118 decorations->clear();
119 decoration_frames->clear();
120
121 for (size_t i = 0; i < left_decorations.size(); ++i) {
122 if (left_decorations[i]->IsVisible()) {
123 NSRect padding, available;
124
125 // Peel off the left-side padding.
126 NSDivideRect(frame, &padding, &available, left_padding, NSMinXEdge);
127
128 // Find out how large the decoration will be in the remaining
129 // space.
130 const CGFloat used_width =
131 left_decorations[i]->GetWidthForSpace(NSWidth(available));
132
133 if (used_width != LocationBarDecoration::kOmittedWidth) {
134 DCHECK_GT(used_width, 0.0);
135 NSRect decoration_frame;
136
137 // Peel off the desired width, leaving the remainder in
138 // |frame|.
139 NSDivideRect(available, &decoration_frame, &frame,
140 used_width, NSMinXEdge);
141
142 decorations->push_back(left_decorations[i]);
143 decoration_frames->push_back(decoration_frame);
144 DCHECK_EQ(decorations->size(), decoration_frames->size());
145
146 // Adjust padding for between decorations.
147 left_padding = kDecorationHorizontalPad;
148 }
149 }
150 }
151
152 *remaining_frame = frame;
153 DCHECK_EQ(decorations->size(), decoration_frames->size());
154 }
155
121 } // namespace 156 } // namespace
122 157
123 @implementation AutocompleteTextAttachmentCell 158 @implementation AutocompleteTextAttachmentCell
124 159
125 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView { 160 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView {
126 // Draw image with |DrawImageInRect()| to get consistent 161 // Draw image with |DrawImageInRect()| to get consistent
127 // flipped treatment. 162 // flipped treatment.
128 DrawImageInRect([self image], aView, cellFrame); 163 DrawImageInRect([self image], aView, cellFrame);
129 } 164 }
130 165
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 } else { 216 } else {
182 DrawImageInRect(view_->GetImage(), controlView, rect_); 217 DrawImageInRect(view_->GetImage(), controlView, rect_);
183 } 218 }
184 } 219 }
185 220
186 @end 221 @end
187 222
188 @implementation AutocompleteTextFieldCell 223 @implementation AutocompleteTextFieldCell
189 224
190 // @synthesize doesn't seem to compile for this transition. 225 // @synthesize doesn't seem to compile for this transition.
191 - (NSAttributedString*)keywordString {
192 return keywordString_.get();
193 }
194 - (NSAttributedString*)hintString { 226 - (NSAttributedString*)hintString {
195 return hintString_.get(); 227 return hintString_.get();
196 } 228 }
197 229
198 - (CGFloat)baselineAdjust { 230 - (CGFloat)baselineAdjust {
199 return kBaselineAdjust; 231 return kBaselineAdjust;
200 } 232 }
201 233
202 - (CGFloat)cornerRadius { 234 - (CGFloat)cornerRadius {
203 return kCornerRadius; 235 return kCornerRadius;
204 } 236 }
205 237
206 - (void)setKeywordString:(NSString*)fullString
207 partialString:(NSString*)partialString
208 availableWidth:(CGFloat)width {
209 DCHECK(fullString != nil);
210
211 hintString_.reset();
212
213 // Adjust for space between editor and decorations.
214 width -= 2 * kEditorHorizontalInset;
215
216 // Get the magnifying glass to put at the front of the string.
217 NSImage* image =
218 AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
219 const NSSize imageSize = [image size];
220
221 // Based on what fits, choose |fullString| with the image,
222 // |fullString| without the image, or |partialString|.
223 NSDictionary* attributes =
224 [NSDictionary dictionaryWithObject:[self font]
225 forKey:NSFontAttributeName];
226 NSString* s = fullString;
227 const CGFloat sWidth = [s sizeWithAttributes:attributes].width;
228 if (sWidth + imageSize.width > width) {
229 image = nil;
230 }
231 if (sWidth > width) {
232 if (partialString) {
233 s = partialString;
234 }
235 }
236
237 scoped_nsobject<NSMutableAttributedString> as(
238 [[NSMutableAttributedString alloc] initWithString:s
239 attributes:attributes]);
240
241 // Insert the image at the front of the string if it didn't make
242 // things too wide.
243 if (image) {
244 NSAttributedString* is =
245 AttributedStringForImage(image, kKeywordSearchImageBaseline);
246 [as insertAttributedString:is atIndex:0];
247 }
248
249 keywordString_.reset([as copy]);
250 }
251
252 // Convenience for the attributes used in the right-justified info 238 // Convenience for the attributes used in the right-justified info
253 // cells. 239 // cells.
254 - (NSDictionary*)hintAttributes { 240 - (NSDictionary*)hintAttributes {
255 scoped_nsobject<NSMutableParagraphStyle> style( 241 scoped_nsobject<NSMutableParagraphStyle> style(
256 [[NSMutableParagraphStyle alloc] init]); 242 [[NSMutableParagraphStyle alloc] init]);
257 [style setAlignment:NSRightTextAlignment]; 243 [style setAlignment:NSRightTextAlignment];
258 244
259 return [NSDictionary dictionaryWithObjectsAndKeys: 245 return [NSDictionary dictionaryWithObjectsAndKeys:
260 [self font], NSFontAttributeName, 246 [self font], NSFontAttributeName,
261 [NSColor lightGrayColor], NSForegroundColorAttributeName, 247 [NSColor lightGrayColor], NSForegroundColorAttributeName,
262 style.get(), NSParagraphStyleAttributeName, 248 style.get(), NSParagraphStyleAttributeName,
263 nil]; 249 nil];
264 } 250 }
265 251
266 - (void)setKeywordHintPrefix:(NSString*)prefixString 252 - (void)setKeywordHintPrefix:(NSString*)prefixString
267 image:(NSImage*)anImage 253 image:(NSImage*)anImage
268 suffix:(NSString*)suffixString 254 suffix:(NSString*)suffixString
269 availableWidth:(CGFloat)width { 255 availableWidth:(CGFloat)width {
270 DCHECK(prefixString != nil); 256 DCHECK(prefixString != nil);
271 DCHECK(anImage != nil); 257 DCHECK(anImage != nil);
272 DCHECK(suffixString != nil); 258 DCHECK(suffixString != nil);
273 259
274 keywordString_.reset();
275
276 // Adjust for space between editor and decorations. 260 // Adjust for space between editor and decorations.
277 width -= 2 * kEditorHorizontalInset; 261 width -= 2 * kEditorHorizontalInset;
278 262
279 // If |hintString_| is now too wide, clear it so that we don't pass 263 // If |hintString_| is now too wide, clear it so that we don't pass
280 // the equality tests. 264 // the equality tests.
281 if (hintString_ && WidthForHint(hintString_) > width) { 265 if (hintString_ && WidthForHint(hintString_) > width) {
282 [self clearKeywordAndHint]; 266 [self clearHint];
283 } 267 }
284 268
285 // TODO(shess): Also check the length? 269 // TODO(shess): Also check the length?
286 if (![[hintString_ string] hasPrefix:prefixString] || 270 if (![[hintString_ string] hasPrefix:prefixString] ||
287 ![[hintString_ string] hasSuffix:suffixString]) { 271 ![[hintString_ string] hasSuffix:suffixString]) {
288 272
289 // Build an attributed string with the concatenation of the prefix 273 // Build an attributed string with the concatenation of the prefix
290 // and suffix. 274 // and suffix.
291 NSString* s = [prefixString stringByAppendingString:suffixString]; 275 NSString* s = [prefixString stringByAppendingString:suffixString];
292 scoped_nsobject<NSMutableAttributedString> as( 276 scoped_nsobject<NSMutableAttributedString> as(
(...skipping 12 matching lines...) Expand all
305 } 289 }
306 } 290 }
307 291
308 - (void)setSearchHintString:(NSString*)aString 292 - (void)setSearchHintString:(NSString*)aString
309 availableWidth:(CGFloat)width { 293 availableWidth:(CGFloat)width {
310 DCHECK(aString != nil); 294 DCHECK(aString != nil);
311 295
312 // Adjust for space between editor and decorations. 296 // Adjust for space between editor and decorations.
313 width -= 2 * kEditorHorizontalInset; 297 width -= 2 * kEditorHorizontalInset;
314 298
315 keywordString_.reset();
316
317 // If |hintString_| is now too wide, clear it so that we don't pass 299 // If |hintString_| is now too wide, clear it so that we don't pass
318 // the equality tests. 300 // the equality tests.
319 if (hintString_ && WidthForHint(hintString_) > width) { 301 if (hintString_ && WidthForHint(hintString_) > width) {
320 [self clearKeywordAndHint]; 302 [self clearHint];
321 } 303 }
322 304
323 if (![[hintString_ string] isEqualToString:aString]) { 305 if (![[hintString_ string] isEqualToString:aString]) {
324 scoped_nsobject<NSAttributedString> as( 306 scoped_nsobject<NSAttributedString> as(
325 [[NSAttributedString alloc] initWithString:aString 307 [[NSAttributedString alloc] initWithString:aString
326 attributes:[self hintAttributes]]); 308 attributes:[self hintAttributes]]);
327 309
328 // If too wide, don't keep the hint. 310 // If too wide, don't keep the hint.
329 hintString_.reset(WidthForHint(as) > width ? nil : [as copy]); 311 hintString_.reset(WidthForHint(as) > width ? nil : [as copy]);
330 } 312 }
331 } 313 }
332 314
333 - (void)clearKeywordAndHint { 315 - (void)clearHint {
334 keywordString_.reset();
335 hintString_.reset(); 316 hintString_.reset();
336 } 317 }
337 318
338 - (void)setPageActionViewList:(LocationBarViewMac::PageActionViewList*)list { 319 - (void)setPageActionViewList:(LocationBarViewMac::PageActionViewList*)list {
339 page_action_views_ = list; 320 page_action_views_ = list;
340 } 321 }
341 322
342 - (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view {
343 locationIconView_ = view;
344 }
345
346 - (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view { 323 - (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view {
347 starIconView_ = view; 324 starIconView_ = view;
348 } 325 }
349 326
350 - (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view {
351 securityLabelView_ = view;
352 }
353
354 - (void)setContentSettingViewsList: 327 - (void)setContentSettingViewsList:
355 (LocationBarViewMac::ContentSettingViews*)views { 328 (LocationBarViewMac::ContentSettingViews*)views {
356 content_setting_views_ = views; 329 content_setting_views_ = views;
357 } 330 }
358 331
332 - (void)clearDecorations {
333 leftDecorations_.clear();
334 }
335
336 - (void)addLeftDecoration:(LocationBarDecoration*)decoration {
337 leftDecorations_.push_back(decoration);
338 }
339
340 - (CGFloat)availableWidthInFrame:(const NSRect)frame {
341 std::vector<LocationBarDecoration*> decorations;
342 std::vector<NSRect> decorationFrames;
343 NSRect textFrame;
344 CalculatePositionsInFrame(frame, leftDecorations_,
345 &decorations, &decorationFrames, &textFrame);
346
347 return NSWidth(textFrame);
348 }
349
350 - (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
351 inFrame:(NSRect)cellFrame {
352 // Short-circuit if the decoration is known to be not visible.
353 if (aDecoration && !aDecoration->IsVisible())
354 return NSZeroRect;
355
356 // Layout the decorations.
357 std::vector<LocationBarDecoration*> decorations;
358 std::vector<NSRect> decorationFrames;
359 NSRect textFrame;
360 CalculatePositionsInFrame(cellFrame, leftDecorations_,
361 &decorations, &decorationFrames, &textFrame);
362
363 // Find our decoration and return the corresponding frame.
364 std::vector<LocationBarDecoration*>::const_iterator iter =
365 std::find(decorations.begin(), decorations.end(), aDecoration);
366 if (iter != decorations.end()) {
367 const size_t index = iter - decorations.begin();
368 return decorationFrames[index];
369 }
370
371 // Decorations which are not visible should have been filtered out
372 // at the top, but return |NSZeroRect| rather than a 0-width rect
373 // for consistency.
374 NOTREACHED();
375 return NSZeroRect;
376 }
377
359 // Overriden to account for the hint strings and hint icons. 378 // Overriden to account for the hint strings and hint icons.
360 - (NSRect)textFrameForFrame:(NSRect)cellFrame { 379 - (NSRect)textFrameForFrame:(NSRect)cellFrame {
361 NSRect textFrame([super textFrameForFrame:cellFrame]); 380 // Get the frame adjusted for decorations.
381 std::vector<LocationBarDecoration*> decorations;
382 std::vector<NSRect> decorationFrames;
383 NSRect textFrame = [super textFrameForFrame:cellFrame];
384 CalculatePositionsInFrame(textFrame, leftDecorations_,
385 &decorations, &decorationFrames, &textFrame);
362 386
363 // NOTE: This function must closely match the logic in 387 // NOTE: This function must closely match the logic in
364 // |-drawInteriorWithFrame:inView:|. 388 // |-drawInteriorWithFrame:inView:|.
365 389
366 // Location icon is not shown in keyword search mode.
367 if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) {
368 const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame];
369 const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad;
370 textFrame.size.width = NSMaxX(textFrame) - newOrigin;
371 textFrame.origin.x = newOrigin;
372 }
373
374 // Leave room for items on the right (SSL label, page actions, etc). 390 // Leave room for items on the right (SSL label, page actions, etc).
375 // Icons are laid out in |cellFrame| rather than |textFrame| for 391 // Icons are laid out in |cellFrame| rather than |textFrame| for
376 // consistency with drawing code. 392 // consistency with drawing code.
377 NSArray* icons = [self layedOutIcons:cellFrame]; 393 NSArray* icons = [self layedOutIcons:cellFrame];
378 if ([icons count]) { 394 if ([icons count]) {
379 // Max x for resulting text frame. 395 // Max x for resulting text frame.
380 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); 396 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]);
381 textFrame.size.width = maxX - NSMinX(textFrame); 397 textFrame.size.width = maxX - NSMinX(textFrame);
382 } 398 }
383 399
384 // Keyword string or hint string if they fit. 400 // Keyword string or hint string if they fit.
385 if (keywordString_) { 401 if (hintString_) {
386 DCHECK(!hintString_);
387 const CGFloat keywordWidth(WidthForKeyword(keywordString_));
388
389 if (keywordWidth < NSWidth(textFrame)) {
390 textFrame.origin.x += keywordWidth;
391 textFrame.size.width -= keywordWidth;
392 }
393 } else if (hintString_) {
394 DCHECK(!keywordString_);
395 const CGFloat hintWidth(WidthForHint(hintString_)); 402 const CGFloat hintWidth(WidthForHint(hintString_));
396 403
397 // TODO(shess): This could be better. Show the hint until the 404 // TODO(shess): This could be better. Show the hint until the
398 // non-hint text bumps against it? 405 // non-hint text bumps against it?
399 if (hintWidth < NSWidth(textFrame)) { 406 if (hintWidth < NSWidth(textFrame)) {
400 textFrame.size.width -= hintWidth; 407 textFrame.size.width -= hintWidth;
401 } 408 }
402 } 409 }
403 410
404 // SSL label if it fits.
405 if (securityLabelView_ && securityLabelView_->IsVisible() &&
406 securityLabelView_->GetLabel()) {
407 NSAttributedString* label = securityLabelView_->GetLabel();
408 const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad;
409 if (NSWidth(textFrame) > labelWidth) {
410 textFrame.size.width -= labelWidth;
411 }
412 }
413
414 return textFrame; 411 return textFrame;
415 } 412 }
416 413
417 - (NSRect)locationIconFrameForFrame:(NSRect)cellFrame {
418 if (!locationIconView_ || !locationIconView_->IsVisible())
419 return NSZeroRect;
420
421 const NSSize imageSize = locationIconView_->GetImageSize();
422 const CGFloat yOffset = floor((NSHeight(cellFrame) - imageSize.height) / 2);
423 return NSMakeRect(NSMinX(cellFrame) + kLocationIconXOffset,
424 NSMinY(cellFrame) + yOffset,
425 imageSize.width, imageSize.height);
426 }
427
428 - (NSRect)starIconFrameForFrame:(NSRect)cellFrame { 414 - (NSRect)starIconFrameForFrame:(NSRect)cellFrame {
429 if (!starIconView_ || !starIconView_->IsVisible()) 415 if (!starIconView_ || !starIconView_->IsVisible())
430 return NSZeroRect; 416 return NSZeroRect;
431 417
432 // The star icon is always at the RHS. 418 // The star icon is always at the RHS.
433 scoped_nsobject<AutocompleteTextFieldIcon> icon( 419 scoped_nsobject<AutocompleteTextFieldIcon> icon(
434 [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]); 420 [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]);
435 cellFrame.size.width -= kHintXOffset; 421 cellFrame.size.width -= kHintXOffset;
436 [icon positionInFrame:cellFrame]; 422 [icon positionInFrame:cellFrame];
437 return [icon rect]; 423 return [icon rect];
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 DCHECK(hintString_); 465 DCHECK(hintString_);
480 466
481 NSRect textFrame = [self textFrameForFrame:cellFrame]; 467 NSRect textFrame = [self textFrameForFrame:cellFrame];
482 NSRect infoFrame(NSMakeRect(NSMaxX(textFrame), 468 NSRect infoFrame(NSMakeRect(NSMaxX(textFrame),
483 cellFrame.origin.y + kHintYOffset, 469 cellFrame.origin.y + kHintYOffset,
484 ceil([hintString_ size].width), 470 ceil([hintString_ size].width),
485 cellFrame.size.height - kHintYOffset)); 471 cellFrame.size.height - kHintYOffset));
486 [hintString_.get() drawInRect:infoFrame]; 472 [hintString_.get() drawInRect:infoFrame];
487 } 473 }
488 474
489 - (void)drawKeywordWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { 475 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
490 DCHECK(keywordString_); 476 std::vector<LocationBarDecoration*> decorations;
477 std::vector<NSRect> decorationFrames;
478 NSRect workingFrame;
479 CalculatePositionsInFrame(cellFrame, leftDecorations_,
480 &decorations, &decorationFrames, &workingFrame);
491 481
492 NSRect textFrame = [self textFrameForFrame:cellFrame]; 482 // Draw the decorations first.
493 const CGFloat x = NSMinX(cellFrame) + kKeywordXOffset; 483 for (size_t i = 0; i < decorations.size(); ++i) {
494 NSRect infoFrame(NSMakeRect(x, 484 if (decorations[i])
495 cellFrame.origin.y + kKeywordYInset, 485 decorations[i]->DrawInFrame(decorationFrames[i], controlView);
496 NSMinX(textFrame) - x, 486 }
497 cellFrame.size.height - 2 * kKeywordYInset));
498
499 // Draw the token rectangle with rounded corners.
500 NSRect frame(NSInsetRect(infoFrame, 0.5, 0.5));
501 NSBezierPath* path =
502 [NSBezierPath bezierPathWithRoundedRect:frame xRadius:4.0 yRadius:4.0];
503
504 // Matches the color of the highlighted line in the popup.
505 [[NSColor selectedControlColor] set];
506 [path fill];
507
508 // Border around token rectangle, match focus ring's inner color.
509 [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5] set];
510 [path setLineWidth:1.0];
511 [path stroke];
512
513 // Draw text w/in the rectangle.
514 infoFrame.origin.x += 3.0;
515 [keywordString_.get() drawInRect:infoFrame];
516 }
517
518 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
519 NSRect workingFrame = cellFrame;
520 487
521 // NOTE: This function must closely match the logic in 488 // NOTE: This function must closely match the logic in
522 // |-textFrameForFrame:|. 489 // |-textFrameForFrame:|.
523 490
524 // Location icon is not shown in keyword search mode.
525 if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) {
526 const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame];
527 DrawImageInRect(locationIconView_->GetImage(), controlView, iconFrame);
528 const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad;
529 workingFrame.size.width = NSMaxX(workingFrame) - newOrigin;
530 workingFrame.origin.x = newOrigin;
531 }
532
533 NSArray* icons = [self layedOutIcons:cellFrame]; 491 NSArray* icons = [self layedOutIcons:cellFrame];
534 for (AutocompleteTextFieldIcon* icon in icons) { 492 for (AutocompleteTextFieldIcon* icon in icons) {
535 [icon drawInView:controlView]; 493 [icon drawInView:controlView];
536 } 494 }
537 if ([icons count]) { 495 if ([icons count]) {
538 // Max x for resulting text frame. 496 // Max x for resulting text frame.
539 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); 497 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]);
540 workingFrame.size.width = maxX - NSMinX(workingFrame); 498 workingFrame.size.width = maxX - NSMinX(workingFrame);
541 } 499 }
542 500
543 // Keyword string or hint string if they fit. 501 // Keyword string or hint string if they fit.
544 if (keywordString_) { 502 if (hintString_) {
545 DCHECK(!hintString_);
546 const CGFloat keywordWidth(WidthForKeyword(keywordString_));
547
548 if (keywordWidth < NSWidth(workingFrame)) {
549 [self drawKeywordWithFrame:cellFrame inView:controlView];
550 workingFrame.origin.x += keywordWidth;
551 workingFrame.size.width -= keywordWidth;
552 }
553 } else if (hintString_) {
554 DCHECK(!keywordString_);
555 const CGFloat hintWidth(WidthForHint(hintString_)); 503 const CGFloat hintWidth(WidthForHint(hintString_));
556 504
557 // TODO(shess): This could be better. Show the hint until the 505 // TODO(shess): This could be better. Show the hint until the
558 // non-hint text bumps against it? 506 // non-hint text bumps against it?
559 if (hintWidth < NSWidth(workingFrame)) { 507 if (hintWidth < NSWidth(workingFrame)) {
560 [self drawHintWithFrame:cellFrame inView:controlView]; 508 [self drawHintWithFrame:cellFrame inView:controlView];
561 workingFrame.size.width -= hintWidth; 509 workingFrame.size.width -= hintWidth;
562 } 510 }
563 } 511 }
564 512
565 // SSL label if it fits.
566 if (securityLabelView_ && securityLabelView_->IsVisible() &&
567 securityLabelView_->GetLabel()) {
568 NSAttributedString* label = securityLabelView_->GetLabel();
569 const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad;
570 if (NSWidth(workingFrame) > labelWidth) {
571 workingFrame.size.width -= kIconHorizontalPad;
572
573 scoped_nsobject<AutocompleteTextFieldIcon> icon(
574 [[AutocompleteTextFieldIcon alloc]
575 initLabelWithView:securityLabelView_]);
576 [icon positionInFrame:workingFrame];
577 [icon drawInView:controlView];
578 DCHECK_EQ(labelWidth, NSWidth([icon rect]) + kIconHorizontalPad);
579 workingFrame.size.width -= NSWidth([icon rect]);
580 }
581 }
582
583 // Superclass draws text portion WRT original |cellFrame|. 513 // Superclass draws text portion WRT original |cellFrame|.
584 [super drawInteriorWithFrame:cellFrame inView:controlView]; 514 [super drawInteriorWithFrame:cellFrame inView:controlView];
585 } 515 }
586 516
587 - (NSArray*)layedOutIcons:(NSRect)cellFrame { 517 - (NSArray*)layedOutIcons:(NSRect)cellFrame {
588 // The set of views to display right-justified in the cell, from 518 // The set of views to display right-justified in the cell, from
589 // left to right. 519 // left to right.
590 NSMutableArray* result = [NSMutableArray array]; 520 NSMutableArray* result = [NSMutableArray array];
591 521
592 // Collect the image views for bulk processing. 522 // Collect the image views for bulk processing.
(...skipping 30 matching lines...) Expand all
623 } 553 }
624 554
625 // Leave a boundary at RHS of field. 555 // Leave a boundary at RHS of field.
626 cellFrame.size.width -= kHintXOffset; 556 cellFrame.size.width -= kHintXOffset;
627 557
628 // Position each view within the frame from right to left. 558 // Position each view within the frame from right to left.
629 for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) { 559 for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) {
630 [icon positionInFrame:cellFrame]; 560 [icon positionInFrame:cellFrame];
631 561
632 // Trim the icon's space from the frame. 562 // Trim the icon's space from the frame.
633 cellFrame.size.width = NSMinX([icon rect]) - kIconHorizontalPad; 563 cellFrame.size.width = NSMinX([icon rect]) - kDecorationHorizontalPad;
634 } 564 }
635 return result; 565 return result;
636 } 566 }
637 567
568 // Returns the decoration under |theEvent|, or NULL if none.
569 // Like |-iconForEvent:inRect:ofView:|, but for decorations.
570 - (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
571 inRect:(NSRect)cellFrame
572 ofView:(AutocompleteTextField*)controlView
573 {
574 const BOOL flipped = [controlView isFlipped];
575 const NSPoint location =
576 [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
577
578 std::vector<LocationBarDecoration*> decorations;
579 std::vector<NSRect> decorationFrames;
580 NSRect textFrame;
581 CalculatePositionsInFrame(cellFrame, leftDecorations_,
582 &decorations, &decorationFrames, &textFrame);
583
584 for (size_t i = 0; i < decorations.size(); ++i) {
585 if (NSMouseInRect(location, decorationFrames[i], flipped))
586 return decorations[i];
587 }
588
589 return NULL;
590 }
591
638 - (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent 592 - (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent
639 inRect:(NSRect)cellFrame 593 inRect:(NSRect)cellFrame
640 ofView:(AutocompleteTextField*)controlView { 594 ofView:(AutocompleteTextField*)controlView {
641 const BOOL flipped = [controlView isFlipped]; 595 const BOOL flipped = [controlView isFlipped];
642 const NSPoint location = 596 const NSPoint location =
643 [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; 597 [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
644 598
645 // Special check for location image, it is not in |-layedOutIcons:|.
646 const NSRect locationIconFrame = [self locationIconFrameForFrame:cellFrame];
647 if (NSMouseInRect(location, locationIconFrame, flipped)) {
648 // Make up an icon to return.
649 AutocompleteTextFieldIcon* icon =
650 [[[AutocompleteTextFieldIcon alloc]
651 initImageWithView:locationIconView_] autorelease];
652 [icon setRect:locationIconFrame];
653 return icon;
654 }
655
656 for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { 599 for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) {
657 if (NSMouseInRect(location, [icon rect], flipped)) 600 if (NSMouseInRect(location, [icon rect], flipped))
658 return icon; 601 return icon;
659 } 602 }
660 603
661 return nil; 604 return nil;
662 } 605 }
663 606
664 - (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent 607 - (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent
665 inRect:(NSRect)cellFrame 608 inRect:(NSRect)cellFrame
666 ofView:(AutocompleteTextField*)controlView { 609 ofView:(AutocompleteTextField*)controlView {
610 LocationBarDecoration* decoration =
611 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
612 if (decoration)
613 return decoration->GetMenu();
614
667 AutocompleteTextFieldIcon* 615 AutocompleteTextFieldIcon*
668 icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; 616 icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView];
669 if (icon) 617 if (icon)
670 return [icon view]->GetMenu(); 618 return [icon view]->GetMenu();
671 return nil; 619 return nil;
672 } 620 }
673 621
674 - (BOOL)mouseDown:(NSEvent*)theEvent 622 - (BOOL)mouseDown:(NSEvent*)theEvent
675 inRect:(NSRect)cellFrame 623 inRect:(NSRect)cellFrame
676 ofView:(AutocompleteTextField*)controlView { 624 ofView:(AutocompleteTextField*)controlView {
625 LocationBarDecoration* decoration =
626 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
677 AutocompleteTextFieldIcon* icon = 627 AutocompleteTextFieldIcon* icon =
678 [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; 628 [self iconForEvent:theEvent inRect:cellFrame ofView:controlView];
679 if (!icon) 629 if (!decoration && !icon)
680 return NO; 630 return NO;
681 631
632 NSRect decorationRect = NSZeroRect;
633 if (icon) {
634 decorationRect = [icon rect];
635 } else if (decoration) {
636 decorationRect = [self frameForDecoration:decoration inFrame:cellFrame];
637 }
638
682 // If the icon is draggable, then initiate a drag if the user drags 639 // If the icon is draggable, then initiate a drag if the user drags
683 // or holds the mouse down for awhile. 640 // or holds the mouse down for awhile.
684 if ([icon view]->IsDraggable()) { 641 if ((icon && [icon view]->IsDraggable()) ||
642 (decoration && decoration->IsDraggable())) {
643 DCHECK(icon || decoration);
685 NSDate* timeout = 644 NSDate* timeout =
686 [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; 645 [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout];
687 NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | 646 NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
688 NSLeftMouseUpMask) 647 NSLeftMouseUpMask)
689 untilDate:timeout 648 untilDate:timeout
690 inMode:NSEventTrackingRunLoopMode 649 inMode:NSEventTrackingRunLoopMode
691 dequeue:YES]; 650 dequeue:YES];
692 if (!event || [event type] == NSLeftMouseDragged) { 651 if (!event || [event type] == NSLeftMouseDragged) {
693 NSPasteboard* pboard = [icon view]->GetDragPasteboard(); 652 NSPasteboard* pboard;
653 if (icon) pboard = [icon view]->GetDragPasteboard();
654 if (decoration) pboard = decoration->GetDragPasteboard();
694 DCHECK(pboard); 655 DCHECK(pboard);
695 656
696 // TODO(shess): My understanding is that the -isFlipped 657 // TODO(shess): My understanding is that the -isFlipped
697 // adjustment should not be necessary. But without it, the 658 // adjustment should not be necessary. But without it, the
698 // image is nowhere near the cursor. Perhaps the icon's rect is 659 // image is nowhere near the cursor. Perhaps the icon's rect is
699 // incorrectly calculated? 660 // incorrectly calculated?
700 // http://crbug.com/40711 661 // http://crbug.com/40711
701 NSPoint dragPoint = [icon rect].origin; 662 NSPoint dragPoint = decorationRect.origin;
702 if ([controlView isFlipped]) 663 if ([controlView isFlipped])
703 dragPoint.y += NSHeight([icon rect]); 664 dragPoint.y += NSHeight(decorationRect);
704 665
705 [controlView dragImage:[icon view]->GetImage() 666 NSImage* image;
667 if (icon) image = [icon view]->GetImage();
668 if (decoration) image = decoration->GetDragImage();
669 [controlView dragImage:image
706 at:dragPoint 670 at:dragPoint
707 offset:NSZeroSize 671 offset:NSZeroSize
708 event:event ? event : theEvent 672 event:event ? event : theEvent
709 pasteboard:pboard 673 pasteboard:pboard
710 source:self 674 source:self
711 slideBack:YES]; 675 slideBack:YES];
712 return YES; 676 return YES;
713 } 677 }
714 678
715 // On mouse-up fall through to mouse-pressed case. 679 // On mouse-up fall through to mouse-pressed case.
716 DCHECK_EQ([event type], NSLeftMouseUp); 680 DCHECK_EQ([event type], NSLeftMouseUp);
717 } 681 }
718 682
719 [icon view]->OnMousePressed([icon rect]); 683 if (icon) {
684 [icon view]->OnMousePressed(decorationRect);
685 } else if (decoration) {
686 if (!decoration->OnMousePressed(decorationRect))
687 return NO;
688 }
689
720 return YES; 690 return YES;
721 } 691 }
722 692
723 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { 693 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
724 return NSDragOperationCopy; 694 return NSDragOperationCopy;
725 } 695 }
726 696
727 - (NSPasteboard*)locationDragPasteboard {
728 if (locationIconView_ && locationIconView_->IsDraggable())
729 return locationIconView_->GetDragPasteboard();
730
731 return nil;
732 }
733
734 @end 697 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698