Skip to content

Instantly share code, notes, and snippets.

@andreyvit
Created October 2, 2013 08:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreyvit/6790726 to your computer and use it in GitHub Desktop.
Save andreyvit/6790726 to your computer and use it in GitHub Desktop.
#import <Cocoa/Cocoa.h>
// NSTextField has alignmentRectInsets = {.left=.right=3, .top=.bottom=0}, so
// when autolayout aligns NSTextField to its container's side margin (e.g. to x=0),
// the actual x position is -3, and the label gets clipped.
//
// ATUnclippedTextField compensates for that by overriding drawRect to extend
// the clipping rect by alignmentRectInsets.
//
// Note that visual artifacts may occur in certain case; make sure that no other views
// are within a 3px area to both sides of the label. We take care of NSClipView,
// any other view interactions are up to you.
//
// Requires OS X 10.7.
//
@interface ATUnclippedTextField : NSTextField
@end
#import "ATUnclippedTextField.h"
static NSView *ATFindViewAncestorByClass(NSView *view, Class ancestorClass) {
NSView *contentView = view.window.contentView;
while (view != nil) {
if ([view isKindOfClass:ancestorClass])
return view;
if (view == contentView)
break;
view = view.superview;
}
return nil;
}
@implementation ATUnclippedTextField
// has no effect (for an unknown reason), but we set our own clipping rect anyway, so it cannot hurt either
- (BOOL)wantsDefaultClipping {
return NO;
}
- (void)drawRect:(NSRect)dirtyRect {
[NSGraphicsContext saveGraphicsState];
NSRect clipRect = self.bounds;
// compensate for alignment rect insets by extending the clip rect
NSEdgeInsets insets = self.alignmentRectInsets;
clipRect.origin.x -= insets.left;
clipRect.size.width += insets.left + insets.right;
// force-clip by NSClipView to avoid the 3px overhang spilling out of NSScrollView
NSView *clippingAncestor = ATFindViewAncestorByClass(self, [NSClipView class]);
if (clippingAncestor) {
NSRect ancestorRect = [self convertRect:clippingAncestor.bounds fromView:clippingAncestor];
clipRect = NSIntersectionRect(clipRect, ancestorRect);
}
[[NSBezierPath bezierPathWithRect:clipRect] setClip];
[super drawRect:dirtyRect];
[NSGraphicsContext restoreGraphicsState];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment