Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/omnibox/omnibox_popup_cell.h" | 5 #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include <cmath> | 8 #include <cmath> |
| 8 | 9 |
| 10 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | |
| 11 | |
| 9 namespace { | 12 namespace { |
| 10 | 13 |
| 11 // How far to offset image column from the left. | 14 // How far to offset image column from the left. |
| 12 const CGFloat kImageXOffset = 5.0; | 15 const CGFloat kImageXOffset = 5.0; |
| 13 | 16 |
| 14 // How far to offset the text column from the left. | 17 // How far to offset the text column from the left. |
| 15 const CGFloat kTextXOffset = 28.0; | 18 const CGFloat kTextXOffset = 28.0; |
| 16 | 19 |
| 20 // Maximum fraction of the popup width that can be used to display match | |
| 21 // contents. | |
| 22 const CGFloat kMaxContentsFraction = 0.7; | |
| 23 | |
| 17 // Rounding radius of selection and hover background on popup items. | 24 // Rounding radius of selection and hover background on popup items. |
| 18 const CGFloat kCellRoundingRadius = 2.0; | 25 const CGFloat kCellRoundingRadius = 2.0; |
| 19 | 26 |
| 20 NSColor* SelectedBackgroundColor() { | 27 void DrawFadeTruncatingTitle(NSAttributedString* title, |
| 21 return [NSColor selectedControlColor]; | 28 NSRect titleRect) { |
| 22 } | 29 NSSize size = [title size]; |
| 23 NSColor* HoveredBackgroundColor() { | 30 |
| 24 return [NSColor controlHighlightColor]; | 31 // Empirically, Cocoa will draw an extra 2 pixels past NSWidth(titleRect) |
| 32 // before it clips the text. | |
| 33 const CGFloat kOverflowBeforeClip = 2; | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
2.0
sail
2013/06/28 18:41:16
Done.
| |
| 34 BOOL clipping = | |
| 35 std::floor(size.width) > NSWidth(titleRect) + kOverflowBeforeClip; | |
| 36 | |
| 37 // Gradient is about twice our line height long. | |
| 38 CGFloat gradientWidth = MIN(size.height * 2, NSWidth(titleRect) / 4); | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
std::min().
sail
2013/06/28 18:41:16
Done.
| |
| 39 | |
| 40 NSRect solidPart, gradientPart; | |
| 41 NSDivideRect(titleRect, &gradientPart, &solidPart, gradientWidth, NSMaxXEdge); | |
| 42 | |
| 43 NSPoint textOffset; | |
| 44 textOffset.x = NSMinX(titleRect); | |
| 45 textOffset.y = | |
| 46 NSMinY(titleRect) + roundf((NSHeight(titleRect) - size.height) / 2.0) - 1; | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
Sigh. No std::round until c++11.
| |
| 47 | |
| 48 // Draw non-gradient part without transparency layer, as light text on a dark | |
| 49 // background looks bad with a gradient layer. | |
| 50 { | |
| 51 gfx::ScopedNSGraphicsContextSaveGState scopedGState; | |
| 52 if (clipping) | |
| 53 [NSBezierPath clipRect:solidPart]; | |
| 54 [title drawAtPoint:textOffset]; | |
| 55 } | |
| 56 | |
| 57 if (!clipping) | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
Couldn't this result in incorrect drawing if the t
sail
2013/06/28 18:41:16
Done.
This part is not relevant anymore now that I
| |
| 58 return; | |
| 59 | |
| 60 // Draw the gradient part with a transparency layer. This makes the text look | |
| 61 // suboptimal, but since it fades out, that's ok. | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
This seems complicated. Something like this using
sail
2013/06/28 18:41:16
Done.
Yep, I just draw the full string and then dr
| |
| 62 gfx::ScopedNSGraphicsContextSaveGState scopedGState; | |
| 63 [NSBezierPath clipRect:gradientPart]; | |
| 64 CGContextRef context = static_cast<CGContextRef>( | |
| 65 [[NSGraphicsContext currentContext] graphicsPort]); | |
| 66 CGContextBeginTransparencyLayerWithRect(context, | |
| 67 NSRectToCGRect(gradientPart), 0); | |
| 68 [title drawAtPoint:textOffset]; | |
| 69 | |
| 70 NSColor *color = [NSColor textColor]; | |
| 71 NSColor *alphaColor = [color colorWithAlphaComponent:0.0]; | |
| 72 NSGradient *mask = [[NSGradient alloc] initWithStartingColor:color | |
| 73 endingColor:alphaColor]; | |
| 74 | |
| 75 // Draw the gradient mask | |
| 76 CGContextSetBlendMode(context, kCGBlendModeDestinationIn); | |
| 77 [mask drawFromPoint:NSMakePoint(NSMaxX(titleRect) - gradientWidth, | |
| 78 NSMinY(titleRect)) | |
| 79 toPoint:NSMakePoint(NSMaxX(titleRect), | |
| 80 NSMinY(titleRect)) | |
| 81 options:NSGradientDrawsBeforeStartingLocation]; | |
| 82 [mask release]; | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
Why not scoped_ptr<>? Does the mask require speci
sail
2013/06/28 18:41:16
Done.
| |
| 83 CGContextEndTransparencyLayer(context); | |
| 25 } | 84 } |
| 26 | 85 |
| 27 } // namespace | 86 } // namespace |
| 28 | 87 |
| 29 @implementation OmniboxPopupCell | 88 @implementation OmniboxPopupCell |
| 30 | 89 |
| 31 - (id)init { | 90 - (id)init { |
| 32 self = [super init]; | 91 if ((self = [super init])) { |
| 33 if (self) { | |
| 34 [self setImagePosition:NSImageLeft]; | 92 [self setImagePosition:NSImageLeft]; |
| 35 [self setBordered:NO]; | 93 [self setBordered:NO]; |
| 36 [self setButtonType:NSRadioButton]; | 94 [self setButtonType:NSRadioButton]; |
| 37 | 95 |
| 38 // Without this highlighting messes up white areas of images. | 96 // Without this highlighting messes up white areas of images. |
| 39 [self setHighlightsBy:NSNoCellMask]; | 97 [self setHighlightsBy:NSNoCellMask]; |
| 40 } | 98 } |
| 41 return self; | 99 return self; |
| 42 } | 100 } |
| 43 | 101 |
| 44 // The default NSButtonCell drawing leaves the image flush left and | 102 - (NSAttributedString*)contentText { |
| 45 // the title next to the image. This spaces things out to line up | 103 return contentText_; |
| 46 // with the star button and autocomplete field. | 104 } |
| 105 | |
| 106 - (void)setContentText:(NSAttributedString*)contentText { | |
| 107 contentText_.reset([contentText retain]); | |
| 108 } | |
| 109 | |
| 110 - (NSAttributedString*)descriptionText { | |
| 111 return descriptionText_; | |
| 112 } | |
| 113 | |
| 114 - (void)setDescriptionText:(NSAttributedString*)descriptionText { | |
| 115 descriptionText_.reset([descriptionText retain]); | |
| 116 } | |
| 117 | |
| 47 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { | 118 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { |
| 48 if ([self state] == NSOnState || [self isHighlighted]) { | 119 if ([self state] == NSOnState || [self isHighlighted]) { |
| 49 if ([self state] == NSOnState) | 120 if ([self state] == NSOnState) |
| 50 [SelectedBackgroundColor() set]; | 121 [[NSColor selectedControlColor] set]; |
| 51 else | 122 else |
| 52 [HoveredBackgroundColor() set]; | 123 [[NSColor controlHighlightColor] set]; |
| 53 NSBezierPath* path = | 124 NSBezierPath* path = |
| 54 [NSBezierPath bezierPathWithRoundedRect:cellFrame | 125 [NSBezierPath bezierPathWithRoundedRect:cellFrame |
| 55 xRadius:kCellRoundingRadius | 126 xRadius:kCellRoundingRadius |
| 56 yRadius:kCellRoundingRadius]; | 127 yRadius:kCellRoundingRadius]; |
| 57 [path fill]; | 128 [path fill]; |
| 58 } | 129 } |
| 59 | 130 |
| 60 // Put the image centered vertically but in a fixed column. | 131 // Put the image centered vertically but in a fixed column. |
| 61 NSImage* image = [self image]; | 132 NSImage* image = [self image]; |
| 62 if (image) { | 133 if (image) { |
| 63 NSRect imageRect = cellFrame; | 134 NSRect imageRect = cellFrame; |
| 64 imageRect.size = [image size]; | 135 imageRect.size = [image size]; |
| 65 imageRect.origin.y += | 136 imageRect.origin.y += |
| 66 std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0); | 137 std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0); |
| 67 imageRect.origin.x += kImageXOffset; | 138 imageRect.origin.x += kImageXOffset; |
| 68 [image drawInRect:imageRect | 139 [image drawInRect:imageRect |
| 69 fromRect:NSZeroRect // Entire image | 140 fromRect:NSZeroRect // Entire image |
| 70 operation:NSCompositeSourceOver | 141 operation:NSCompositeSourceOver |
| 71 fraction:1.0 | 142 fraction:1.0 |
| 72 respectFlipped:YES | 143 respectFlipped:YES |
| 73 hints:nil]; | 144 hints:nil]; |
| 74 } | 145 } |
| 75 | 146 |
| 76 // Adjust the title position to be lined up under the field's text. | 147 // Adjust the title position to be lined up under the field's text. |
| 77 NSAttributedString* title = [self attributedTitle]; | 148 if ([contentText_ length]) { |
| 78 if (title && [title length]) { | 149 CGFloat availableWidth = NSWidth(cellFrame) - kTextXOffset; |
| 79 NSRect titleRect = cellFrame; | 150 CGFloat contentWidth = [contentText_ size].width; |
| 80 titleRect.size.width -= kTextXOffset; | 151 CGFloat descriptionWidth = 0; |
| 81 titleRect.origin.x += kTextXOffset; | 152 if ([descriptionText_ length]) |
| 82 [self drawTitle:title withFrame:titleRect inView:controlView]; | 153 descriptionWidth = [descriptionText_ size].width; |
| 154 | |
| 155 if (contentWidth + descriptionWidth > availableWidth) { | |
| 156 if (contentWidth > kMaxContentsFraction * availableWidth) { | |
| 157 if (descriptionWidth > (1.0 - kMaxContentsFraction) * availableWidth) | |
| 158 descriptionWidth = (1.0 - kMaxContentsFraction) * availableWidth; | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
std::min?
sail
2013/06/28 18:41:16
Done.
| |
| 159 contentWidth = | |
| 160 std::min(contentWidth, availableWidth - descriptionWidth); | |
| 161 } else { | |
| 162 descriptionWidth = availableWidth - contentWidth; | |
| 163 } | |
| 164 } | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
I think this entire if() can be replaced with some
sail
2013/06/28 18:41:16
Done.
| |
| 165 | |
| 166 NSRect contentRect = cellFrame; | |
| 167 contentRect.origin.x = kTextXOffset; | |
| 168 contentRect.size.width = contentWidth; | |
| 169 DrawFadeTruncatingTitle(contentText_, contentRect); | |
| 170 | |
| 171 NSRect descriptionRect = cellFrame; | |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
if ([descriptionText_ length]){...} around this?
sail
2013/06/28 18:41:16
Done.
| |
| 172 descriptionRect.origin.x = NSMaxX(contentRect); | |
| 173 descriptionRect.size.width = descriptionWidth; | |
| 174 DrawFadeTruncatingTitle(descriptionText_, descriptionRect); | |
| 83 } | 175 } |
| 84 } | 176 } |
| 85 | 177 |
| 86 @end | 178 @end |
| OLD | NEW |