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); |
} |
} |