Faster iLifeControls
I’m working on a project that uses Sean Patrick O’Brien’s iLifeControls. My application is a QuickTime editing tool, and I quickly ran into performance problems that I traced to the NFIFrame class within iLifeControls. Here is an updated version of NFIFrame that consumes ~50% less CPU time doing a window refresh.
NOTE: My changes are enclosed in #ifdef FASTER blocks.
NFIFrame.h
// // NFIFrame.h // iLife Window // // Created by Sean Patrick O'Brien on 9/15/06. // Copyright 2006 Sean Patrick O'Brien. All rights reserved. // #import#import "NSGrayFrame.h" #define FASTER 1 @class NSGrayFrame; @interface NFIFrame : NSGrayFrame { float mTitleBarHeight; float mBottomBarHeight; float mMidBarHeight; float mMidBarOriginY; id mInnerGradient; id mOuterGradient; #if FASTER NSImage* mCachedBackground; #endif } + (NSBezierPath*)_clippingPathForFrame:(NSRect)frame; + (float)cornerRadius; - (void)_drawTitleBar:(NSRect)rect; - (void)_drawMidBar:(NSRect)rect; - (void)_drawBottomBar:(NSRect)rect; - (void)_drawTitle:(NSRect)rect; - (id)backgroundColor; - (id)gradientStartColor; - (id)gradientEndColor; - (id)gradient2StartColor; - (id)gradient2EndColor; - (id)edgeColor; - (id)bottomEdgeColor; - (id)topWindowEdgeColor; - (id)bottomWindowEdgeColor; - (id)titleColor; - (float)titleBarHeight; - (void)setTitleBarHeight:(float)height; - (float)bottomBarHeight; - (void)setBottomBarHeight:(float)height; - (float)midBarHeight; - (float)midBarOriginY; - (void)setMidBarHeight:(float)height origin:(float)origin; @end
NFIFrame.m
//
// NFIFrame.m
// CustomWindow
//
// Created by Sean Patrick O'Brien on 9/15/06.
// Copyright 2006 Sean Patrick O'Brien. All rights reserved.
//
#import "NFIFrame.h"
#import "CTGradient.h"
#import "EtchedTextCell.h"
#import "NSImage+FrameworkImage.h"
@implementation NFIFrame
- (id)initWithFrame:(struct _NSRect)frame styleMask:(unsigned int)style owner:(id)o
{
self = [super initWithFrame:frame styleMask:style owner:o];
mTitleBarHeight = 25.0f;
mBottomBarHeight = 0;
mMidBarOriginY = 0;
mMidBarHeight = 0;
mInnerGradient = [[CTGradient gradientWithBeginningColor: [self gradientStartColor]
endingColor:[self gradientEndColor]] retain];
mOuterGradient = [[CTGradient gradientWithBeginningColor: [self gradient2StartColor]
endingColor:[self gradient2EndColor]] retain];
titleCell = [[EtchedTextCell alloc] initTextCell: @""];
[titleCell setFont:[NSFont fontWithName:@"LucidaGrande" size:13.0]];
[titleCell setShadowColor:[NSColor whiteColor]];
return self;
}
#if FASTER
- (void) dealloc
{
[mCachedBackground release];
[super dealloc];
}
#endif
- (NSSize)_topCornerSize
{
return NSMakeSize(0, [self titleBarHeight]);
}
+ (NSBezierPath*)_clippingPathForFrame:(NSRect)aRect
{
float radius = [self cornerRadius];
NSBezierPath *path = [NSBezierPath alloc];
NSPoint topMid = NSMakePoint(NSMidX(aRect), NSMaxY(aRect));
NSPoint topLeft = NSMakePoint(NSMinX(aRect), NSMaxY(aRect));
NSPoint topRight = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect));
NSPoint bottomRight = NSMakePoint(NSMaxX(aRect), NSMinY(aRect));
[path moveToPoint: topMid];
[path appendBezierPathWithArcFromPoint: topRight
toPoint: bottomRight
radius: radius];
[path appendBezierPathWithArcFromPoint: bottomRight
toPoint: aRect.origin
radius: radius];
[path appendBezierPathWithArcFromPoint: aRect.origin
toPoint: topLeft
radius: radius];
[path appendBezierPathWithArcFromPoint: topLeft
toPoint: topRight
radius: radius];
[path closePath];
return path;
}
- (void)_drawTitle:(NSRect)rect
{
[self _drawTitleStringIn:rect withColor:[self titleColor]];
}
- (void)_drawTitleBar:(NSRect)rect
{
[[self topWindowEdgeColor] set];
NSRectFill(rect);
rect.size.height--;
[[self bottomEdgeColor] set];
NSRectFill(rect);
rect.size.height++;
NSRect gradientRect = rect;
gradientRect.origin.y++;
gradientRect.size.height -= 2;
[mOuterGradient fillRect: gradientRect angle:-90.0f];
gradientRect.origin.x++;
gradientRect.size.width -= 2;
[mInnerGradient fillRect: gradientRect angle:-90.0f];
NSImage *topLeft = [NSImage frameworkImageNamed: @"IWWindowCornerTL"];
NSImage *topRight = [NSImage frameworkImageNamed: @"IWWindowCornerTR"];
[topLeft compositeToPoint:NSMakePoint(rect.origin.x,
rect.origin.y + [self titleBarHeight] - [topLeft size].height) operation: NSCompositeSourceOver];
[topRight compositeToPoint:NSMakePoint(rect.origin.x + rect.size.width-[topRight size].width,
rect.origin.y + [self titleBarHeight] - [topLeft size].height) operation: NSCompositeSourceOver];
[self _drawTitle:rect];
}
- (void)_drawMidBar:(NSRect)rect
{
[[self bottomWindowEdgeColor] set];
NSRectFill(rect);
rect.origin.y++;
rect.size.height--;
[[self bottomEdgeColor] set];
NSRectFill(rect);
rect.size.height -= 2;
rect.origin.y++;
[[self edgeColor] set];
NSRectFill(rect);
rect.size.height += 3;
rect.origin.y -= 2;
NSRect gradientRect = rect;
gradientRect.origin.y++;
gradientRect.size.height -= 3;
[mOuterGradient fillRect: gradientRect angle:-90.0f];
gradientRect.origin.x++;
gradientRect.size.width -= 2;
[mInnerGradient fillRect: gradientRect angle:-90.0f];
}
- (void)_drawBottomBar:(NSRect)rect
{
[[self bottomWindowEdgeColor] set];
NSRectFill(rect);
rect.origin.y++;
rect.size.height--;
[[self bottomEdgeColor] set];
NSRectFill(rect);
rect.size.height -= 2;
rect.origin.y++;
[[self edgeColor] set];
NSRectFill(rect);
rect.size.height += 3;
rect.origin.y -= 2;
NSRect gradientRect = rect;
gradientRect.origin.y++;
gradientRect.size.height -= 3;
[mOuterGradient fillRect: gradientRect angle:-90.0f];
gradientRect.origin.x++;
gradientRect.size.width -= 2;
[mInnerGradient fillRect: gradientRect angle:-90.0f];
NSImage *bottomLeft = [NSImage frameworkImageNamed: @"IWWindowCornerBL"];
NSImage *bottomRight = [NSImage frameworkImageNamed: @"IWWindowCornerBR"];
[bottomLeft compositeToPoint:NSMakePoint(rect.origin.x, rect.origin.y) operation: NSCompositeSourceOver];
[bottomRight compositeToPoint:NSMakePoint(rect.origin.x + rect.size.width-[bottomRight size].width, rect.origin.y) operation: NSCompositeSourceOver];
}
- (void)drawRect:(struct _NSRect)_rect
{
NSRect rect = [self bounds];
#if FASTER
NSSize size = mCachedBackground ? [mCachedBackground size] : NSZeroSize;
if (!mCachedBackground || size.width != NSWidth(rect) || size.height != NSHeight(rect))
{
[mCachedBackground release];
mCachedBackground = [[NSImage alloc] initWithSize:rect.size];
[mCachedBackground lockFocus];
{
[[NSColor clearColor] set];
NSRectFill(_rect);
NSBezierPath *path = [[self class] _clippingPathForFrame: rect];
[path addClip];
[[self backgroundColor] set];
NSRectFill(rect);
NSRect titleBarRect = rect;
titleBarRect.origin.y += rect.size.height - [self titleBarHeight];
titleBarRect.size.height = [self titleBarHeight];
NSRect bottomBarRect = rect;
bottomBarRect.size.height = [self bottomBarHeight];
NSRect midBarRect = rect;
midBarRect.origin.y += [self midBarOriginY];
midBarRect.size.height = [self midBarHeight];
[self _drawMidBar: midBarRect];
[self _drawTitleBar: titleBarRect];
[self _drawBottomBar: bottomBarRect];
}
[mCachedBackground unlockFocus];
}
[[NSColor clearColor] set];
NSRectFill(NSUnionRect(rect, _rect));
[mCachedBackground drawInRect:_rect
fromRect:_rect
operation:NSCompositeSourceOver
fraction:1.0];
#else
[[NSColor clearColor] set];
NSRectFill(rect);
NSRectFill(_rect);
NSBezierPath *path = [[self class] _clippingPathForFrame: rect];
[path addClip];
[[self backgroundColor] set];
NSRectFill(rect);
NSRect titleBarRect = rect;
titleBarRect.origin.y += rect.size.height - [self titleBarHeight];
titleBarRect.size.height = [self titleBarHeight];
NSRect bottomBarRect = rect;
bottomBarRect.size.height = [self bottomBarHeight];
NSRect midBarRect = rect;
midBarRect.origin.y += [self midBarOriginY];
midBarRect.size.height = [self midBarHeight];
[self _drawMidBar: midBarRect];
[self _drawTitleBar: titleBarRect];
[self _drawBottomBar: bottomBarRect];
#endif
}
- (void)_drawGrowBoxWithClip:(struct _NSRect)rect
{
rect.origin.x += 3;
rect.origin.y += 2;
NSImage *resize = [NSImage frameworkImageNamed:@"IWWindowResizeControl"];
[resize compositeToPoint:rect.origin operation: NSCompositeSourceOver];
}
- (float)titleBarHeight
{
if([self _toolbarIsShown])
return mTitleBarHeight + [self _distanceFromToolbarBaseToTitlebar];
return mTitleBarHeight;
}
- (void)setTitleBarHeight:(float)height
{
mTitleBarHeight = height;
#if FASTER
[mCachedBackground release];
mCachedBackground = nil;
#endif
[self setNeedsDisplay:YES];
}
- (float)bottomBarHeight
{
return mBottomBarHeight;
}
- (void)setBottomBarHeight:(float)height
{
mBottomBarHeight = height;
#if FASTER
[mCachedBackground release];
mCachedBackground = nil;
#endif
[self setNeedsDisplay:YES];
}
- (float)midBarHeight
{
return mMidBarHeight;
}
- (float)midBarOriginY
{
return mMidBarOriginY;
}
- (void)setMidBarHeight:(float)height origin:(float)origin
{
mMidBarHeight = height;
mMidBarOriginY = origin;
#if FASTER
[mCachedBackground release];
mCachedBackground = nil;
#endif
[self setNeedsDisplay:YES];
}
- (NSRect)contentRectForFrameRect:(NSRect)frameRect styleMask:(unsigned int)aStyle
{
frameRect.size.height -= 25;//[self titleBarHeight];
return frameRect;
}
- (NSRect)frameRectForContentRect:(NSRect)windowContent styleMask:(unsigned int)aStyle
{
windowContent.size.height += 25;//[self titleBarHeight];
return windowContent;
}
- (void)_showToolbarWithAnimation:(BOOL)animate
{
[super _showToolbarWithAnimation:animate];
[self setNeedsDisplay:YES];
}
- (id)backgroundColor
{
return [NSColor colorWithCalibratedWhite: 224/255.0 alpha: 1.0];
}
- (id)gradientStartColor
{
return [NSColor colorWithCalibratedWhite: 197/255.0 alpha: 1.0];
}
- (id)gradientEndColor
{
return [NSColor colorWithCalibratedWhite: 150/255.0 alpha: 1.0];
}
- (id)gradient2StartColor
{
return [NSColor colorWithCalibratedWhite: 179/255.0 alpha: 1.0];
}
- (id)gradient2EndColor
{
return [NSColor colorWithCalibratedWhite: 139/255.0 alpha: 1.0];
}
- (id)edgeColor
{
return [NSColor colorWithCalibratedWhite: 226/255.0 alpha: 1.0];
}
- (id)bottomEdgeColor
{
return [NSColor colorWithCalibratedWhite: 102/255.0 alpha: 1.0];
}
- (id)topWindowEdgeColor
{
return [NSColor colorWithCalibratedWhite: 222/255.0 alpha: 1.0];
}
- (id)bottomWindowEdgeColor
{
return [NSColor colorWithCalibratedWhite: 65/255.0 alpha: 1.0];
}
- (id)titleColor
{
if([[self window] isMainWindow])
return [NSColor colorWithCalibratedWhite:0 alpha:0.9];
return [NSColor colorWithCalibratedWhite:0 alpha:0.50];
}
+ (float)cornerRadius
{
return 5.0;
}
@end