diff options
-rw-r--r-- | AppKit/GTMFadeTruncatingTextFieldCell.m | 89 | ||||
-rw-r--r-- | AppKit/GTMFadeTruncatingTextFieldCellTest.m | 11 | ||||
-rw-r--r-- | AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff | bin | 2188 -> 2136 bytes | |||
-rw-r--r-- | AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff | bin | 2068 -> 2048 bytes | |||
-rw-r--r-- | AppKit/TestData/GTMFadeTruncatingTextFieldCellTest8.tiff | bin | 0 -> 2896 bytes | |||
-rw-r--r-- | GTM.xcodeproj/project.pbxproj | 4 |
6 files changed, 76 insertions, 28 deletions
diff --git a/AppKit/GTMFadeTruncatingTextFieldCell.m b/AppKit/GTMFadeTruncatingTextFieldCell.m index ec266a2..66e6874 100644 --- a/AppKit/GTMFadeTruncatingTextFieldCell.m +++ b/AppKit/GTMFadeTruncatingTextFieldCell.m @@ -43,26 +43,30 @@ // 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]; + [NSBezierPath clipRect:backgroundRect]; CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; CGContextBeginTransparencyLayerWithRect(context, - NSRectToCGRect(clipRect), 0); + NSRectToCGRect(backgroundRect), 0); if ([self drawsBackground]) { [[self backgroundColor] set]; - NSRectFillUsingOperation([self titleRectForBounds:backgroundRect], + NSRectFillUsingOperation(backgroundRect, NSCompositeSourceOver); } + + [[NSGraphicsContext currentContext] saveGraphicsState]; + [NSBezierPath clipRect:clipRect]; [attributedString drawInRect:titleRect]; + [[NSGraphicsContext currentContext] restoreGraphicsState]; NSPoint startPoint; NSPoint endPoint; if (fadeToRight) { - startPoint = clipRect.origin; - endPoint = NSMakePoint(NSMaxX(clipRect), NSMinY(clipRect)); + startPoint = backgroundRect.origin; + endPoint = NSMakePoint(NSMaxX(backgroundRect), NSMinY(backgroundRect)); } else { - startPoint = NSMakePoint(NSMaxX(clipRect), NSMinY(clipRect)); - endPoint = clipRect.origin; + startPoint = NSMakePoint(NSMaxX(backgroundRect), NSMinY(backgroundRect)); + endPoint = backgroundRect.origin; } // Draw the gradient mask @@ -83,10 +87,10 @@ titleRect.size.width -= 2; NSAttributedString *attributedString = [self attributedStringValue]; - NSSize size = [attributedString size]; + NSSize stringSize = [attributedString size]; // Don't complicate drawing unless we need to clip - if (size.width <= NSWidth(titleRect)) { + if (stringSize.width <= NSWidth(titleRect)) { [super drawInteriorWithFrame:cellFrame inView:controlView]; return; } @@ -97,7 +101,7 @@ case GTMFadeTruncatingTail: break; case GTMFadeTruncatingHead: - offsetX = size.width - titleRect.size.width; + offsetX = stringSize.width - titleRect.size.width; break; case GTMFadeTruncatingHeadAndTail: { if (desiredCharactersToTruncateFromHead_ > 0) { @@ -106,15 +110,24 @@ NSMakeRange(0, desiredCharactersToTruncateFromHead_)]; NSSize clippedHeadSize = [clippedHeadString size]; - // Clip the desired portion from the beginning of the string. + // This is the offset at which we start drawing. This causes the + // beginning of the string to get clipped. offsetX = clippedHeadSize.width; - CGFloat delta = size.width - titleRect.size.width; + // Due to the fade effect the first character is hard to see. + // We want to make sure the first character starting at + // |desiredCharactersToTruncateFromHead_| is readable so we reduce + // the offset by a little bit. + offsetX = MAX(0, offsetX - stringSize.height); + + // If the offset is so large that there's empty space at the tail + // then reduce the offset so we can use up the empty space. + CGFloat delta = stringSize.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); + offsetX = round((stringSize.width - titleRect.size.width) / 2.0); } break; } @@ -124,31 +137,48 @@ offsetTitleRect.origin.x -= offsetX; offsetTitleRect.size.width += offsetX; BOOL isTruncatingHead = offsetX > 0; - BOOL isTruncatingTail = (size.width - titleRect.size.width) > offsetX; + BOOL isTruncatingTail = (stringSize.width - titleRect.size.width) > offsetX; // Gradient is about twice our line height long - CGFloat gradientWidth = MIN(size.height * 2, round(NSWidth(cellFrame) / 4)); - NSRect solidPart = cellFrame; - NSRect headGradientPart = NSZeroRect; - NSRect tailGradientPart = NSZeroRect; + CGFloat gradientWidth = MIN(stringSize.height * 2, round(NSWidth(cellFrame) / 4)); + + // Head, solid, and tail rects for drawing the background. + NSRect solidBackgroundPart = [self drawingRectForBounds:cellFrame]; + NSRect headBackgroundPart = NSZeroRect; + NSRect tailBackgroundPart = NSZeroRect; if (isTruncatingHead) - NSDivideRect(solidPart, &headGradientPart, &solidPart, + NSDivideRect(solidBackgroundPart, &headBackgroundPart, &solidBackgroundPart, gradientWidth, NSMinXEdge); if (isTruncatingTail) - NSDivideRect(solidPart, &tailGradientPart, &solidPart, + NSDivideRect(solidBackgroundPart, &tailBackgroundPart, &solidBackgroundPart, gradientWidth, NSMaxXEdge); + // Head, solid and tail rects for clipping the title. This is slightly + // smaller than the background rects. + NSRect solidTitleClipPart = titleRect; + NSRect headTitleClipPart = NSZeroRect; + NSRect tailTitleClipPart = NSZeroRect; + if (isTruncatingHead) { + CGFloat width = NSMinX(solidBackgroundPart) - NSMinX(solidTitleClipPart); + NSDivideRect(solidTitleClipPart, &headTitleClipPart, &solidTitleClipPart, + width, NSMinXEdge); + } + if (isTruncatingTail) { + CGFloat width = NSMaxX(solidTitleClipPart) - NSMaxX(solidBackgroundPart); + NSDivideRect(solidTitleClipPart, &tailTitleClipPart, &solidTitleClipPart, + width, 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]; if ([self drawsBackground]) { [[self backgroundColor] set]; - NSRectFillUsingOperation(backgroundRect, NSCompositeSourceOver); + NSRectFillUsingOperation(solidBackgroundPart, NSCompositeSourceOver); } // We draw the text ourselves because [super drawInteriorWithFrame:inView:] // doesn't draw correctly if the cell draws its own background. + [NSBezierPath clipRect:solidTitleClipPart]; [attributedString drawInRect:offsetTitleRect]; [[NSGraphicsContext currentContext] restoreGraphicsState]; @@ -160,15 +190,15 @@ if (isTruncatingHead) [self drawTextGradientPart:attributedString titleRect:offsetTitleRect - backgroundRect:backgroundRect - clipRect:headGradientPart + backgroundRect:headBackgroundPart + clipRect:headTitleClipPart mask:mask fadeToRight:NO]; if (isTruncatingTail) [self drawTextGradientPart:attributedString titleRect:offsetTitleRect - backgroundRect:backgroundRect - clipRect:tailGradientPart + backgroundRect:tailBackgroundPart + clipRect:tailTitleClipPart mask:mask fadeToRight:YES]; @@ -197,6 +227,11 @@ return desiredCharactersToTruncateFromHead_; } +// The faded ends of the cell are not opaque. +- (BOOL)isOpaque { + return NO; +} + @end #endif diff --git a/AppKit/GTMFadeTruncatingTextFieldCellTest.m b/AppKit/GTMFadeTruncatingTextFieldCellTest.m index a1bf937..c201d27 100644 --- a/AppKit/GTMFadeTruncatingTextFieldCellTest.m +++ b/AppKit/GTMFadeTruncatingTextFieldCellTest.m @@ -75,7 +75,7 @@ @"GTMFadeTruncatingTextFieldCellTest5", nil); - [field setStringValue:@"Fade on left only AA"]; + [field setStringValue:@"Fade on left only A"]; GTMAssertObjectImageEqualToImageNamed(field, @"GTMFadeTruncatingTextFieldCellTest6", nil); @@ -92,6 +92,15 @@ GTMAssertObjectImageEqualToImageNamed(field, @"GTMFadeTruncatingTextFieldCellTest7", nil); + + // Border with a solid background color. + [field setTextColor:[NSColor whiteColor]]; + [field setDrawsBackground:YES]; + [field setBackgroundColor:[NSColor blackColor]]; + [field setBordered:YES]; + GTMAssertObjectImageEqualToImageNamed(field, + @"GTMFadeTruncatingTextFieldCellTest8", + nil); } @end diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff Binary files differindex f360479..4d4635f 100644 --- a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff +++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest5.tiff diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff Binary files differindex d704a81..c8b435d 100644 --- a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff +++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest6.tiff diff --git a/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest8.tiff b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest8.tiff Binary files differnew file mode 100644 index 0000000..47d70bd --- /dev/null +++ b/AppKit/TestData/GTMFadeTruncatingTextFieldCellTest8.tiff diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj index db294ea..9cbed35 100644 --- a/GTM.xcodeproj/project.pbxproj +++ b/GTM.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ B71B91E21332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest5.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B71B91E01332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest5.tiff */; }; B71B91E31332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest6.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B71B91E11332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest6.tiff */; }; B71B92371332DA380039B2CB /* GTMFadeTruncatingTextFieldCellTest7.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B71B92361332DA380039B2CB /* GTMFadeTruncatingTextFieldCellTest7.tiff */; }; + B7764E80133906B600AFDC7D /* GTMFadeTruncatingTextFieldCellTest8.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B7764E7F133906B600AFDC7D /* GTMFadeTruncatingTextFieldCellTest8.tiff */; }; F413908F0D75F63C00F72B31 /* GTMNSFileManager+Path.h in Headers */ = {isa = PBXBuildFile; fileRef = F413908C0D75F63C00F72B31 /* GTMNSFileManager+Path.h */; settings = {ATTRIBUTES = (Public, ); }; }; F41390900D75F63C00F72B31 /* GTMNSFileManager+Path.m in Sources */ = {isa = PBXBuildFile; fileRef = F413908D0D75F63C00F72B31 /* GTMNSFileManager+Path.m */; }; F41711350ECDFBD500B9B276 /* GTMLightweightProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = F41711320ECDFBD500B9B276 /* GTMLightweightProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -790,6 +791,7 @@ B71B91E01332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest5.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMFadeTruncatingTextFieldCellTest5.tiff; sourceTree = "<group>"; }; B71B91E11332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest6.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMFadeTruncatingTextFieldCellTest6.tiff; sourceTree = "<group>"; }; B71B92361332DA380039B2CB /* GTMFadeTruncatingTextFieldCellTest7.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMFadeTruncatingTextFieldCellTest7.tiff; sourceTree = "<group>"; }; + B7764E7F133906B600AFDC7D /* GTMFadeTruncatingTextFieldCellTest8.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMFadeTruncatingTextFieldCellTest8.tiff; sourceTree = "<group>"; }; F413908C0D75F63C00F72B31 /* GTMNSFileManager+Path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSFileManager+Path.h"; sourceTree = "<group>"; }; F413908D0D75F63C00F72B31 /* GTMNSFileManager+Path.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSFileManager+Path.m"; sourceTree = "<group>"; }; F413908E0D75F63C00F72B31 /* GTMNSFileManager+PathTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSFileManager+PathTest.m"; sourceTree = "<group>"; }; @@ -1203,6 +1205,7 @@ B71B91E01332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest5.tiff */, B71B91E11332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest6.tiff */, B71B92361332DA380039B2CB /* GTMFadeTruncatingTextFieldCellTest7.tiff */, + B7764E7F133906B600AFDC7D /* GTMFadeTruncatingTextFieldCellTest8.tiff */, 8B1802410E25592200280961 /* GTMLargeTypeWindowMediumTextTest.gtmUTState */, 8BA9FBAC119CB08200E264C3 /* GTMLargeTypeWindowMediumTextTest.10.6.gtmUTState */, 8B1801A80E25341B00280961 /* GTMLargeTypeWindowImageTest.gtmUTState */, @@ -2130,6 +2133,7 @@ B71B91E21332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest5.tiff in Resources */, B71B91E31332CD680039B2CB /* GTMFadeTruncatingTextFieldCellTest6.tiff in Resources */, B71B92371332DA380039B2CB /* GTMFadeTruncatingTextFieldCellTest7.tiff in Resources */, + B7764E80133906B600AFDC7D /* GTMFadeTruncatingTextFieldCellTest8.tiff in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; |