Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MyQuickDrawView.m
////////// |
// |
// File: MyQuickDrawView.m |
// |
// Contains: Implementation file for the MyQuickDrawView class. |
// |
// Overview: |
// |
// Subclass of NSQuickDrawView. This class contains code for drawing into a NSQuickDrawView. More specifically, |
// we draw video frames to the NSQuickDrawView's QuickDraw port using QuickTime/QuickDraw calls. We |
// also draw on top of these video frames (compositing) using standard Cocoa, Core Graphics and QuickDraw routines. |
// |
// Specifics: |
// |
// This Cocoa sample demonstrates how to step frame-by-frame through a QuickTime movie using |
// the GetNextInterestingTime function, drawing each frame of the movie into an offscreen GWorld using |
// a decompression sequence. The offscreen GWorld contents are then drawn into a Cocoa NSQuickDrawView |
// (using the NSQuickDrawView's QuickDraw port) for display. Other drawing is also done into the NSQuickDrawView using |
// Cocoa, Core Graphics and QuickDraw routines. |
// |
// Lastly, a compile flag is provided which allows drawing into the NSQuickDrawView's QuickDraw |
// port directly, bypassing the offscreen GWorld (Note - if you select this option to have QuickTime |
// draw _directly_ to the NSQuickDrawView's QuickDraw port (via SetMovieGWorld), QuickTime essentially |
// creates a subwindow which appears inside the main window to perform it's drawing. It's contents can |
// completely cover the contents of the window buffer where all Cocoa drawing takes place so even if |
// you try drawing on top (compositing) of it you will only see the movie drawing). |
// |
// Written by: Apple Developer Technical Support |
// |
// Copyright: © 2002 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <1> 11/18/02 srk first file |
// <2> 12/9/02 srk added compile flag to optionally draw directly to NSQuickDrawView QT port, |
// other misc. improvements/re-organization of the code |
// |
////////// |
/* |
IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in |
consideration of your agreement to the following terms, and your use, installation, |
modification or redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject to these |
terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in |
this original Apple software (the "Apple Software"), to use, reproduce, modify and |
redistribute the Apple Software, with or without modifications, in source and/or binary |
forms; provided that if you redistribute the Apple Software in its entirety and without |
modifications, you must retain this notice and the following text and disclaimers in all |
such redistributions of the Apple Software. Neither the name, trademarks, service marks |
or logos of Apple Computer, Inc. may be used to endorse or promote products derived from |
the Apple Software without specific prior written permission from Apple. Except as expressly |
stated in this notice, no other rights or licenses, express or implied, are granted by Apple |
herein, including but not limited to any patent rights that may be infringed by your |
derivative works or by other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, |
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS |
USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, |
REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND |
WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR |
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
#import "MyQuickDrawView.h" |
#define DO_OFFSCREEN_DRAWING 1 /* 1 = draw to offscreen gworld first, then blit to window |
0 = draw to window QD port only */ |
#if DO_OFFSCREEN_DRAWING |
enum { kHeightOfWindowButtonArea = 50 }; |
#else |
enum { kHeightOfWindowButtonArea = 70 }; |
#endif |
@implementation MyQuickDrawView |
////////// |
// |
// awakeFromNib |
// |
// Called after all our objects are unarchived and |
// connected but just before the interface is made visible |
// to the user. We will do custom initialization of our |
// objects here. |
// |
////////// |
- (void)awakeFromNib |
{ |
decompressSeqID = 0; // unique identifier for our draw sequence |
firstDrawRect = TRUE; // true for first call to the view's drawRect method |
movie = NULL; // the QuickTime movie we are using |
srcGWorld = NULL; // GWorld we are drawing into |
movieTime = 0; // set current time value to begining of the Movie |
movieFrameCount = 0; // movie frame count |
movieFrameNumber = 1; // current movie frame number |
imageSize = 0; // how big is image |
EraseRect(&movieBox); |
/* prompt the user for a movie to display */ |
movie = [self createQTMovieFromMovieFilePath:[myObject movieFilePath]]; |
if (movie != NULL) |
{ |
/* we must initialize the movie toolbox before calling |
any of it's functions */ |
EnterMovies(); |
movieFrameCount = [self countMovieFrames]; |
// normalize the movie rect |
[self normalizeMovieRect]; |
#if DO_OFFSCREEN_DRAWING |
/* make offscreen gworld to draw movie frames into */ |
srcGWorld = [self makeGWorldForMovie]; |
if (srcGWorld != NULL) |
{ |
/* set the graphics world for displaying the movie */ |
SetMovieGWorld(movie, srcGWorld, GetGWorldDevice(srcGWorld)); |
} |
#endif |
displayString = [self makeDisplayString]; |
[self setViewWindowContentSizeAndPosition]; |
[self setViewFrameRectToMovieRect]; |
[self setMovieFrameButtonSizeAndPosition]; |
} |
} |
////////// |
// |
// setMovieFrameButtonSizeAndPosition |
// |
// Adjust our button to fit into the window appropriately |
// |
////////// |
-(void)setMovieFrameButtonSizeAndPosition |
{ |
NSRect newResizedRect, buttonAreaRect; |
NSAssert(movieFrameButton != nil, @"nil movie frame button"); |
[movieFrameButton setFrameOrigin:NSMakePoint(0, 0)]; |
buttonAreaRect = NSMakeRect(0, 0, |
[self normalizedMovieRectWidth], |
[self normalizedMovieRectHeight] + kHeightOfWindowButtonArea); |
buttonAreaRect.size.height = kHeightOfWindowButtonArea; |
newResizedRect = [self centerRectInEnclosingRect:[movieFrameButton frame] enclosingRect:buttonAreaRect]; |
[movieFrameButton setFrame:newResizedRect]; |
} |
////////// |
// |
// centerRectInEnclosingRect |
// |
// Utility routine which will center the specified rect in |
// another rect |
// |
////////// |
-(NSRect)centerRectInEnclosingRect:(NSRect) currentRect enclosingRect:(NSRect)enclosingRect |
{ |
float currentWidth = NSWidth(currentRect); |
float currentHeight = NSHeight(currentRect); |
float newX,newY; |
/* this is the new x,y */ |
newX = (NSWidth(enclosingRect) - currentWidth)/2 + enclosingRect.origin.x; |
newY = (NSHeight(enclosingRect) - currentHeight)/2 + enclosingRect.origin.y; |
return (NSMakeRect(newX, newY, currentWidth, currentHeight)); |
} |
////////// |
// |
// setViewFrameRectToMovieRect |
// |
// set the view's frame rect to the movie rect |
// |
////////// |
-(void)setViewFrameRectToMovieRect |
{ |
NSRect newFrameRect = NSMakeRect(0, 0, |
[self normalizedMovieRectWidth], |
[self normalizedMovieRectHeight] + kHeightOfWindowButtonArea); |
[self setFrame:newFrameRect]; |
} |
////////// |
// |
// setViewWindowContentSizeAndPosition |
// |
// set the view's window content size appropriately |
// |
////////// |
-(void)setViewWindowContentSizeAndPosition |
{ |
NSWindow *window = [self window]; |
if (window != nil) |
{ |
[window setContentSize: NSMakeSize([self normalizedMovieRectWidth], |
[self normalizedMovieRectHeight] + kHeightOfWindowButtonArea)]; |
[window center]; |
} |
NSAssert(window != nil, @"nil window"); |
} |
////////// |
// |
// createQTMovieFromMovieFilePath |
// |
// Given a path to a movie file, create a |
// QuickTime movie |
// |
////////// |
-(Movie)createQTMovieFromMovieFilePath:(NSString *)movieFilePath |
{ |
NSURL *movieFileURL = nil; |
NSMovie *theNSMovie = nil; |
Movie qtMovie = NULL; |
NSAssert(movieFilePath, @"nil movie file path"); |
movieFileURL = [NSURL fileURLWithPath:movieFilePath]; |
if (movieFileURL != nil) |
{ |
theNSMovie = [[NSMovie alloc] initWithURL:movieFileURL byReference:NO]; |
if (theNSMovie != nil) |
{ |
qtMovie = [theNSMovie QTMovie]; |
if (qtMovie != NULL) |
{ |
SetMovieActive(qtMovie,true); |
} |
} |
} |
NSAssert(movieFileURL != NULL, @"nil movieFileURL"); |
NSAssert(theNSMovie != NULL, @"nil theNSMovie"); |
NSAssert(qtMovie != NULL, @"null qtmovie"); |
return (qtMovie); |
} |
////////// |
// |
// normalizeMovieRect |
// |
// Set the movie rect to be 0,0 based |
// |
////////// |
-(void)normalizeMovieRect |
{ |
NSAssert(movie != NULL, @"NULL movie in normalizeMovieRect"); |
GetMovieBox(movie, &movieBox); |
OffsetRect(&movieBox, -movieBox.left, -movieBox.top); |
SetMovieBox(movie, &movieBox); |
} |
////////// |
// |
// normalizedMovieRectWidth |
// |
// Return the normalized movie rect width |
// |
////////// |
-(float)normalizedMovieRectWidth |
{ |
return((float)(movieBox.right - movieBox.left)); |
} |
////////// |
// |
// normalizedMovieRectHeight |
// |
// Return the normalized movie rect height |
// |
////////// |
-(float)normalizedMovieRectHeight |
{ |
return((float)(movieBox.bottom - movieBox.top)); |
} |
////////// |
// |
// makeGWorldForMovie |
// |
// Get the bounding rectangle of the Movie the create a 32-bit GWorld |
// with those dimensions. |
// This GWorld will be used for rendering Movie frames into. |
// |
////////// |
-(GWorldPtr) makeGWorldForMovie |
{ |
Rect srcRect; |
GWorldPtr newGWorld = NULL; |
CGrafPtr savedPort; |
GDHandle savedDevice; |
OSErr err = noErr; |
GetGWorld(&savedPort, &savedDevice); |
GetMovieBox(movie,&srcRect); |
err = NewGWorld(&newGWorld, |
k32ARGBPixelFormat, |
&srcRect, |
NULL, |
NULL, |
0); |
if (err == noErr) |
{ |
if (LockPixels(GetGWorldPixMap(newGWorld))) |
{ |
Rect portRect; |
RGBColor theBlackColor = { 0, 0, 0 }; |
RGBColor theWhiteColor = { 65535, 65535, 65535 }; |
SetGWorld(newGWorld, NULL); |
GetPortBounds(newGWorld, &portRect); |
RGBBackColor(&theBlackColor); |
RGBForeColor(&theWhiteColor); |
EraseRect(&portRect); |
UnlockPixels(GetGWorldPixMap(newGWorld)); |
} |
} |
SetGWorld(savedPort, savedDevice); |
NSAssert(newGWorld != NULL, @"NULL gworld"); |
return newGWorld; |
} |
////////// |
// |
// countMovieFrames |
// |
// Count the number of video "frames" in the Movie by stepping through |
// all of the video "interesting times", or in other words, the places where the |
// movie displays a new video sample. The time between these interesting times |
// is not necessarily constant. |
// |
////////// |
-(UInt32)countMovieFrames |
{ |
OSType whichMediaType = VIDEO_TYPE; |
short flags = nextTimeMediaSample + nextTimeEdgeOK; |
TimeValue duration; |
TimeValue theTime = 0; |
UInt32 frameCnt = 0; |
NSAssert(movie != NULL, @"NULL movie in countMovieFrames"); |
while (theTime >= 0) |
{ |
frameCnt++; |
GetMovieNextInterestingTime(movie, |
flags, |
1, |
&whichMediaType, |
theTime, |
0, |
&theTime, |
&duration); |
NSAssert(GetMoviesError() == noErr, @"GetMovieNextInterestingTime error"); |
// after the first interesting time, don't include the time we |
// are currently at. |
flags = nextTimeMediaSample; |
} // while |
return frameCnt; |
} |
////////// |
// |
// nextFrame |
// |
// Get the next frame of the movie, set the movie time for that frame |
// then task the movie which will draw the frame to the GWorld |
// finally draw the frame number on top of the image and inval the window rect |
// |
////////// |
-(void)nextFrame |
{ |
NSAssert(movie != NULL, @"null movie"); |
if (movieFrameNumber >= movieFrameCount) |
{ |
// reset the movie time back to the beginning |
// then do it all over again |
movieTime = 0; |
movieFrameNumber = 1; |
GoToBeginningOfMovie(movie); |
} |
else |
{ |
short flags; |
OSType whichMediaType; |
TimeValue duration; |
// get the next frame of the source movie |
flags = nextTimeMediaSample; |
whichMediaType = VIDEO_TYPE; |
// if this is the first frame, include the frame we are currently on |
if (movieFrameNumber == 1) |
{ |
flags |= nextTimeEdgeOK; |
} |
// skip to the next interesting time and get the duration for that frame |
GetMovieNextInterestingTime(movie, |
flags, |
1, |
&whichMediaType, |
movieTime, |
0, |
&movieTime, |
&duration); |
// set the time for the frame and give time to the movie toolbox |
SetMovieTimeValue(movie,movieTime); |
// You now have pixels you can play with in the GWorld! |
// This sample simply blits the contents of the GWorld back to |
// a window with the frame number drawn on top of the image |
movieFrameNumber++; |
} |
} |
////////// |
// |
// initDecompressSeq |
// |
// setup our decompression sequence for drawing |
// into the gworld |
// |
////////// |
-(ComponentResult)initDecompressSeq:(CGrafPtr)dstPort |
{ |
ComponentResult err = noErr; |
Rect bounds; |
ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); |
PixMapHandle hPixMap = NULL; |
NSAssert(imageDesc != NULL, @"null ImageDescriptionHandle"); |
NSAssert(srcGWorld != NULL, @"srcGWorld NULL"); |
/* Set up getting grabbed data into the Window */ |
hPixMap = GetGWorldPixMap(srcGWorld); |
NSAssert(hPixMap != NULL, @"null PixMapHandle"); |
NSAssert(LockPixels(hPixMap), @"LockPixels failed"); |
GetPixBounds(hPixMap,&bounds); |
decompressSeqID = 0; |
// returns an image description for the GWorlds PixMap |
// on entry the imageDesc is NULL, on return it is correctly filled out |
// you are responsible for disposing it |
err = MakeImageDescriptionForPixMap(hPixMap, &imageDesc); |
if (err == noErr) |
{ |
imageSize = (GetPixRowBytes(hPixMap) * (*imageDesc)->height); |
// begin the process of decompressing a sequence of frames - see above notes on this call. |
// destination is specified as the QuickDraw port for our NSView |
err = DecompressSequenceBeginS( &decompressSeqID, |
imageDesc, |
GetPixBaseAddr(hPixMap), |
imageSize, |
dstPort, |
NULL, |
&bounds, |
NULL, |
ditherCopy, |
NULL, |
0, |
codecHighQuality, |
anyCodec); |
} |
NSAssert(err == noErr, @"DecompressSequenceBeginS error"); |
UnlockPixels(hPixMap); |
if (imageDesc) |
{ |
DisposeHandle((Handle)imageDesc); |
} |
return (err); |
} |
////////// |
// |
// decompress |
// |
// Use our decompression sequence to decompress into the gworld |
// |
////////// |
-(OSErr)decompress |
{ |
ComponentResult err = noErr; |
CodecFlags ignore; |
err = DecompressSequenceFrameS( decompressSeqID, |
GetPixBaseAddr(GetGWorldPixMap(srcGWorld)), |
imageSize, |
0, |
&ignore, |
NULL); |
NSAssert(err == noErr, @"DecompressSequenceFrameS error"); |
return err; |
} |
////////// |
// |
// endDecompress |
// |
// terminate our decompress |
// |
////////// |
-(OSErr)endDecompress |
{ |
NSAssert(decompressSeqID != NULL, @"Null draw seq"); |
return (CDSequenceEnd(decompressSeqID)); |
} |
////////// |
// |
// makeDisplayString |
// |
// create a string for display |
// |
////////// |
-(NSMutableAttributedString *)makeDisplayString |
{ |
NSFont *font = nil; |
NSMutableDictionary *attrs = nil; |
font = [NSFont fontWithName:@"Helvetica" size:36.0]; |
NSAssert(font != nil, @"fontWithName failure"); |
attrs = [NSMutableDictionary dictionary]; |
NSAssert(attrs != nil, @"NSMutableDictionary failure"); |
[attrs setObject:font forKey:NSFontAttributeName]; |
[attrs setObject:[NSColor blueColor]forKey:NSForegroundColorAttributeName]; |
return ([[NSMutableAttributedString alloc] |
initWithString:@"QuickTime!" |
attributes:attrs]); |
} |
////////// |
// |
// freeAllocatedObjects |
// |
////////// |
-(void)freeAllocatedObjects |
{ |
#if DO_OFFSCREEN_DRAWING |
[self endDecompress]; |
#endif |
[displayString release]; |
} |
////////// |
// |
// drawRect |
// |
// Overridden by subclasses of NSView to draw the receiver's |
// image within aRect. It's here we decompress our frames |
// to the window for display |
// |
////////// |
-(void)drawRect:(NSRect)rect |
{ |
/* do initialization the first time our drawRect |
is called */ |
if (firstDrawRect) |
{ |
#if DO_OFFSCREEN_DRAWING |
/* Draw to offscreen GWorld, then later blit to |
the window's QuickDraw port */ |
[self initDecompressSeq:[self qdPort]]; |
#else |
/* Draw _directly_ to the NSQuickDrawView's QuickDraw port - note |
that if you are doing this, QuickTime creates a subwindow |
which appears inside the main window to perform it's drawing. |
It's contents can completely cover the contents of the window |
buffer where all Cocoa drawing takes place so even if you try |
drawing on top of it you will only see the movie drawing */ |
SetMovieGWorld(movie, [self qdPort], nil); |
#endif |
firstDrawRect = FALSE; |
} |
/* This causes QuickTime to draw the movie frame into the |
movie's designated gworld. */ |
MoviesTask(movie,0); |
#if DO_OFFSCREEN_DRAWING |
/* use a decompression sequence to decompress frame from |
our offscreen gworld to the screen */ |
[self decompress]; |
/* do some drawing with Core Graphics calls */ |
[self drawCoreGraphicsFivePointStar:[self qdPort]]; |
/* do some Cocoa drawing of miscellaneous shapes over the frame */ |
[self drawCocoaMiscShapes]; |
/* draw some shapes using QuickDraw calls */ |
[self drawQuickDrawShapes]; |
#endif |
// draw frame counter using Cocoa calls |
[self drawFrameCounter]; |
} |
////////// |
// |
// drawCoreGraphicsFivePointStar |
// |
// use Core Graphics routines to draw a shape (a five point star) |
// |
////////// |
-(void)drawCoreGraphicsFivePointStar:(CGrafPtr)port |
{ |
CGContextRef context = NULL; |
const float kMediaHeight = 50.0; |
const float kMediaWidth = 50.0; |
const float yOffset = 95.0, xOffset = 113.0; |
CGRect mediaBox; |
// This color approximates a green |
const float kStarRGBColor[3] = {0.1, 0.6, 0.1}; |
// Define the locations (relative to the origin of the |
// graphics context) of all five points of the star |
const float kSize = (kMediaHeight * 0.9); |
const float kHalfSize = (kSize * 0.5); |
const float kTenthSize = (kSize * 0.1); |
CGPoint location[6] = |
{ |
{kTenthSize + xOffset, 0 + yOffset}, // lower left |
{kHalfSize + xOffset, (kSize - kTenthSize) + yOffset}, // top |
{kSize - kTenthSize + xOffset, 0 + yOffset}, // lower right |
{0 + xOffset, kHalfSize + yOffset}, // left |
{kSize + xOffset, kHalfSize + yOffset}, // right |
{kTenthSize + xOffset, 0 + yOffset} // return to lower left |
}; |
mediaBox = CGRectMake( 0, 0, kMediaWidth, kMediaHeight ); |
// Create the context |
QDBeginCGContext( port, &context ); |
if (context) |
{ |
// We must begin a new page before drawing to a PDF context |
CGContextBeginPage( context, &mediaBox ); |
// |
// Just for fun, skew the star slightly by rotating the CTM |
// a little bit. |
// |
// Since the rotation will otherwise cause the tip of one edge of the |
// star to be clipped, we translate the CTM ten units horizontally to |
// make sure the entire star fits on the page. |
// |
CGContextTranslateCTM( context, 10.0, 0.0 ); |
CGContextRotateCTM( context, 0.1 ); |
// Set the color |
CGContextSetRGBFillColor( context, kStarRGBColor[0], |
kStarRGBColor[1], |
kStarRGBColor[2], |
1.0 ); |
// Add the star to the path |
CGContextAddLines( context, &location[0], 6 ); |
CGContextEOFillPath( context ); |
// FillPath and EOFillPath always clear the path, |
// so we need to add the lines again to draw the star outline |
CGContextAddLines( context, &location[0], 6 ); |
CGContextStrokePath( context ); |
// WeÕve finished rendering the page |
CGContextEndPage( context ); |
// We're done drawing |
QDEndCGContext( port, &context ); |
} |
} |
////////// |
// |
// drawQuickDrawShapes |
// |
// draws some QuickDraw shapes |
// |
////////// |
-(void)drawQuickDrawShapes |
{ |
Rect aRect = {100,150,130,180}; |
Pattern aPattern; |
GetQDGlobalsLightGray(&aPattern); |
PenPat(&aPattern); |
PaintOval(&aRect); |
} |
////////// |
// |
// drawFrameCounter |
// |
// draws the current frame count using Cocoa calls |
// |
////////// |
-(void)drawFrameCounter |
{ |
float yPos; |
NSSize stringSize; |
NSMutableDictionary *descriptionAttributes; |
NSString *frameNumDisplayString = [[NSString alloc] initWithFormat:@"Frame #%4.0f", (float)movieFrameNumber, nil]; |
NSAssert(frameNumDisplayString != nil, @"failure to create string"); |
descriptionAttributes = [[NSMutableDictionary alloc] init]; |
NSAssert(descriptionAttributes != nil, @"failure to create NSMutableDictionary"); |
[descriptionAttributes setObject:[NSFont fontWithName:@"Arial" size:11] forKey:NSFontAttributeName]; |
// [descriptionAttributes setObject:[NSColor whiteColor] forKey:NSBackgroundColorAttributeName]; // background color |
stringSize = [frameNumDisplayString sizeWithAttributes:descriptionAttributes]; |
#if DO_OFFSCREEN_DRAWING |
/* draw on top of the movie */ |
yPos = [self normalizedMovieRectHeight] - stringSize.height; |
#else |
/* don't draw on top of the movie because it will get |
wiped out by the movie drawing - instead draw below it */ |
yPos = [self normalizedMovieRectHeight]; |
#endif |
/* draw the frame count string at the desired location */ |
[frameNumDisplayString drawAtPoint:NSMakePoint(0,yPos) withAttributes:descriptionAttributes]; |
/* clean up */ |
[descriptionAttributes release]; |
[frameNumDisplayString release]; |
} |
////////// |
// |
// drawCocoaMiscShapes |
// |
// Use Cocoa calls to draw some text and other miscellaneous shapes |
// |
////////// |
-(void)drawCocoaMiscShapes |
{ |
NSColor *aColor; |
aColor = [NSColor colorWithDeviceRed:0.5 |
green:0.5 |
blue:0.1 |
alpha:0.5 ]; |
NSAssert(aColor != nil, @"colorWithDeviceRed failure"); |
[aColor set]; |
[NSBezierPath fillRect:NSMakeRect(12,75,130,57)]; |
[self drawChristmasStar]; |
NSAssert(displayString != nil, @"displayString nil"); |
[displayString drawAtPoint:NSMakePoint(16,30)]; |
} |
////////// |
// |
// drawStar |
// |
// draw a star shape using Cocoa calls |
// |
////////// |
-(void)drawChristmasStar |
{ |
NSBezierPath *path = [NSBezierPath bezierPath]; |
NSPoint center = NSMakePoint(50,120); |
NSAssert(path != nil, @"bezierPath method failed"); |
[[NSColor magentaColor] set]; |
[path setLineWidth:2.0]; |
[path moveToPoint:NSMakePoint(50,70)]; |
[path curveToPoint:NSMakePoint(100,120) |
controlPoint1:center controlPoint2:center]; |
[path curveToPoint:NSMakePoint(50,170) |
controlPoint1:center controlPoint2:center]; |
[path curveToPoint:NSMakePoint(0,120) |
controlPoint1:center controlPoint2:center]; |
[path curveToPoint:NSMakePoint(50,70) |
controlPoint1:center controlPoint2:center]; |
[path stroke]; |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14