Chromium Code Reviews| Index: chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm |
| diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm |
| index f1b47c7e467cb36811517ce947d5dcfb290e1466..212a603a86dd2197f40876a729d981e4110cd64f 100644 |
| --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm |
| +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm |
| @@ -4,8 +4,11 @@ |
| #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h" |
| +#include <algorithm> |
| #include <cmath> |
| +#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" |
| + |
| namespace { |
| // How far to offset image column from the left. |
| @@ -14,14 +17,70 @@ const CGFloat kImageXOffset = 5.0; |
| // How far to offset the text column from the left. |
| const CGFloat kTextXOffset = 28.0; |
| +// Maximum fraction of the popup width that can be used to display match |
| +// contents. |
| +const CGFloat kMaxContentsFraction = 0.7; |
| + |
| // Rounding radius of selection and hover background on popup items. |
| const CGFloat kCellRoundingRadius = 2.0; |
| -NSColor* SelectedBackgroundColor() { |
| - return [NSColor selectedControlColor]; |
| -} |
| -NSColor* HoveredBackgroundColor() { |
| - return [NSColor controlHighlightColor]; |
| +void DrawFadeTruncatingTitle(NSAttributedString* title, |
| + NSRect titleRect) { |
| + NSSize size = [title size]; |
| + |
| + // Empirically, Cocoa will draw an extra 2 pixels past NSWidth(titleRect) |
| + // before it clips the text. |
| + const CGFloat kOverflowBeforeClip = 2; |
|
Scott Hess - ex-Googler
2013/06/28 01:02:48
2.0
sail
2013/06/28 18:41:16
Done.
|
| + BOOL clipping = |
| + std::floor(size.width) > NSWidth(titleRect) + kOverflowBeforeClip; |
| + |
| + // Gradient is about twice our line height long. |
| + 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.
|
| + |
| + NSRect solidPart, gradientPart; |
| + NSDivideRect(titleRect, &gradientPart, &solidPart, gradientWidth, NSMaxXEdge); |
| + |
| + NSPoint textOffset; |
| + textOffset.x = NSMinX(titleRect); |
| + textOffset.y = |
| + 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.
|
| + |
| + // Draw non-gradient part without transparency layer, as light text on a dark |
| + // background looks bad with a gradient layer. |
| + { |
| + gfx::ScopedNSGraphicsContextSaveGState scopedGState; |
| + if (clipping) |
| + [NSBezierPath clipRect:solidPart]; |
| + [title drawAtPoint:textOffset]; |
| + } |
| + |
| + 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
|
| + return; |
| + |
| + // Draw the gradient part with a transparency layer. This makes the text look |
| + // 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
|
| + gfx::ScopedNSGraphicsContextSaveGState scopedGState; |
| + [NSBezierPath clipRect:gradientPart]; |
| + CGContextRef context = static_cast<CGContextRef>( |
| + [[NSGraphicsContext currentContext] graphicsPort]); |
| + CGContextBeginTransparencyLayerWithRect(context, |
| + NSRectToCGRect(gradientPart), 0); |
| + [title drawAtPoint:textOffset]; |
| + |
| + NSColor *color = [NSColor textColor]; |
| + NSColor *alphaColor = [color colorWithAlphaComponent:0.0]; |
| + NSGradient *mask = [[NSGradient alloc] initWithStartingColor:color |
| + endingColor:alphaColor]; |
| + |
| + // Draw the gradient mask |
| + CGContextSetBlendMode(context, kCGBlendModeDestinationIn); |
| + [mask drawFromPoint:NSMakePoint(NSMaxX(titleRect) - gradientWidth, |
| + NSMinY(titleRect)) |
| + toPoint:NSMakePoint(NSMaxX(titleRect), |
| + NSMinY(titleRect)) |
| + options:NSGradientDrawsBeforeStartingLocation]; |
| + [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.
|
| + CGContextEndTransparencyLayer(context); |
| } |
| } // namespace |
| @@ -29,8 +88,7 @@ NSColor* HoveredBackgroundColor() { |
| @implementation OmniboxPopupCell |
| - (id)init { |
| - self = [super init]; |
| - if (self) { |
| + if ((self = [super init])) { |
| [self setImagePosition:NSImageLeft]; |
| [self setBordered:NO]; |
| [self setButtonType:NSRadioButton]; |
| @@ -41,15 +99,28 @@ NSColor* HoveredBackgroundColor() { |
| return self; |
| } |
| -// The default NSButtonCell drawing leaves the image flush left and |
| -// the title next to the image. This spaces things out to line up |
| -// with the star button and autocomplete field. |
| +- (NSAttributedString*)contentText { |
| + return contentText_; |
| +} |
| + |
| +- (void)setContentText:(NSAttributedString*)contentText { |
| + contentText_.reset([contentText retain]); |
| +} |
| + |
| +- (NSAttributedString*)descriptionText { |
| + return descriptionText_; |
| +} |
| + |
| +- (void)setDescriptionText:(NSAttributedString*)descriptionText { |
| + descriptionText_.reset([descriptionText retain]); |
| +} |
| + |
| - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { |
| if ([self state] == NSOnState || [self isHighlighted]) { |
| if ([self state] == NSOnState) |
| - [SelectedBackgroundColor() set]; |
| + [[NSColor selectedControlColor] set]; |
| else |
| - [HoveredBackgroundColor() set]; |
| + [[NSColor controlHighlightColor] set]; |
| NSBezierPath* path = |
| [NSBezierPath bezierPathWithRoundedRect:cellFrame |
| xRadius:kCellRoundingRadius |
| @@ -74,12 +145,33 @@ NSColor* HoveredBackgroundColor() { |
| } |
| // Adjust the title position to be lined up under the field's text. |
| - NSAttributedString* title = [self attributedTitle]; |
| - if (title && [title length]) { |
| - NSRect titleRect = cellFrame; |
| - titleRect.size.width -= kTextXOffset; |
| - titleRect.origin.x += kTextXOffset; |
| - [self drawTitle:title withFrame:titleRect inView:controlView]; |
| + if ([contentText_ length]) { |
| + CGFloat availableWidth = NSWidth(cellFrame) - kTextXOffset; |
| + CGFloat contentWidth = [contentText_ size].width; |
| + CGFloat descriptionWidth = 0; |
| + if ([descriptionText_ length]) |
| + descriptionWidth = [descriptionText_ size].width; |
| + |
| + if (contentWidth + descriptionWidth > availableWidth) { |
| + if (contentWidth > kMaxContentsFraction * availableWidth) { |
| + if (descriptionWidth > (1.0 - kMaxContentsFraction) * availableWidth) |
| + 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.
|
| + contentWidth = |
| + std::min(contentWidth, availableWidth - descriptionWidth); |
| + } else { |
| + descriptionWidth = availableWidth - contentWidth; |
| + } |
| + } |
|
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.
|
| + |
| + NSRect contentRect = cellFrame; |
| + contentRect.origin.x = kTextXOffset; |
| + contentRect.size.width = contentWidth; |
| + DrawFadeTruncatingTitle(contentText_, contentRect); |
| + |
| + 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.
|
| + descriptionRect.origin.x = NSMaxX(contentRect); |
| + descriptionRect.size.width = descriptionWidth; |
| + DrawFadeTruncatingTitle(descriptionText_, descriptionRect); |
| } |
| } |