aboutsummaryrefslogtreecommitdiff
path: root/AppKit
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2011-03-18 21:00:21 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2011-03-18 21:00:21 +0000
commitfb696efd169db17e8169d0d0cfd1caf0728c0722 (patch)
treec5e617df9d40b77132892abb3d0264dca3a8e56a /AppKit
parent72bd0c479793ffcd5a78696da9ba27e8b26c8e3e (diff)
[Author: sail]
Currently GTMFadeTruncatingTextFieldCell only supports truncating the tail of a string. It should also allow the head of a string to be truncated. I'd like to use this in Chromium. See http://crbug.com/69304 R=thomasvl APPROVED=thomasvl DELTA=238 (197 added, 17 deleted, 24 changed)
Diffstat (limited to 'AppKit')
-rw-r--r--AppKit/GTMFadeTruncatingTextFieldCell.h22
-rw-r--r--AppKit/GTMFadeTruncatingTextFieldCell.m173
-rw-r--r--AppKit/GTMFadeTruncatingTextFieldCellTest.m36
-rw-r--r--AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiffbin0 -> 2188 bytes
-rw-r--r--AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiffbin0 -> 2068 bytes
-rw-r--r--AppKit/TestData/GTMFadeTruncatingTextFieldCellTest7.tiffbin0 -> 2222 bytes
6 files changed, 198 insertions, 33 deletions
diff --git a/AppKit/GTMFadeTruncatingTextFieldCell.h b/AppKit/GTMFadeTruncatingTextFieldCell.h
index 76e7b1c..267d4b8 100644
--- a/AppKit/GTMFadeTruncatingTextFieldCell.h
+++ b/AppKit/GTMFadeTruncatingTextFieldCell.h
@@ -21,8 +21,26 @@
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
-// A simple text field cell that truncates the right hand edge using a gradient
-@interface GTMFadeTruncatingTextFieldCell : NSTextFieldCell
+typedef enum {
+ GTMFadeTruncatingTail,
+ GTMFadeTruncatingHead,
+ GTMFadeTruncatingHeadAndTail,
+} GTMFadeTruncateMode;
+
+// A simple text field cell that can truncate at the beginning or the end
+// using a gradient. By default it truncates the end.
+@interface GTMFadeTruncatingTextFieldCell : NSTextFieldCell {
+ @private
+ NSUInteger desiredCharactersToTruncateFromHead_;
+ GTMFadeTruncateMode truncateMode_;
+}
+
+@property (nonatomic) GTMFadeTruncateMode truncateMode;
+
+// When truncating the head this specifies the maximum number of characters
+// that can be truncated. Setting this to 0 means that there is no maximum.
+@property (nonatomic) NSUInteger desiredCharactersToTruncateFromHead;
+
@end
#endif
diff --git a/AppKit/GTMFadeTruncatingTextFieldCell.m b/AppKit/GTMFadeTruncatingTextFieldCell.m
index 0e7344c..ec266a2 100644
--- a/AppKit/GTMFadeTruncatingTextFieldCell.m
+++ b/AppKit/GTMFadeTruncatingTextFieldCell.m
@@ -34,54 +34,167 @@
return self;
}
+- (void)drawTextGradientPart:(NSAttributedString *)attributedString
+ titleRect:(NSRect)titleRect
+ backgroundRect:(NSRect)backgroundRect
+ clipRect:(NSRect)clipRect
+ mask:(NSGradient *)mask
+ fadeToRight:(BOOL)fadeToRight {
+ // Draw the gradient part with a transparency layer. This makes the text look
+ // suboptimal, but since it fades out, that's ok.
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ [NSBezierPath clipRect:clipRect];
+ CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
+ CGContextBeginTransparencyLayerWithRect(context,
+ NSRectToCGRect(clipRect), 0);
+
+ if ([self drawsBackground]) {
+ [[self backgroundColor] set];
+ NSRectFillUsingOperation([self titleRectForBounds:backgroundRect],
+ NSCompositeSourceOver);
+ }
+ [attributedString drawInRect:titleRect];
+
+ NSPoint startPoint;
+ NSPoint endPoint;
+ if (fadeToRight) {
+ startPoint = clipRect.origin;
+ endPoint = NSMakePoint(NSMaxX(clipRect), NSMinY(clipRect));
+ } else {
+ startPoint = NSMakePoint(NSMaxX(clipRect), NSMinY(clipRect));
+ endPoint = clipRect.origin;
+ }
+
+ // Draw the gradient mask
+ CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
+ [mask drawFromPoint:startPoint
+ toPoint:endPoint
+ options:fadeToRight ? NSGradientDrawsBeforeStartingLocation :
+ NSGradientDrawsAfterEndingLocation];
+
+ CGContextEndTransparencyLayer(context);
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+}
+
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
- NSSize size = [[self attributedStringValue] size];
+ NSRect titleRect = [self titleRectForBounds:cellFrame];
+ // For some reason the title rect is too far to the left.
+ titleRect.origin.x += 2;
+ titleRect.size.width -= 2;
+
+ NSAttributedString *attributedString = [self attributedStringValue];
+ NSSize size = [attributedString size];
// Don't complicate drawing unless we need to clip
- if (size.width <= NSWidth(cellFrame)) {
+ if (size.width <= NSWidth(titleRect)) {
[super drawInteriorWithFrame:cellFrame inView:controlView];
return;
}
+ // Clip the string by drawing it to the left by |offsetX|.
+ CGFloat offsetX = 0;
+ switch (truncateMode_) {
+ case GTMFadeTruncatingTail:
+ break;
+ case GTMFadeTruncatingHead:
+ offsetX = size.width - titleRect.size.width;
+ break;
+ case GTMFadeTruncatingHeadAndTail: {
+ if (desiredCharactersToTruncateFromHead_ > 0) {
+ NSAttributedString *clippedHeadString =
+ [attributedString attributedSubstringFromRange:
+ NSMakeRange(0, desiredCharactersToTruncateFromHead_)];
+ NSSize clippedHeadSize = [clippedHeadString size];
+
+ // Clip the desired portion from the beginning of the string.
+ offsetX = clippedHeadSize.width;
+
+ CGFloat delta = size.width - titleRect.size.width;
+ if (offsetX > delta)
+ offsetX = delta;
+ } else {
+ // Center the string and clip equal portions of the head and tail.
+ offsetX = round((size.width - titleRect.size.width) / 2.0);
+ }
+ break;
+ }
+ }
+
+ NSRect offsetTitleRect = titleRect;
+ offsetTitleRect.origin.x -= offsetX;
+ offsetTitleRect.size.width += offsetX;
+ BOOL isTruncatingHead = offsetX > 0;
+ BOOL isTruncatingTail = (size.width - titleRect.size.width) > offsetX;
+
// Gradient is about twice our line height long
- CGFloat gradientWidth = MIN(size.height * 2, NSWidth(cellFrame) / 4);
+ CGFloat gradientWidth = MIN(size.height * 2, round(NSWidth(cellFrame) / 4));
+ NSRect solidPart = cellFrame;
+ NSRect headGradientPart = NSZeroRect;
+ NSRect tailGradientPart = NSZeroRect;
+ if (isTruncatingHead)
+ NSDivideRect(solidPart, &headGradientPart, &solidPart,
+ gradientWidth, NSMinXEdge);
+ if (isTruncatingTail)
+ NSDivideRect(solidPart, &tailGradientPart, &solidPart,
+ gradientWidth, NSMaxXEdge);
- NSRect solidPart, gradientPart;
- NSDivideRect(cellFrame, &gradientPart, &solidPart, gradientWidth, NSMaxXEdge);
-
// Draw non-gradient part without transparency layer, as light text on a dark
// background looks bad with a gradient layer.
+ NSRect backgroundRect = [self drawingRectForBounds:cellFrame];
[[NSGraphicsContext currentContext] saveGraphicsState];
[NSBezierPath clipRect:solidPart];
- [super drawInteriorWithFrame:cellFrame inView:controlView];
+ if ([self drawsBackground]) {
+ [[self backgroundColor] set];
+ NSRectFillUsingOperation(backgroundRect, NSCompositeSourceOver);
+ }
+ // We draw the text ourselves because [super drawInteriorWithFrame:inView:]
+ // doesn't draw correctly if the cell draws its own background.
+ [attributedString drawInRect:offsetTitleRect];
[[NSGraphicsContext currentContext] restoreGraphicsState];
- // Draw the gradient part with a transparency layer. This makes the text look
- // suboptimal, but since it fades out, that's ok.
- [[NSGraphicsContext currentContext] saveGraphicsState];
- [NSBezierPath clipRect:gradientPart];
- CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
- CGContextBeginTransparencyLayerWithRect(context,
- NSRectToCGRect(gradientPart), 0);
-
- [super drawInteriorWithFrame:cellFrame inView:controlView];
+ NSColor *startColor = [self textColor];;
+ NSColor *endColor = [startColor colorWithAlphaComponent:0.0];
+ NSGradient *mask = [[NSGradient alloc] initWithStartingColor:startColor
+ endingColor:endColor];
- // TODO(alcor): switch this to GTMLinearRGBShading if we ever need on 10.4
- NSColor *color = [self textColor];
- NSColor *alphaColor = [color colorWithAlphaComponent:0.0];
- NSGradient *mask = [[NSGradient alloc] initWithStartingColor:color
- endingColor:alphaColor];
+ if (isTruncatingHead)
+ [self drawTextGradientPart:attributedString
+ titleRect:offsetTitleRect
+ backgroundRect:backgroundRect
+ clipRect:headGradientPart
+ mask:mask
+ fadeToRight:NO];
+ if (isTruncatingTail)
+ [self drawTextGradientPart:attributedString
+ titleRect:offsetTitleRect
+ backgroundRect:backgroundRect
+ clipRect:tailGradientPart
+ mask:mask
+ fadeToRight:YES];
- // Draw the gradient mask
- CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
- [mask drawFromPoint:NSMakePoint(NSMaxX(cellFrame) - gradientWidth,
- NSMinY(cellFrame))
- toPoint:NSMakePoint(NSMaxX(cellFrame),
- NSMinY(cellFrame))
- options:NSGradientDrawsBeforeStartingLocation];
[mask release];
- CGContextEndTransparencyLayer(context);
- [[NSGraphicsContext currentContext] restoreGraphicsState];
+}
+
+- (void)setTruncateMode:(GTMFadeTruncateMode)mode {
+ if (truncateMode_ != mode) {
+ truncateMode_ = mode;
+ [[self controlView] setNeedsDisplay:YES];
+ }
+}
+
+- (GTMFadeTruncateMode)truncateMode {
+ return truncateMode_;
+}
+
+- (void)setDesiredCharactersToTruncateFromHead:(NSUInteger)length {
+ if (desiredCharactersToTruncateFromHead_ != length) {
+ desiredCharactersToTruncateFromHead_ = length;
+ [[self controlView] setNeedsDisplay:YES];
+ }
+}
+
+- (NSUInteger)desiredCharactersToTruncateFromHead {
+ return desiredCharactersToTruncateFromHead_;
}
@end
diff --git a/AppKit/GTMFadeTruncatingTextFieldCellTest.m b/AppKit/GTMFadeTruncatingTextFieldCellTest.m
index a42e22e..a1bf937 100644
--- a/AppKit/GTMFadeTruncatingTextFieldCellTest.m
+++ b/AppKit/GTMFadeTruncatingTextFieldCellTest.m
@@ -28,7 +28,7 @@
@implementation GTMFadeTruncatingTextFieldCellTest
-- (void)testFadeCell {
+- (void)testFadeCellRight {
NSTextField *field = [[[NSTextField alloc] initWithFrame:
NSMakeRect(0, 0, 100, 16)] autorelease];
[field setCell:[[[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@""]
@@ -38,6 +38,7 @@
GTMAssertObjectImageEqualToImageNamed(field,
@"GTMFadeTruncatingTextFieldCellTest1",
nil);
+
[field setStringValue:@"A short string"];
GTMAssertObjectImageEqualToImageNamed(field,
@"GTMFadeTruncatingTextFieldCellTest2",
@@ -60,6 +61,39 @@
nil);
}
+- (void)testFadeCellLeftAndRight {
+ NSTextField *field = [[[NSTextField alloc] initWithFrame:
+ NSMakeRect(0, 0, 100, 16)] autorelease];
+ GTMFadeTruncatingTextFieldCell *cell =
+ [[[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@""] autorelease];
+ [cell setTruncateMode:GTMFadeTruncatingHeadAndTail];
+ [cell setDesiredCharactersToTruncateFromHead:5];
+ [field setCell:cell];
+
+ [field setStringValue:@"Fade on both left and right AAAA"];
+ GTMAssertObjectImageEqualToImageNamed(field,
+ @"GTMFadeTruncatingTextFieldCellTest5",
+ nil);
+
+ [field setStringValue:@"Fade on left only AA"];
+ GTMAssertObjectImageEqualToImageNamed(field,
+ @"GTMFadeTruncatingTextFieldCellTest6",
+ nil);
+
+ [field setStringValue:@"A short string"];
+ GTMAssertObjectImageEqualToImageNamed(field,
+ @"GTMFadeTruncatingTextFieldCellTest2",
+ nil);
+
+ // Test the case where the number of characters to truncate from head is not
+ // specified. This should cause the string to be drawn centered.
+ [cell setDesiredCharactersToTruncateFromHead:0];
+ [field setStringValue:@"Fade on both left and right AAAA"];
+ GTMAssertObjectImageEqualToImageNamed(field,
+ @"GTMFadeTruncatingTextFieldCellTest7",
+ nil);
+}
+
@end
#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff
new file mode 100644
index 0000000..f360479
--- /dev/null
+++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff
Binary files differ
diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff
new file mode 100644
index 0000000..d704a81
--- /dev/null
+++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff
Binary files differ
diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest7.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest7.tiff
new file mode 100644
index 0000000..ac1dca6
--- /dev/null
+++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest7.tiff
Binary files differ