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 |