| OLD | NEW |
| (Empty) |
| 1 // | |
| 2 // NSBezierPath+MCAdditions.m | |
| 3 // | |
| 4 // Created by Sean Patrick O'Brien on 4/1/08. | |
| 5 // Copyright 2008 MolokoCacao. All rights reserved. | |
| 6 // | |
| 7 | |
| 8 #import "NSBezierPath+MCAdditions.h" | |
| 9 | |
| 10 #import "third_party/GTM/AppKit/GTMNSBezierPath+CGPath.h" | |
| 11 | |
| 12 // remove/comment out this line of you don't want to use undocumented functions | |
| 13 #define MCBEZIER_USE_PRIVATE_FUNCTION | |
| 14 | |
| 15 #ifdef MCBEZIER_USE_PRIVATE_FUNCTION | |
| 16 extern CGPathRef CGContextCopyPath(CGContextRef context); | |
| 17 #endif | |
| 18 | |
| 19 static void CGPathCallback(void *info, const CGPathElement *element) | |
| 20 { | |
| 21 NSBezierPath *path = info; | |
| 22 CGPoint *points = element->points; | |
| 23 | |
| 24 switch (element->type) { | |
| 25 case kCGPathElementMoveToPoint: | |
| 26 { | |
| 27 [path moveToPoint:NSMakePoint(points[0].x, points[0].y)]
; | |
| 28 break; | |
| 29 } | |
| 30 case kCGPathElementAddLineToPoint: | |
| 31 { | |
| 32 [path lineToPoint:NSMakePoint(points[0].x, points[0].y)]
; | |
| 33 break; | |
| 34 } | |
| 35 case kCGPathElementAddQuadCurveToPoint: | |
| 36 { | |
| 37 // NOTE: This is untested. | |
| 38 NSPoint currentPoint = [path currentPoint]; | |
| 39 NSPoint interpolatedPoint = NSMakePoint((currentPoint.x
+ 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3); | |
| 40 [path curveToPoint:NSMakePoint(points[1].x, points[1].y)
controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint]; | |
| 41 break; | |
| 42 } | |
| 43 case kCGPathElementAddCurveToPoint: | |
| 44 { | |
| 45 [path curveToPoint:NSMakePoint(points[2].x, points[2].y)
controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(p
oints[1].x, points[1].y)]; | |
| 46 break; | |
| 47 } | |
| 48 case kCGPathElementCloseSubpath: | |
| 49 { | |
| 50 [path closePath]; | |
| 51 break; | |
| 52 } | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 @implementation NSBezierPath (MCAdditions) | |
| 57 | |
| 58 + (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef | |
| 59 { | |
| 60 NSBezierPath *path = [NSBezierPath bezierPath]; | |
| 61 CGPathApply(pathRef, path, CGPathCallback); | |
| 62 | |
| 63 return path; | |
| 64 } | |
| 65 | |
| 66 - (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth | |
| 67 { | |
| 68 #ifdef MCBEZIER_USE_PRIVATE_FUNCTION | |
| 69 NSBezierPath *path = [self copy]; | |
| 70 CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]
; | |
| 71 CGPathRef pathRef = [path gtm_CGPath]; | |
| 72 [path release]; | |
| 73 | |
| 74 CGContextSaveGState(context); | |
| 75 | |
| 76 CGContextBeginPath(context); | |
| 77 CGContextAddPath(context, pathRef); | |
| 78 CGContextSetLineWidth(context, strokeWidth); | |
| 79 CGContextReplacePathWithStrokedPath(context); | |
| 80 CGPathRef strokedPathRef = CGContextCopyPath(context); | |
| 81 CGContextBeginPath(context); | |
| 82 NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPa
thRef]; | |
| 83 | |
| 84 CGContextRestoreGState(context); | |
| 85 | |
| 86 CFRelease(pathRef); | |
| 87 CFRelease(strokedPathRef); | |
| 88 | |
| 89 return strokedPath; | |
| 90 #else | |
| 91 return nil; | |
| 92 #endif // MCBEZIER_USE_PRIVATE_FUNCTION | |
| 93 } | |
| 94 | |
| 95 - (void)fillWithInnerShadow:(NSShadow *)shadow | |
| 96 { | |
| 97 [NSGraphicsContext saveGraphicsState]; | |
| 98 | |
| 99 NSSize offset = shadow.shadowOffset; | |
| 100 NSSize originalOffset = offset; | |
| 101 CGFloat radius = shadow.shadowBlurRadius; | |
| 102 NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius),
-(ABS(offset.height) + radius)); | |
| 103 offset.height += bounds.size.height; | |
| 104 shadow.shadowOffset = offset; | |
| 105 NSAffineTransform *transform = [NSAffineTransform transform]; | |
| 106 if ([[NSGraphicsContext currentContext] isFlipped]) | |
| 107 [transform translateXBy:0 yBy:bounds.size.height]; | |
| 108 else | |
| 109 [transform translateXBy:0 yBy:-bounds.size.height]; | |
| 110 | |
| 111 NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds]; | |
| 112 [drawingPath setWindingRule:NSEvenOddWindingRule]; | |
| 113 [drawingPath appendBezierPath:self]; | |
| 114 [drawingPath transformUsingAffineTransform:transform]; | |
| 115 | |
| 116 [self addClip]; | |
| 117 [shadow set]; | |
| 118 [[NSColor blackColor] set]; | |
| 119 [drawingPath fill]; | |
| 120 | |
| 121 shadow.shadowOffset = originalOffset; | |
| 122 | |
| 123 [NSGraphicsContext restoreGraphicsState]; | |
| 124 } | |
| 125 | |
| 126 - (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius | |
| 127 { | |
| 128 NSRect bounds = NSInsetRect(self.bounds, -radius, -radius); | |
| 129 NSShadow *shadow = [[NSShadow alloc] init]; | |
| 130 shadow.shadowOffset = NSMakeSize(0, bounds.size.height); | |
| 131 shadow.shadowBlurRadius = radius; | |
| 132 shadow.shadowColor = color; | |
| 133 NSBezierPath *path = [self copy]; | |
| 134 NSAffineTransform *transform = [NSAffineTransform transform]; | |
| 135 if ([[NSGraphicsContext currentContext] isFlipped]) | |
| 136 [transform translateXBy:0 yBy:bounds.size.height]; | |
| 137 else | |
| 138 [transform translateXBy:0 yBy:-bounds.size.height]; | |
| 139 [path transformUsingAffineTransform:transform]; | |
| 140 | |
| 141 [NSGraphicsContext saveGraphicsState]; | |
| 142 | |
| 143 [shadow set]; | |
| 144 [[NSColor blackColor] set]; | |
| 145 NSRectClip(bounds); | |
| 146 [path fill]; | |
| 147 | |
| 148 [NSGraphicsContext restoreGraphicsState]; | |
| 149 | |
| 150 [path release]; | |
| 151 [shadow release]; | |
| 152 } | |
| 153 | |
| 154 // Credit for the next two methods goes to Matt Gemmell | |
| 155 - (void)strokeInside | |
| 156 { | |
| 157 /* Stroke within path using no additional clipping rectangle. */ | |
| 158 [self strokeInsideWithinRect:NSZeroRect]; | |
| 159 } | |
| 160 | |
| 161 - (void)strokeInsideWithinRect:(NSRect)clipRect | |
| 162 { | |
| 163 NSGraphicsContext *thisContext = [NSGraphicsContext currentContext]; | |
| 164 float lineWidth = [self lineWidth]; | |
| 165 | |
| 166 /* Save the current graphics context. */ | |
| 167 [thisContext saveGraphicsState]; | |
| 168 | |
| 169 /* Double the stroke width, since -stroke centers strokes on paths. */ | |
| 170 [self setLineWidth:(lineWidth * 2.0)]; | |
| 171 | |
| 172 /* Clip drawing to this path; draw nothing outwith the path. */ | |
| 173 [self setClip]; | |
| 174 | |
| 175 /* Further clip drawing to clipRect, usually the view's frame. */ | |
| 176 if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) { | |
| 177 [NSBezierPath clipRect:clipRect]; | |
| 178 } | |
| 179 | |
| 180 /* Stroke the path. */ | |
| 181 [self stroke]; | |
| 182 | |
| 183 /* Restore the previous graphics context. */ | |
| 184 [thisContext restoreGraphicsState]; | |
| 185 [self setLineWidth:lineWidth]; | |
| 186 } | |
| 187 | |
| 188 @end | |
| OLD | NEW |