| OLD | NEW |
| 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/autocomplete_text_field_cell.h" | 5 #import "chrome/browser/cocoa/autocomplete_text_field_cell.h" |
| 6 | 6 |
| 7 #include "app/resource_bundle.h" | 7 #include "app/resource_bundle.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "gfx/font.h" | 9 #include "gfx/font.h" |
| 10 #include "grit/theme_resources.h" |
| 10 | 11 |
| 11 namespace { | 12 namespace { |
| 12 | 13 |
| 13 const CGFloat kBaselineAdjust = 2.0; | 14 const CGFloat kBaselineAdjust = 2.0; |
| 14 | 15 |
| 15 // How far to offset the keyword token into the field. | 16 // How far to offset the keyword token into the field. |
| 16 const NSInteger kKeywordXOffset = 3; | 17 const NSInteger kKeywordXOffset = 3; |
| 17 | 18 |
| 18 // How much width (beyond text) to add to the keyword token on each | 19 // How much width (beyond text) to add to the keyword token on each |
| 19 // side. | 20 // side. |
| 20 const NSInteger kKeywordTokenInset = 3; | 21 const NSInteger kKeywordTokenInset = 3; |
| 21 | 22 |
| 22 // Gap to leave between hint and right-hand-side of cell. | 23 // Gap to leave between hint and right-hand-side of cell. |
| 23 const NSInteger kHintXOffset = 4; | 24 const NSInteger kHintXOffset = 4; |
| 24 | 25 |
| 25 // How far to shift bounding box of hint down from top of field. | 26 // How far to shift bounding box of hint down from top of field. |
| 26 // Assumes -setFlipped:YES. | 27 // Assumes -setFlipped:YES. |
| 27 const NSInteger kHintYOffset = 4; | 28 const NSInteger kHintYOffset = 4; |
| 28 | 29 |
| 29 // How far to inset the keywork token from sides. | 30 // How far to inset the keywork token from sides. |
| 30 const NSInteger kKeywordYInset = 4; | 31 const NSInteger kKeywordYInset = 4; |
| 31 | 32 |
| 32 // TODO(shess): The keyword hint image wants to sit on the baseline. | 33 // TODO(shess): The keyword hint image wants to sit on the baseline. |
| 33 // This moves it down so that there is approximately as much image | 34 // This moves it down so that there is approximately as much image |
| 34 // above the lowercase ascender as below the baseline. A better | 35 // above the lowercase ascender as below the baseline. A better |
| 35 // technique would be nice to have, though. | 36 // technique would be nice to have, though. |
| 36 const NSInteger kKeywordHintImageBaseline = -6; | 37 const NSInteger kKeywordHintImageBaseline = -6; |
| 37 | 38 |
| 39 // Drops the magnifying glass icon so that it looks centered in the |
| 40 // keyword-search bubble. |
| 41 const NSInteger kKeywordSearchImageBaseline = -4; |
| 42 |
| 38 // The amount of padding on either side reserved for drawing an icon. | 43 // The amount of padding on either side reserved for drawing an icon. |
| 39 const NSInteger kIconHorizontalPad = 3; | 44 const NSInteger kIconHorizontalPad = 3; |
| 40 | 45 |
| 41 // How far to shift bounding box of hint icon label down from top of field. | 46 // How far to shift bounding box of hint icon label down from top of field. |
| 42 const NSInteger kIconLabelYOffset = 7; | 47 const NSInteger kIconLabelYOffset = 7; |
| 43 | 48 |
| 44 // How far the editor insets itself, for purposes of determining if | 49 // How far the editor insets itself, for purposes of determining if |
| 45 // decorations need to be trimmed. | 50 // decorations need to be trimmed. |
| 46 const CGFloat kEditorHorizontalInset = 3.0; | 51 const CGFloat kEditorHorizontalInset = 3.0; |
| 47 | 52 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 63 // 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 |
| 64 // correctly. | 69 // correctly. |
| 65 DCHECK(!image || NSEqualSizes([image size], rect.size)); | 70 DCHECK(!image || NSEqualSizes([image size], rect.size)); |
| 66 [image setFlipped:[view isFlipped]]; | 71 [image setFlipped:[view isFlipped]]; |
| 67 [image drawInRect:rect | 72 [image drawInRect:rect |
| 68 fromRect:NSZeroRect // Entire image | 73 fromRect:NSZeroRect // Entire image |
| 69 operation:NSCompositeSourceOver | 74 operation:NSCompositeSourceOver |
| 70 fraction:1.0]; | 75 fraction:1.0]; |
| 71 } | 76 } |
| 72 | 77 |
| 78 // Helper function to generate an attributed string containing |
| 79 // |anImage|. If |baselineAdjustment| is 0, the image sits on the |
| 80 // text baseline, positive values shift it up, negative values shift |
| 81 // it down. |
| 82 NSAttributedString* AttributedStringForImage(NSImage* anImage, |
| 83 CGFloat baselineAdjustment) { |
| 84 scoped_nsobject<NSTextAttachmentCell> attachmentCell( |
| 85 [[NSTextAttachmentCell alloc] initImageCell:anImage]); |
| 86 scoped_nsobject<NSTextAttachment> attachment( |
| 87 [[NSTextAttachment alloc] init]); |
| 88 [attachment setAttachmentCell:attachmentCell]; |
| 89 |
| 90 scoped_nsobject<NSMutableAttributedString> as( |
| 91 [[NSAttributedString attributedStringWithAttachment:attachment] |
| 92 mutableCopy]); |
| 93 [as addAttribute:NSBaselineOffsetAttributeName |
| 94 value:[NSNumber numberWithFloat:baselineAdjustment] |
| 95 range:NSMakeRange(0, [as length])]; |
| 96 |
| 97 return [[as copy] autorelease]; |
| 98 } |
| 99 |
| 73 } // namespace | 100 } // namespace |
| 74 | 101 |
| 75 @implementation AutocompleteTextFieldIcon | 102 @implementation AutocompleteTextFieldIcon |
| 76 | 103 |
| 77 @synthesize rect = rect_; | 104 @synthesize rect = rect_; |
| 78 @synthesize view = view_; | 105 @synthesize view = view_; |
| 79 | 106 |
| 80 // Private helper. | 107 // Private helper. |
| 81 - (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view | 108 - (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view |
| 82 isLabel:(BOOL)isLabel { | 109 isLabel:(BOOL)isLabel { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 - (void)setKeywordString:(NSString*)fullString | 171 - (void)setKeywordString:(NSString*)fullString |
| 145 partialString:(NSString*)partialString | 172 partialString:(NSString*)partialString |
| 146 availableWidth:(CGFloat)width { | 173 availableWidth:(CGFloat)width { |
| 147 DCHECK(fullString != nil); | 174 DCHECK(fullString != nil); |
| 148 | 175 |
| 149 hintString_.reset(); | 176 hintString_.reset(); |
| 150 | 177 |
| 151 // Adjust for space between editor and decorations. | 178 // Adjust for space between editor and decorations. |
| 152 width -= 2 * kEditorHorizontalInset; | 179 width -= 2 * kEditorHorizontalInset; |
| 153 | 180 |
| 154 // If |fullString| won't fit, choose |partialString|. | 181 // Get the magnifying glass to put at the front of the string. |
| 182 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 183 NSImage* image = rb.GetNSImageNamed(IDR_O2_SEARCH); |
| 184 const NSSize imageSize = [image size]; |
| 185 |
| 186 // Based on what fits, choose |fullString| with the image, |
| 187 // |fullString| without the image, or |partialString|. |
| 155 NSDictionary* attributes = | 188 NSDictionary* attributes = |
| 156 [NSDictionary dictionaryWithObject:[self font] | 189 [NSDictionary dictionaryWithObject:[self font] |
| 157 forKey:NSFontAttributeName]; | 190 forKey:NSFontAttributeName]; |
| 158 NSString* s = fullString; | 191 NSString* s = fullString; |
| 159 if ([s sizeWithAttributes:attributes].width > width) { | 192 const CGFloat sWidth = [s sizeWithAttributes:attributes].width; |
| 193 if (sWidth + imageSize.width > width) { |
| 194 image = nil; |
| 195 } |
| 196 if (sWidth > width) { |
| 160 if (partialString) { | 197 if (partialString) { |
| 161 s = partialString; | 198 s = partialString; |
| 162 } | 199 } |
| 163 } | 200 } |
| 164 keywordString_.reset( | 201 |
| 165 [[NSAttributedString alloc] initWithString:s attributes:attributes]); | 202 scoped_nsobject<NSMutableAttributedString> as( |
| 203 [[NSMutableAttributedString alloc] initWithString:s |
| 204 attributes:attributes]); |
| 205 |
| 206 // Insert the image at the front of the string if it didn't make |
| 207 // things too wide. |
| 208 if (image) { |
| 209 NSAttributedString* is = |
| 210 AttributedStringForImage(image, kKeywordSearchImageBaseline); |
| 211 [as insertAttributedString:is atIndex:0]; |
| 212 } |
| 213 |
| 214 keywordString_.reset([as copy]); |
| 166 } | 215 } |
| 167 | 216 |
| 168 // Convenience for the attributes used in the right-justified info | 217 // Convenience for the attributes used in the right-justified info |
| 169 // cells. | 218 // cells. |
| 170 - (NSDictionary*)hintAttributes { | 219 - (NSDictionary*)hintAttributes { |
| 171 scoped_nsobject<NSMutableParagraphStyle> style( | 220 scoped_nsobject<NSMutableParagraphStyle> style( |
| 172 [[NSMutableParagraphStyle alloc] init]); | 221 [[NSMutableParagraphStyle alloc] init]); |
| 173 [style setAlignment:NSRightTextAlignment]; | 222 [style setAlignment:NSRightTextAlignment]; |
| 174 | 223 |
| 175 return [NSDictionary dictionaryWithObjectsAndKeys: | 224 return [NSDictionary dictionaryWithObjectsAndKeys: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 203 ![[hintString_ string] hasSuffix:suffixString]) { | 252 ![[hintString_ string] hasSuffix:suffixString]) { |
| 204 | 253 |
| 205 // Build an attributed string with the concatenation of the prefix | 254 // Build an attributed string with the concatenation of the prefix |
| 206 // and suffix. | 255 // and suffix. |
| 207 NSString* s = [prefixString stringByAppendingString:suffixString]; | 256 NSString* s = [prefixString stringByAppendingString:suffixString]; |
| 208 scoped_nsobject<NSMutableAttributedString> as( | 257 scoped_nsobject<NSMutableAttributedString> as( |
| 209 [[NSMutableAttributedString alloc] | 258 [[NSMutableAttributedString alloc] |
| 210 initWithString:s attributes:[self hintAttributes]]); | 259 initWithString:s attributes:[self hintAttributes]]); |
| 211 | 260 |
| 212 // Build an attachment containing the hint image. | 261 // Build an attachment containing the hint image. |
| 213 scoped_nsobject<NSTextAttachmentCell> attachmentCell( | 262 NSAttributedString* is = |
| 214 [[NSTextAttachmentCell alloc] initImageCell:anImage]); | 263 AttributedStringForImage(anImage, kKeywordHintImageBaseline); |
| 215 scoped_nsobject<NSTextAttachment> attachment( | |
| 216 [[NSTextAttachment alloc] init]); | |
| 217 [attachment setAttachmentCell:attachmentCell]; | |
| 218 | |
| 219 // The attachment's baseline needs to be adjusted so the image | |
| 220 // doesn't sit on the same baseline as the text and make | |
| 221 // everything too tall. | |
| 222 scoped_nsobject<NSMutableAttributedString> is( | |
| 223 [[NSAttributedString attributedStringWithAttachment:attachment] | |
| 224 mutableCopy]); | |
| 225 [is addAttribute:NSBaselineOffsetAttributeName | |
| 226 value:[NSNumber numberWithFloat:kKeywordHintImageBaseline] | |
| 227 range:NSMakeRange(0, [is length])]; | |
| 228 | 264 |
| 229 // Stuff the image attachment between the prefix and suffix. | 265 // Stuff the image attachment between the prefix and suffix. |
| 230 [as insertAttributedString:is atIndex:[prefixString length]]; | 266 [as insertAttributedString:is atIndex:[prefixString length]]; |
| 231 | 267 |
| 232 // If too wide, just show the image. | 268 // If too wide, just show the image. |
| 233 hintString_.reset(WidthForHint(as) > width ? [is copy] : [as copy]); | 269 hintString_.reset(WidthForHint(as) > width ? [is copy] : [as copy]); |
| 234 } | 270 } |
| 235 } | 271 } |
| 236 | 272 |
| 237 - (void)setSearchHintString:(NSString*)aString | 273 - (void)setSearchHintString:(NSString*)aString |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 [[NSColor selectedControlColor] set]; | 460 [[NSColor selectedControlColor] set]; |
| 425 [path fill]; | 461 [path fill]; |
| 426 | 462 |
| 427 // Border around token rectangle, match focus ring's inner color. | 463 // Border around token rectangle, match focus ring's inner color. |
| 428 [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5] set]; | 464 [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5] set]; |
| 429 [path setLineWidth:1.0]; | 465 [path setLineWidth:1.0]; |
| 430 [path stroke]; | 466 [path stroke]; |
| 431 | 467 |
| 432 // Draw text w/in the rectangle. | 468 // Draw text w/in the rectangle. |
| 433 infoFrame.origin.x += 4.0; | 469 infoFrame.origin.x += 4.0; |
| 434 infoFrame.origin.y += 1.0; | |
| 435 [keywordString_.get() drawInRect:infoFrame]; | 470 [keywordString_.get() drawInRect:infoFrame]; |
| 436 } | 471 } |
| 437 | 472 |
| 438 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { | 473 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { |
| 439 if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { | 474 if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { |
| 440 DrawImageInRect(locationIconView_->GetImage(), controlView, | 475 DrawImageInRect(locationIconView_->GetImage(), controlView, |
| 441 [self locationIconFrameForFrame:cellFrame]); | 476 [self locationIconFrameForFrame:cellFrame]); |
| 442 } | 477 } |
| 443 | 478 |
| 444 if (hintString_) { | 479 if (hintString_) { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; | 592 icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; |
| 558 if (icon) { | 593 if (icon) { |
| 559 [icon view]->OnMousePressed([icon rect]); | 594 [icon view]->OnMousePressed([icon rect]); |
| 560 return YES; | 595 return YES; |
| 561 } | 596 } |
| 562 | 597 |
| 563 return NO; | 598 return NO; |
| 564 } | 599 } |
| 565 | 600 |
| 566 @end | 601 @end |
| OLD | NEW |