diff --git a/Sample/Sample.xcodeproj/project.pbxproj b/Sample/Sample.xcodeproj/project.pbxproj index a83daa6..8d4413a 100644 --- a/Sample/Sample.xcodeproj/project.pbxproj +++ b/Sample/Sample.xcodeproj/project.pbxproj @@ -13,6 +13,13 @@ CBE8AF4E13655C3C0056207D /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = CBE8AF4C13655C3C0056207D /* Credits.rtf */; }; CBE8AF5113655C3C0056207D /* SampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE8AF5013655C3C0056207D /* SampleAppDelegate.m */; }; CBE8AF5413655C3C0056207D /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE8AF5213655C3C0056207D /* MainMenu.xib */; }; + CBE8AF6B13655CA70056207D /* ANSegmentedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE8AF6413655CA70056207D /* ANSegmentedCell.m */; }; + CBE8AF6C13655CA70056207D /* ANSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE8AF6613655CA70056207D /* ANSegmentedControl.m */; }; + CBE8AF6D13655CA70056207D /* NSBezierPath+MCAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE8AF6813655CA70056207D /* NSBezierPath+MCAdditions.m */; }; + CBE8AF6E13655CA70056207D /* NSShadow+MCAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE8AF6A13655CA70056207D /* NSShadow+MCAdditions.m */; }; + CBE8AF7413655CAC0056207D /* FilterNone.png in Resources */ = {isa = PBXBuildFile; fileRef = CBE8AF7113655CAC0056207D /* FilterNone.png */; }; + CBE8AF7513655CAC0056207D /* FilterStarred.png in Resources */ = {isa = PBXBuildFile; fileRef = CBE8AF7213655CAC0056207D /* FilterStarred.png */; }; + CBE8AF7613655CAC0056207D /* FilterUnread.png in Resources */ = {isa = PBXBuildFile; fileRef = CBE8AF7313655CAC0056207D /* FilterUnread.png */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,6 +36,17 @@ CBE8AF4F13655C3C0056207D /* SampleAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleAppDelegate.h; sourceTree = ""; }; CBE8AF5013655C3C0056207D /* SampleAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleAppDelegate.m; sourceTree = ""; }; CBE8AF5313655C3C0056207D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; + CBE8AF6313655CA70056207D /* ANSegmentedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANSegmentedCell.h; sourceTree = ""; }; + CBE8AF6413655CA70056207D /* ANSegmentedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANSegmentedCell.m; sourceTree = ""; }; + CBE8AF6513655CA70056207D /* ANSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANSegmentedControl.h; sourceTree = ""; }; + CBE8AF6613655CA70056207D /* ANSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANSegmentedControl.m; sourceTree = ""; }; + CBE8AF6713655CA70056207D /* NSBezierPath+MCAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+MCAdditions.h"; sourceTree = ""; }; + CBE8AF6813655CA70056207D /* NSBezierPath+MCAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBezierPath+MCAdditions.m"; sourceTree = ""; }; + CBE8AF6913655CA70056207D /* NSShadow+MCAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSShadow+MCAdditions.h"; sourceTree = ""; }; + CBE8AF6A13655CA70056207D /* NSShadow+MCAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSShadow+MCAdditions.m"; sourceTree = ""; }; + CBE8AF7113655CAC0056207D /* FilterNone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FilterNone.png; sourceTree = ""; }; + CBE8AF7213655CAC0056207D /* FilterStarred.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FilterStarred.png; sourceTree = ""; }; + CBE8AF7313655CAC0056207D /* FilterUnread.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FilterUnread.png; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,6 +100,8 @@ CBE8AF4313655C3C0056207D /* Sample */ = { isa = PBXGroup; children = ( + CBE8AF7013655CAC0056207D /* Resources */, + CBE8AF6213655CA70056207D /* ANSegmentedControl */, CBE8AF4F13655C3C0056207D /* SampleAppDelegate.h */, CBE8AF5013655C3C0056207D /* SampleAppDelegate.m */, CBE8AF5213655C3C0056207D /* MainMenu.xib */, @@ -102,6 +122,32 @@ name = "Supporting Files"; sourceTree = ""; }; + CBE8AF6213655CA70056207D /* ANSegmentedControl */ = { + isa = PBXGroup; + children = ( + CBE8AF6313655CA70056207D /* ANSegmentedCell.h */, + CBE8AF6413655CA70056207D /* ANSegmentedCell.m */, + CBE8AF6513655CA70056207D /* ANSegmentedControl.h */, + CBE8AF6613655CA70056207D /* ANSegmentedControl.m */, + CBE8AF6713655CA70056207D /* NSBezierPath+MCAdditions.h */, + CBE8AF6813655CA70056207D /* NSBezierPath+MCAdditions.m */, + CBE8AF6913655CA70056207D /* NSShadow+MCAdditions.h */, + CBE8AF6A13655CA70056207D /* NSShadow+MCAdditions.m */, + ); + path = ANSegmentedControl; + sourceTree = ""; + }; + CBE8AF7013655CAC0056207D /* Resources */ = { + isa = PBXGroup; + children = ( + CBE8AF7113655CAC0056207D /* FilterNone.png */, + CBE8AF7213655CAC0056207D /* FilterStarred.png */, + CBE8AF7313655CAC0056207D /* FilterUnread.png */, + ); + name = Resources; + path = Sample/Resources; + sourceTree = SOURCE_ROOT; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -152,6 +198,9 @@ CBE8AF4813655C3C0056207D /* InfoPlist.strings in Resources */, CBE8AF4E13655C3C0056207D /* Credits.rtf in Resources */, CBE8AF5413655C3C0056207D /* MainMenu.xib in Resources */, + CBE8AF7413655CAC0056207D /* FilterNone.png in Resources */, + CBE8AF7513655CAC0056207D /* FilterStarred.png in Resources */, + CBE8AF7613655CAC0056207D /* FilterUnread.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -164,6 +213,10 @@ files = ( CBE8AF4B13655C3C0056207D /* main.m in Sources */, CBE8AF5113655C3C0056207D /* SampleAppDelegate.m in Sources */, + CBE8AF6B13655CA70056207D /* ANSegmentedCell.m in Sources */, + CBE8AF6C13655CA70056207D /* ANSegmentedControl.m in Sources */, + CBE8AF6D13655CA70056207D /* NSBezierPath+MCAdditions.m in Sources */, + CBE8AF6E13655CA70056207D /* NSShadow+MCAdditions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -278,6 +331,7 @@ CBE8AF5913655C3C0056207D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Sample/Sample/ANSegmentedControl/.DS_Store b/Sample/Sample/ANSegmentedControl/.DS_Store new file mode 100644 index 0000000..94b82bd Binary files /dev/null and b/Sample/Sample/ANSegmentedControl/.DS_Store differ diff --git a/Sample/Sample/ANSegmentedControl/ANSegmentedCell.h b/Sample/Sample/ANSegmentedControl/ANSegmentedCell.h new file mode 100644 index 0000000..4274c6d --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/ANSegmentedCell.h @@ -0,0 +1,16 @@ +// +// ANSegmentedCell.h +// test01 +// +// Created by Decors on 11/04/22. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface ANSegmentedCell : NSSegmentedCell { +@private +} + +@end diff --git a/Sample/Sample/ANSegmentedControl/ANSegmentedCell.m b/Sample/Sample/ANSegmentedControl/ANSegmentedCell.m new file mode 100644 index 0000000..997148a --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/ANSegmentedCell.m @@ -0,0 +1,15 @@ +// +// ANSegmentedCell.m +// test01 +// +// Created by Decors on 11/04/22. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "ANSegmentedCell.h" +#import "NSBezierPath+MCAdditions.h" +#import "NSShadow+MCAdditions.h" + +@implementation ANSegmentedCell + +@end diff --git a/Sample/Sample/ANSegmentedControl/ANSegmentedControl.h b/Sample/Sample/ANSegmentedControl/ANSegmentedControl.h new file mode 100644 index 0000000..700a7f9 --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/ANSegmentedControl.h @@ -0,0 +1,22 @@ +// +// ANSegmentedControl.h +// test01 +// +// Created by Decors on 11/04/22. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface ANSegmentedControl : NSSegmentedControl { +@private + NSPoint location; +} + +- (void)drawBackgroud:(NSRect)rect; +- (void)drawKnob:(NSRect)rect; + +-(void)setSelectedSegment:(NSInteger)newSegment animate:(bool)animate; + +@end diff --git a/Sample/Sample/ANSegmentedControl/ANSegmentedControl.m b/Sample/Sample/ANSegmentedControl/ANSegmentedControl.m new file mode 100644 index 0000000..f90ef46 --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/ANSegmentedControl.m @@ -0,0 +1,331 @@ +// +// ANSegmentedControl.m +// test01 +// +// Created by Decors on 11/04/22. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "ANSegmentedControl.h" +#import "ANSegmentedCell.h" +#import "NSBezierPath+MCAdditions.h" +#import "NSShadow+MCAdditions.h" + +@interface ANKnobAnimation : NSAnimation { + int start, range; + id delegate; +} + +@end + +@implementation ANKnobAnimation + +- (id)initWithStart:(int)begin end:(int)end +{ + [super init]; + start = begin; + range = end - begin; + return self; +} + +- (void)setCurrentProgress:(NSAnimationProgress)progress +{ + int x = start + progress * range; + [super setCurrentProgress:progress]; + [delegate performSelector:@selector(setPosition:) + withObject:[NSNumber numberWithInteger:x]]; +} + +- (void)setDelegate:(id)d +{ + delegate = d; +} + +@end + +@interface ANSegmentedControl (Private) +- (void)drawBackgroud:(NSRect)rect; +- (void)drawKnob:(NSRect)rect; +@end + +@implementation ANSegmentedControl + ++ (Class)cellClass +{ + return [ANSegmentedCell class]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if (![aDecoder isKindOfClass:[NSKeyedUnarchiver class]]) + return [super initWithCoder:aDecoder]; + + NSKeyedUnarchiver *unarchiver = (NSKeyedUnarchiver *)aDecoder; + Class oldClass = [[self superclass] cellClass]; + Class newClass = [[self class] cellClass]; + + [unarchiver setClass:newClass forClassName:NSStringFromClass(oldClass)]; + self = [super initWithCoder:aDecoder]; + [unarchiver setClass:oldClass forClassName:NSStringFromClass(oldClass)]; + + return self; +} + +- (void)awakeFromNib +{ + location.x = [self frame].size.width / [self segmentCount] * [self selectedSegment]; + [[self cell] setTrackingMode:NSSegmentSwitchTrackingSelectOne]; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + NSRect rect = dirtyRect; + rect.size.height -= 1; + + [self drawBackgroud:rect]; + [self drawKnob:rect]; +} + +- (void)drawSegment:(NSInteger)segment inFrame:(NSRect)frame withView:(NSView *)controlView +{ + float imageFraction; + + if ([[self window] isKeyWindow]) { + imageFraction = .5; + } else { + imageFraction = .2; + } + + [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh]; + NSRect rect = NSMakeRect(frame.origin.x, + frame.origin.y + 1, + [[self imageForSegment:segment] size].width, + [[self imageForSegment:segment] size].height); + [[self imageForSegment:segment] drawInRect:rect + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:imageFraction + respectFlipped:YES + hints:nil]; +} + +- (void)drawBackgroud:(NSRect)rect +{ + CGFloat radius = 3.5; + NSGradient *gradient; + NSColor *frameColor; + + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:rect + xRadius:radius + yRadius:radius]; + + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + + if ([[self window] isKeyWindow]) { + gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:.75 alpha:1.0] + endingColor:[NSColor colorWithCalibratedWhite:.6 alpha:1.0]]; + frameColor = [[NSColor colorWithCalibratedWhite:.52 alpha:1.0] retain]; + } else { + gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:.8 alpha:1.0] + endingColor:[NSColor colorWithCalibratedWhite:.77 alpha:1.0]]; + frameColor = [[NSColor colorWithCalibratedWhite:.68 alpha:1.0] retain]; + } + + // シャドウ + [ctx saveGraphicsState]; + NSShadow *dropShadow = [[NSShadow alloc] init]; + [dropShadow setShadowOffset:NSMakeSize(0, -1.0)]; + [dropShadow setShadowBlurRadius:1.0]; + [dropShadow setShadowColor:[NSColor colorWithCalibratedWhite:.863 alpha:.75]]; + [dropShadow set]; + [path fill]; + [ctx restoreGraphicsState]; + + // 塗り + [gradient drawInBezierPath:path angle:-90]; + + // 枠線 + [frameColor setStroke]; + [path strokeInside]; + + float segmentWidth = rect.size.width / [self segmentCount]; + float segmentHeight = rect.size.height; + NSRect segmentRect = NSMakeRect(0, 0, segmentWidth, segmentHeight); + + for(int s = 0; s < [self segmentCount]; s ++) { + [self drawSegment:s + inFrame:segmentRect + withView:self]; + segmentRect.origin.x += segmentWidth; + } +} + +- (void)drawKnob:(NSRect)rect +{ + CGFloat radius = 3; + NSGradient *gradient; + float imageFraction; + NSColor *frameColor; + + if ([[self window] isKeyWindow]) { + gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:.68 alpha:1.0] + endingColor:[NSColor colorWithCalibratedWhite:.91 alpha:1.0]]; + imageFraction = 1.0; + frameColor = [[NSColor colorWithCalibratedWhite:.52 alpha:1.0] retain]; + } else { + gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:.76 alpha:1.0] + endingColor:[NSColor colorWithCalibratedWhite:.90 alpha:1.0]]; + imageFraction = .25; + frameColor = [[NSColor colorWithCalibratedWhite:.68 alpha:1.0] retain]; + } + + CGFloat width = rect.size.width / [self segmentCount]; + CGFloat height = rect.size.height; + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(location.x, rect.origin.y, width, height) + xRadius:radius + yRadius:radius]; + // 塗り + [gradient drawInBezierPath:path angle:-90]; + // 枠線 + [frameColor setStroke]; + [path strokeInside]; + + int newSegment = (int)round(location.x / width); + NSPoint pt = location; + pt.y += 1; + NSRect knobRect = NSMakeRect(pt.x, + pt.y, + [[self imageForSegment:newSegment] size].width, + [[self imageForSegment:newSegment] size].height); + [[self imageForSegment:newSegment] drawInRect:knobRect + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:imageFraction + respectFlipped:YES + hints:nil]; +} + +- (void)animateTo:(int)x +{ + float maxX = [self frame].size.width - ([self frame].size.width / [self segmentCount]); + + ANKnobAnimation *a = [[ANKnobAnimation alloc] initWithStart:location.x end:x]; + [a setDelegate:self]; + if (location.x == 0 || location.x == maxX){ + [a setDuration:0.20]; + [a setAnimationCurve:NSAnimationEaseInOut]; + } else { + [a setDuration:0.35 * ((fabs(location.x - x)) / maxX)]; + [a setAnimationCurve:NSAnimationLinear]; + } + + [a setAnimationBlockingMode:NSAnimationBlocking]; + [a startAnimation]; + [a release]; +} + + +- (void)setPosition:(NSNumber*)x +{ + location.x = [x intValue]; + [self display]; +} + +- (void)setSelectedSegment:(NSInteger)newSegment +{ + [self setSelectedSegment:newSegment animate:true]; +} + +- (void)setSelectedSegment:(NSInteger)newSegment animate:(bool)animate +{ + if(newSegment == [self selectedSegment]) + return; + + float maxX = [self frame].size.width - ([self frame].size.width / [self segmentCount]); + + int x = newSegment > [self segmentCount] ? maxX : newSegment * ([self frame].size.width / [self segmentCount]); + + if(animate) + [self animateTo:x]; + else { + [self setNeedsDisplay:YES]; + } + + [super setSelectedSegment:newSegment]; +} + + +- (void)offsetLocationByX:(float)x +{ + location.x = location.x + x; + float maxX = [self frame].size.width - ([self frame].size.width / [self segmentCount]); + + if (location.x < 0) location.x = 0; + if (location.x > maxX) location.x = maxX; + + [self setNeedsDisplay:YES]; +} + +- (void)mouseDown:(NSEvent *)event +{ + BOOL loop = YES; + + NSPoint clickLocation = [self convertPoint:[event locationInWindow] fromView:nil]; + float knobWidth = [self frame].size.width / [self segmentCount]; + NSRect knobRect = NSMakeRect(location.x, 0, knobWidth, [self frame].size.height); + + if (NSPointInRect(clickLocation, [self bounds])) { + NSPoint newDragLocation; + NSPoint localLastDragLocation; + localLastDragLocation = clickLocation; + + while (loop) { + NSEvent *localEvent; + localEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask]; + + switch ([localEvent type]) { + case NSLeftMouseDragged: + if (NSPointInRect(clickLocation, knobRect)) { + newDragLocation = [self convertPoint:[localEvent locationInWindow] + fromView:nil]; + + [self offsetLocationByX:(newDragLocation.x - localLastDragLocation.x)]; + + localLastDragLocation = newDragLocation; + [self autoscroll:localEvent]; + } + break; + case NSLeftMouseUp: + NSLog(@"mouseup"); + loop = NO; + + int newSegment; + + if (memcmp(&clickLocation, &localLastDragLocation, sizeof(NSPoint)) == 0) { + newSegment = floor(clickLocation.x / knobWidth); + //if (newSegment != [self selectedSegment]) { + [self animateTo:newSegment * knobWidth]; + //} + } else { + newSegment = (int)round(location.x / knobWidth); + [self animateTo:newSegment * knobWidth]; + } + + [self setSelectedSegment:newSegment]; + [[self window] invalidateCursorRectsForView:self]; + + break; + default: + break; + } + } + }; + return; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +@end diff --git a/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.h b/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.h new file mode 100644 index 0000000..972856d --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.h @@ -0,0 +1,24 @@ +// +// NSBezierPath+MCAdditions.h +// +// Created by Sean Patrick O'Brien on 4/1/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#import + + +@interface NSBezierPath (MCAdditions) + ++ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef; +- (CGPathRef)cgPath; + +- (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth; + +- (void)fillWithInnerShadow:(NSShadow *)shadow; +- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius; + +- (void)strokeInside; +- (void)strokeInsideWithinRect:(NSRect)clipRect; + +@end diff --git a/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.m b/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.m new file mode 100644 index 0000000..241d161 --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/NSBezierPath+MCAdditions.m @@ -0,0 +1,225 @@ +// +// NSBezierPath+MCAdditions.m +// +// Created by Sean Patrick O'Brien on 4/1/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#import "NSBezierPath+MCAdditions.h" + +// remove/comment out this line of you don't want to use undocumented functions +#define MCBEZIER_USE_PRIVATE_FUNCTION + +#ifdef MCBEZIER_USE_PRIVATE_FUNCTION +extern CGPathRef CGContextCopyPath(CGContextRef context); +#endif + +static void CGPathCallback(void *info, const CGPathElement *element) +{ + NSBezierPath *path = info; + CGPoint *points = element->points; + + switch (element->type) { + case kCGPathElementMoveToPoint: + { + [path moveToPoint:NSMakePoint(points[0].x, points[0].y)]; + break; + } + case kCGPathElementAddLineToPoint: + { + [path lineToPoint:NSMakePoint(points[0].x, points[0].y)]; + break; + } + case kCGPathElementAddQuadCurveToPoint: + { + // NOTE: This is untested. + NSPoint currentPoint = [path currentPoint]; + NSPoint interpolatedPoint = NSMakePoint((currentPoint.x + 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3); + [path curveToPoint:NSMakePoint(points[1].x, points[1].y) controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint]; + break; + } + case kCGPathElementAddCurveToPoint: + { + [path curveToPoint:NSMakePoint(points[2].x, points[2].y) controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(points[1].x, points[1].y)]; + break; + } + case kCGPathElementCloseSubpath: + { + [path closePath]; + break; + } + } +} + +@implementation NSBezierPath (MCAdditions) + ++ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef +{ + NSBezierPath *path = [NSBezierPath bezierPath]; + CGPathApply(pathRef, path, CGPathCallback); + + return path; +} + +// Method borrowed from Google's Cocoa additions +- (CGPathRef)cgPath +{ + CGMutablePathRef thePath = CGPathCreateMutable(); + if (!thePath) return nil; + + unsigned int elementCount = (unsigned int)[self elementCount]; + + // The maximum number of points is 3 for a NSCurveToBezierPathElement. + // (controlPoint1, controlPoint2, and endPoint) + NSPoint controlPoints[3]; + + for (unsigned int i = 0; i < elementCount; i++) { + switch ([self elementAtIndex:i associatedPoints:controlPoints]) { + case NSMoveToBezierPathElement: + CGPathMoveToPoint(thePath, &CGAffineTransformIdentity, + controlPoints[0].x, controlPoints[0].y); + break; + case NSLineToBezierPathElement: + CGPathAddLineToPoint(thePath, &CGAffineTransformIdentity, + controlPoints[0].x, controlPoints[0].y); + break; + case NSCurveToBezierPathElement: + CGPathAddCurveToPoint(thePath, &CGAffineTransformIdentity, + controlPoints[0].x, controlPoints[0].y, + controlPoints[1].x, controlPoints[1].y, + controlPoints[2].x, controlPoints[2].y); + break; + case NSClosePathBezierPathElement: + CGPathCloseSubpath(thePath); + break; + default: + NSLog(@"Unknown element at [NSBezierPath (GTMBezierPathCGPathAdditions) cgPath]"); + break; + }; + } + return thePath; +} + +- (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth +{ +#ifdef MCBEZIER_USE_PRIVATE_FUNCTION + NSBezierPath *path = [self copy]; + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; + CGPathRef pathRef = [path cgPath]; + [path release]; + + CGContextSaveGState(context); + + CGContextBeginPath(context); + CGContextAddPath(context, pathRef); + CGContextSetLineWidth(context, strokeWidth); + CGContextReplacePathWithStrokedPath(context); + CGPathRef strokedPathRef = CGContextCopyPath(context); + CGContextBeginPath(context); + NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPathRef]; + + CGContextRestoreGState(context); + + CFRelease(pathRef); + CFRelease(strokedPathRef); + + return strokedPath; +#else + return nil; +#endif//MCBEZIER_USE_PRIVATE_FUNCTION +} + +- (void)fillWithInnerShadow:(NSShadow *)shadow +{ + [NSGraphicsContext saveGraphicsState]; + + NSSize offset = shadow.shadowOffset; + NSSize originalOffset = offset; + CGFloat radius = shadow.shadowBlurRadius; + NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius)); + offset.height += bounds.size.height; + shadow.shadowOffset = offset; + NSAffineTransform *transform = [NSAffineTransform transform]; + if ([[NSGraphicsContext currentContext] isFlipped]) + [transform translateXBy:0 yBy:bounds.size.height]; + else + [transform translateXBy:0 yBy:-bounds.size.height]; + + NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds]; + [drawingPath setWindingRule:NSEvenOddWindingRule]; + [drawingPath appendBezierPath:self]; + [drawingPath transformUsingAffineTransform:transform]; + + [self addClip]; + [shadow set]; + [[NSColor blackColor] set]; + [drawingPath fill]; + + shadow.shadowOffset = originalOffset; + + [NSGraphicsContext restoreGraphicsState]; +} + +- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius +{ + NSRect bounds = NSInsetRect(self.bounds, -radius, -radius); + NSShadow *shadow = [[NSShadow alloc] init]; + shadow.shadowOffset = NSMakeSize(0, bounds.size.height); + shadow.shadowBlurRadius = radius; + shadow.shadowColor = color; + NSBezierPath *path = [self copy]; + NSAffineTransform *transform = [NSAffineTransform transform]; + if ([[NSGraphicsContext currentContext] isFlipped]) + [transform translateXBy:0 yBy:bounds.size.height]; + else + [transform translateXBy:0 yBy:-bounds.size.height]; + [path transformUsingAffineTransform:transform]; + + [NSGraphicsContext saveGraphicsState]; + + [shadow set]; + [[NSColor blackColor] set]; + NSRectClip(bounds); + [path fill]; + + [NSGraphicsContext restoreGraphicsState]; + + [path release]; + [shadow release]; +} + +// Credit for the next two methods goes to Matt Gemmell +- (void)strokeInside +{ + /* Stroke within path using no additional clipping rectangle. */ + [self strokeInsideWithinRect:NSZeroRect]; +} + +- (void)strokeInsideWithinRect:(NSRect)clipRect +{ + NSGraphicsContext *thisContext = [NSGraphicsContext currentContext]; + float lineWidth = [self lineWidth]; + + /* Save the current graphics context. */ + [thisContext saveGraphicsState]; + + /* Double the stroke width, since -stroke centers strokes on paths. */ + [self setLineWidth:(lineWidth * 2.0)]; + + /* Clip drawing to this path; draw nothing outwith the path. */ + [self setClip]; + + /* Further clip drawing to clipRect, usually the view's frame. */ + if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) { + [NSBezierPath clipRect:clipRect]; + } + + /* Stroke the path. */ + [self stroke]; + + /* Restore the previous graphics context. */ + [thisContext restoreGraphicsState]; + [self setLineWidth:lineWidth]; +} + +@end diff --git a/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.h b/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.h new file mode 100644 index 0000000..5870d51 --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.h @@ -0,0 +1,15 @@ +// +// NSShadow+MCAdditions.h +// +// Created by Sean Patrick O'Brien on 4/3/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#import + + +@interface NSShadow (MCAdditions) + +- (id)initWithColor:(NSColor *)color offset:(NSSize)offset blurRadius:(CGFloat)blur; + +@end diff --git a/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.m b/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.m new file mode 100644 index 0000000..2c0bab3 --- /dev/null +++ b/Sample/Sample/ANSegmentedControl/NSShadow+MCAdditions.m @@ -0,0 +1,26 @@ +// +// NSShadow+MCAdditions.m +// +// Created by Sean Patrick O'Brien on 4/3/08. +// Copyright 2008 MolokoCacao. All rights reserved. +// + +#import "NSShadow+MCAdditions.h" + + +@implementation NSShadow (MCAdditions) + +- (id)initWithColor:(NSColor *)color offset:(NSSize)offset blurRadius:(CGFloat)blur +{ + self = [self init]; + + if (self != nil) { + self.shadowColor = color; + self.shadowOffset = offset; + self.shadowBlurRadius = blur; + } + + return self; +} + +@end diff --git a/Sample/Sample/Resources/.DS_Store b/Sample/Sample/Resources/.DS_Store new file mode 100644 index 0000000..b07a411 Binary files /dev/null and b/Sample/Sample/Resources/.DS_Store differ diff --git a/Sample/Sample/Resources/FilterNone.png b/Sample/Sample/Resources/FilterNone.png new file mode 100644 index 0000000..5d1ff6c Binary files /dev/null and b/Sample/Sample/Resources/FilterNone.png differ diff --git a/Sample/Sample/Resources/FilterStarred.png b/Sample/Sample/Resources/FilterStarred.png new file mode 100644 index 0000000..5651928 Binary files /dev/null and b/Sample/Sample/Resources/FilterStarred.png differ diff --git a/Sample/Sample/Resources/FilterUnread.png b/Sample/Sample/Resources/FilterUnread.png new file mode 100644 index 0000000..d65dfa2 Binary files /dev/null and b/Sample/Sample/Resources/FilterUnread.png differ diff --git a/Sample/Sample/SampleAppDelegate.h b/Sample/Sample/SampleAppDelegate.h index a86203a..25d9a09 100644 --- a/Sample/Sample/SampleAppDelegate.h +++ b/Sample/Sample/SampleAppDelegate.h @@ -7,12 +7,19 @@ // #import +#import "ANSegmentedControl.h" @interface SampleAppDelegate : NSObject { @private NSWindow *window; + ANSegmentedControl *segment; } @property (assign) IBOutlet NSWindow *window; +@property (assign) IBOutlet ANSegmentedControl *segment; + +- (IBAction)clickButton1:(id)sender; +- (IBAction)clickButton2:(id)sender; +- (IBAction)clickButton3:(id)sender; @end diff --git a/Sample/Sample/SampleAppDelegate.m b/Sample/Sample/SampleAppDelegate.m index 64c5843..086e135 100644 --- a/Sample/Sample/SampleAppDelegate.m +++ b/Sample/Sample/SampleAppDelegate.m @@ -11,10 +11,26 @@ @implementation SampleAppDelegate @synthesize window; +@synthesize segment; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application } +- (IBAction)clickButton1:(id)sender +{ + [segment setSelectedSegment:0]; +} + +- (IBAction)clickButton2:(id)sender +{ + [segment setSelectedSegment:1]; +} + +- (IBAction)clickButton3:(id)sender +{ + [segment setSelectedSegment:2]; +} + @end