// // DSBezierPathCategories.m // Shared categories // // Created by David Sinclair on Fri Oct 29 2004. // Copyright (c) 2004 - 2007 Dejal Systems, LLC. All rights reserved. // // Portions based on sample code from . // Portions based on sample code from . // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // Redistributions of source code must retain this list of conditions and the following disclaimer. // // The name of Dejal Systems, LLC may not be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THIS SOFTWARE. // #import "DSBezierPathCategories.h" @implementation NSBezierPath (DSBezierPathCategories) + (NSBezierPath *)bezierPathWithPlateInRect:(NSRect)rect { NSBezierPath *result = [[NSBezierPath alloc] init]; [result appendBezierPathWithPlateInRect:rect]; return [result autorelease]; } - (void)appendBezierPathWithPlateInRect:(NSRect)rect { if (rect.size.height > 0) { float xoff = rect.origin.x; float yoff = rect.origin.y; float radius = rect.size.height/2.0; NSPoint point4 = NSMakePoint(xoff+radius, yoff+rect.size.height); NSPoint center1 = NSMakePoint(xoff+radius, yoff+radius); NSPoint center2 = NSMakePoint(xoff+rect.size.width-radius, yoff+radius); [self moveToPoint:point4]; [self appendBezierPathWithArcWithCenter:center1 radius:radius startAngle:90.0 endAngle:270.0]; [self appendBezierPathWithArcWithCenter:center2 radius:radius startAngle:270.0 endAngle:90.0]; [self closePath]; } } + (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius { NSBezierPath *result = [[[NSBezierPath alloc] init] autorelease]; [result appendBezierPathWithRoundedRect:rect cornerRadius:radius]; return result; } - (void)appendBezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius { if (rect.size.height > 0) { float xoff = rect.origin.x; float yoff = rect.origin.y; NSPoint startpoint = NSMakePoint(xoff, yoff+radius); NSPoint center1 = NSMakePoint(xoff+radius, yoff+radius); NSPoint center2 = NSMakePoint(xoff+rect.size.width-radius, yoff+radius); NSPoint center3 = NSMakePoint(xoff+rect.size.width-radius, yoff+rect.size.height-radius); NSPoint center4 = NSMakePoint(xoff+radius, yoff+rect.size.height-radius); [self moveToPoint:startpoint]; [self appendBezierPathWithArcWithCenter:center1 radius:radius startAngle:180.0 endAngle:270.0]; [self appendBezierPathWithArcWithCenter:center2 radius:radius startAngle:270.0 endAngle:360.0]; [self appendBezierPathWithArcWithCenter:center3 radius:radius startAngle:360.0 endAngle:90.0]; [self appendBezierPathWithArcWithCenter:center4 radius:radius startAngle:90.0 endAngle:180.0]; [self closePath]; } } + (NSBezierPath *)bezierPathWithTriangleInRect:(NSRect)aRect orientation:(DSTriangleOrientation)orientation { NSBezierPath *result = [[[NSBezierPath alloc] init] autorelease]; [result appendBezierPathWithTriangleInRect:aRect orientation:orientation]; return result; } - (void)appendBezierPathWithTriangleInRect:(NSRect)aRect orientation:(DSTriangleOrientation)orientation { NSPoint a, b, c; switch (orientation) { case DSTriangleUp: { a = NSMakePoint(NSMinX(aRect), NSMinY(aRect)); b = NSMakePoint((NSMinX(aRect) + NSMaxX(aRect)) / 2, NSMaxY(aRect)); c = NSMakePoint(NSMaxX(aRect), NSMinY(aRect)); break; } case DSTriangleDown: { a = NSMakePoint(NSMinX(aRect), NSMaxY(aRect)); c = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect)); b = NSMakePoint((NSMinX(aRect) + NSMaxX(aRect)) / 2, NSMinY(aRect)); break; } case DSTriangleLeft: { a = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect)); b = NSMakePoint(NSMaxX(aRect), NSMinY(aRect)); c = NSMakePoint(NSMinX(aRect), (NSMinY(aRect) + NSMaxY(aRect)) / 2); break; } default : // case DSTriangleRight: { a = NSMakePoint(NSMinX(aRect), NSMinY(aRect)); b = NSMakePoint(NSMinX(aRect), NSMaxY(aRect)); c = NSMakePoint(NSMaxX(aRect), (NSMinY(aRect) + NSMaxY(aRect)) / 2); break; } } [self moveToPoint:a]; [self lineToPoint:b]; [self lineToPoint:c]; [self closePath]; } static void linearShadedColor(void *info, const float *in, float *out) { float *colors = info; *out++ = colors[0] + *in * colors[8]; *out++ = colors[1] + *in * colors[9]; *out++ = colors[2] + *in * colors[10]; *out++ = colors[3] + *in * colors[11]; } static void bilinearShadedColor(void *info, const float *in, float *out) { float *colors = info; float factor = (*in)*2.0; if (*in > 0.5) { factor = 2-factor; } *out++ = colors[0] + factor * colors[8]; *out++ = colors[1] + factor * colors[9]; *out++ = colors[2] + factor * colors[10]; *out++ = colors[3] + factor * colors[11]; } - (void)linearGradientFillWithStartColor:(NSColor *)startColor endColor:(NSColor *)endColor { static const CGFunctionCallbacks callbacks = {0, &linearShadedColor, NULL}; [self customVerticalFillWithCallbacks:callbacks firstColor:startColor secondColor:endColor]; }; - (void)bilinearGradientFillWithOuterColor:(NSColor *)outerColor innerColor:(NSColor *)innerColor { static const CGFunctionCallbacks callbacks = {0, &bilinearShadedColor, NULL}; [self customVerticalFillWithCallbacks:callbacks firstColor:innerColor secondColor:outerColor]; } - (void)customVerticalFillWithCallbacks:(CGFunctionCallbacks)functionCallbacks firstColor:(NSColor *)firstColor secondColor:(NSColor *)secondColor { CGColorSpaceRef colorspace; CGShadingRef shading; CGPoint startPoint = {0, 0}; CGPoint endPoint = {0, 0}; CGFunctionRef function; float colors[12]; // pointer to color values // get my context CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; NSColor *deviceDependentFirstColor = [firstColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; NSColor *deviceDependentSecondColor = [secondColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; // set up colors for gradient colors[0] = [deviceDependentFirstColor redComponent]; colors[1] = [deviceDependentFirstColor greenComponent]; colors[2] = [deviceDependentFirstColor blueComponent]; colors[3] = [deviceDependentFirstColor alphaComponent]; colors[4] = [deviceDependentSecondColor redComponent]; colors[5] = [deviceDependentSecondColor greenComponent]; colors[6] = [deviceDependentSecondColor blueComponent]; colors[7] = [deviceDependentSecondColor alphaComponent]; // difference between start and end color for each color components colors[8] = (colors[4]-colors[0]); colors[9] = (colors[5]-colors[1]); colors[10] = (colors[6]-colors[2]); colors[11] = (colors[7]-colors[3]); // draw gradient colorspace = CGColorSpaceCreateDeviceRGB(); size_t components = 1 + CGColorSpaceGetNumberOfComponents(colorspace); static const float domain[2] = {0.0, 1.0}; static const float range[10] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; //static const CGFunctionCallbacks callbacks = {0, &bilinearShadedColor, NULL}; // Create a CGFunctionRef that describes a function taking 1 input and kChannelsPerColor outputs. function = CGFunctionCreate(colors, 1, domain, components, range, &functionCallbacks); startPoint.x=0; startPoint.y=[self bounds].origin.y; endPoint.x=0; endPoint.y=NSMaxY([self bounds]); shading = CGShadingCreateAxial(colorspace, startPoint, endPoint, function, NO, NO); CGContextSaveGState(currentContext); [self addClip]; CGContextDrawShading(currentContext, shading); CGContextRestoreGState(currentContext); CGShadingRelease(shading); CGFunctionRelease(function); CGColorSpaceRelease(colorspace); } @end // ---------------------------------------------------------------------------------------- #pragma mark - #pragma mark CONVENIENCE FUNCTIONS // ---------------------------------------------------------------------------------------- /* DSFrameRoundedRect() Convenience function to frame a rounded rectangle. See also DSFrameRoundedRectWithWidth() and -appendBezierPathWithRoundedRect:cornerRadius:. Written by DJS 2004-10. */ void DSFrameRoundedRect(NSRect aRect, float radius) { NSBezierPath *path = [NSBezierPath bezierPath]; [path appendBezierPathWithRoundedRect:aRect cornerRadius:radius]; [path stroke]; } /* DSFrameRoundedRectWithWidth() Convenience function to frame a rounded rectangle, specifying a line width. See also DSFrameRoundedRect() and -appendBezierPathWithRoundedRect:cornerRadius:. Written by DJS 2004-10. */ void DSFrameRoundedRectWithWidth(NSRect aRect, float radius, float width) { NSBezierPath *path = [NSBezierPath bezierPath]; [path appendBezierPathWithRoundedRect:aRect cornerRadius:radius]; [path setLineWidth:width]; [path stroke]; }