This is MorphDocument.m in view mode; [Download] [Up]
// MorphDocument.m
//
// created by Martin Wennerberg on Sun 12-Nov-1995
//
// when who modification
#import "MorphDocument.h"
#import "AppController.h"
#import "MorphLine.h"
#import "Morpher.h"
#import "Editor.h"
#import "NSBitmapImageRep_editing.h"
#import "algebra.h"
#import "PreviewCell.h"
#import "InspectorController.h"
#import "MorphLineInspector.h"
#define NIB_NAME @"MorphDocument.nib"
@implementation MorphDocument
+ (NSSet *) readableFileTypes;
{
return [NSSet setWithObject:MORPH_DOC_EXTENTION];
}
+ (void) load
{
[[NSApp delegate] registerDocumentClass:[self class]];
}
- (void) dealloc
{
[firstImage release];
[lastImage release];
[morphLines release];
[super dealloc];
}
- initWithContentsOfFile:(NSString *)path
{
NSString *filename;
NSString *fullPath;
NSImage *image;
NSArray *lineDefs;
int i;
MorphLine *morphLine;
NSDictionary *infoDict;
NSDictionary *morphLineDict;
NSSize interCellSpacing = {2, 2};
self = [super initWithContentsOfFile:path];
morphLines = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:20];
selectedLines = [[NSMutableArray allocWithZone:[self zone]] initWithCapacity:20];
if (![NSBundle loadNibNamed:NIB_NAME owner: self])
{
[self autorelease];
return nil;
}
previewMatrix = [[NSMatrix allocWithZone:[self zone]] initWithFrame:[previewBox bounds]
mode:0
cellClass:[PreviewCell class]
numberOfRows:1
numberOfColumns:5];
[previewMatrix setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[previewMatrix setAutosizesCells:YES];
[previewMatrix setDelegate:self];
[previewMatrix setIntercellSpacing:interCellSpacing];
[(NSBox *)previewBox setContentView:previewMatrix];
[firstEditor setDelta:0.0];
[lastEditor setDelta:1.0];
[[InspectorController sharedInspectorController] registerInspector:[MorphLineInspector sharedInspector]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selectionChanged:) name:NOTIFICATION_SELECTION_CHANGED object:nil];
if (!filePath)
return self;
[[self window] setTitle:[NSLocalizedString (@"Opening file ", @"Opening window title") stringByAppendingString:filePath]];
infoDict = [[[NSDictionary allocWithZone:[self zone]] initWithContentsOfFile:[filePath stringByAppendingPathComponent:DICT_PATHCOMPONENT]] autorelease];
if (!infoDict)
{
[self autorelease];
return nil;
}
filename = [infoDict objectForKey:DICT_IMAGE0_PATH_KEY];
if ([filename characterAtIndex:0] == '/')
fullPath = filename;
else
fullPath = [filePath stringByAppendingPathComponent:filename];
image = [[[NSImage allocWithZone:[self zone]] initWithContentsOfFile:fullPath] autorelease];
[self setImage:image atDelta:0.0];
filename = [infoDict objectForKey:DICT_IMAGE1_PATH_KEY];
if ([filename characterAtIndex:0] == '/')
fullPath = filename;
else
fullPath = [filePath stringByAppendingPathComponent:filename];
image = [[[NSImage allocWithZone:[self zone]] initWithContentsOfFile:fullPath] autorelease];
[self setImage:image atDelta:1.0];
if ([infoDict objectForKey:@"frameWidth"])
[frameWidthField setStringValue:[infoDict objectForKey:@"frameWidth"]];
if ([infoDict objectForKey:@"frameHeight"])
[frameHeightField setStringValue:[infoDict objectForKey:@"frameHeight"]];
lineDefs = [infoDict objectForKey:DICT_MORPHLINES_KEY];
for (i = 0; i < [lineDefs count]; ++i)
{
morphLineDict = [lineDefs objectAtIndex:i];
morphLine = [[MorphLine allocWithZone:[self zone]] initWithValuesInDict:morphLineDict];
if (morphLine != nil)
[self addMorphLine:morphLine];
}
[[self window] setRepresentedFilename:path];
[[self window] setDocumentEdited:NO];
[self calcPreview:nil];
if (filePath)
[[self window] setTitleWithRepresentedFilename:filePath];
return self;
}
- (void) selectionChanged:(NSNotification *)sender
{
[firstEditor setNeedsDisplay:YES];
[lastEditor setNeedsDisplay:YES];
[previewMatrix setNeedsDisplay:YES];
}
- (NSArray *) morphLines
{
return morphLines;
}
- (void) addMorphLine:(MorphLine *)morphLine
{
[morphLines addObject:morphLine];
[firstEditor setNeedsDisplay:YES];
[lastEditor setNeedsDisplay:YES];
[[self window] setDocumentEdited:YES];
}
- (void) deleteMorphLine:(MorphLine *)morphLine
{
[morphLines removeObject:morphLine];
[firstEditor setNeedsDisplay:YES];
[lastEditor setNeedsDisplay:YES];
[selectedLines removeObject:morphLine];
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[[self window] setDocumentEdited:YES];
}
// Access methods
- (void) setImage:(NSImage *)image atDelta:(float) delta
{
NSSize size = [image size];
if (delta < 0.5)
{
[firstImage release];
firstImage = [image retain];
}
else
{
[lastImage release];
lastImage = [image retain];
}
[image setScalesWhenResized:YES];
[frameWidthField setIntValue:size.width];
[frameHeightField setIntValue:size.height];
[[self window] setDocumentEdited:YES];
}
- (NSImage *) imageAtDelta:(float)delta
{
if (delta < 0.5)
return firstImage;
else
return lastImage;
}
- (NSWindow *)window
{
return [firstEditor window];
}
// Actions
- (void) save:sender
{
NSFileManager *fileManager;
NSString *dirPath;
NSString *fullPath;
NSMutableDictionary *dict;
NSImageRep *rep;
NSEnumerator *repEnum;
NSImage *im0;
NSImage *im1;
NSData *im0Data = nil;
NSData *im1Data = nil;
if (filePath == nil)
return [self saveAs:sender];
// Create the info dict
dict = [NSMutableDictionary dictionaryWithCapacity:10];
// Add the morph lines to the dict
[dict setObject:[self morphLines] forKey: DICT_MORPHLINES_KEY];
// Get the NSData for the images
im0 = [self imageAtDelta:0.0];
im1 = [self imageAtDelta:1.0];
repEnum = [[im0 representations] objectEnumerator];
while ((rep = [repEnum nextObject]))
{
if ([rep respondsToSelector:@selector(EPSRepresentation)])
{
im0Data = [rep performSelector:@selector(EPSRepresentation)];
[dict setObject:@"Image_0.eps" forKey: DICT_IMAGE0_PATH_KEY];
break;
}
}
repEnum = [[im1 representations] objectEnumerator];
while ((rep = [repEnum nextObject]))
{
if ([rep respondsToSelector:@selector(EPSRepresentation)])
{
im1Data = [rep performSelector:@selector(EPSRepresentation)];
[dict setObject:@"Image_0.eps" forKey: DICT_IMAGE1_PATH_KEY];
break;
}
}
if (im0Data == nil)
{
[dict setObject:@"Image_0.tiff" forKey: DICT_IMAGE0_PATH_KEY];
im0Data = [im0 TIFFRepresentation];
}
if (im1Data == nil)
{
[dict setObject:@"Image_1.tiff" forKey: DICT_IMAGE1_PATH_KEY];
im1Data = [im1 TIFFRepresentation];
}
[dict setObject:[NSString stringWithFormat:@"%i", [frameHeightField intValue]] forKey:@"frameHeight"];
[dict setObject:[NSString stringWithFormat:@"%i", [frameWidthField intValue]] forKey:@"frameWidth"];
// (Re)create the file package
dirPath = [self filePath];
fileManager = [NSFileManager defaultManager];
[fileManager removeFileAtPath:filePath handler:nil];
[fileManager createDirectoryAtPath:filePath attributes:nil];
// Save the info plist
fullPath = [filePath stringByAppendingPathComponent:DICT_PATHCOMPONENT];
NSAssert1 ( [dict writeToFile:fullPath atomically:NO], @"Failed to write info dict %@", fullPath);
// Save the image data
fullPath = [dirPath stringByAppendingPathComponent:[dict objectForKey: DICT_IMAGE0_PATH_KEY]];
NSAssert1 ( [im0Data writeToFile:fullPath atomically:NO], @"Failed to write image %@", fullPath);
fullPath = [dirPath stringByAppendingPathComponent:[dict objectForKey: DICT_IMAGE1_PATH_KEY]];
NSAssert1 ( [im1Data writeToFile:fullPath atomically:NO], @"Failed to write image %@", fullPath);
[[self window] setDocumentEdited:NO];
}
- (void) saveAs:sender
{
NSSavePanel *sp;
NSString *path;
NSString *fname;
NSString *dname;
int result;
[[self window] setDocumentEdited:NO];
path = [self filePath];
if (path)
{
dname = [path stringByDeletingLastPathComponent];
fname = [path lastPathComponent];
}
else
{
dname = NSHomeDirectory();
fname = nil;
}
sp = [NSSavePanel savePanel];
[sp setRequiredFileType: MORPH_DOC_EXTENTION];
result = [sp runModalForDirectory:dname file:fname];
if (result == NSOKButton)
{
path = [sp filename];
[self setFilePath:[sp filename]];
[self save:self];
}
}
- (void) saveTo:sender
{
[[self window] setDocumentEdited:NO];
return;
}
- (void) saveFrames:sender
{
NSString *path;
NSString *fullPath;
NSSavePanel *sp;
NSString *dname;
NSString *fname;
NSMutableDictionary *dict;
int result;
NSFileManager *fileManager;
int frameCount;
NSSize frameSize;
path = [self filePath];
if (path)
{
dname = [path stringByDeletingLastPathComponent];
fname = [[path lastPathComponent] stringByDeletingPathExtension];
}
else
{
dname = NSHomeDirectory();
fname = nil;
}
sp = [NSSavePanel savePanel];
[sp setRequiredFileType: XMOVIE_EXTENTION];
[sp setAccessoryView:frameSettingsView];
result = [sp runModalForDirectory:dname file:fname];
if (result != NSOKButton)
return;
path = [sp filename];
frameCount = [frameCountField intValue];
frameSize.width = [frameWidthField floatValue];
frameSize.height = [frameHeightField floatValue];
// (Re)create the file package
fileManager = [NSFileManager defaultManager];
[fileManager removeFileAtPath:path handler:nil];
[fileManager createDirectoryAtPath:path attributes:nil];
// Save the info plist
fullPath = [path stringByAppendingPathComponent:DICT_PATHCOMPONENT];
dict = [NSMutableDictionary dictionaryWithCapacity:10];
// Insert code to fill the dictionary with usefull information
NSAssert1 ( [dict writeToFile:fullPath atomically:NO], @"Failed to write info dict %@", fullPath);
[[self window] display];
[self calcFramesAndSaveToPath:path count:frameCount size:frameSize];
[[[NSApplication sharedApplication] delegate] application:[NSApplication sharedApplication] openFile:path];
}
- (void) selectAll:sender
{
[selectedLines removeAllObjects];
[selectedLines addObjectsFromArray:[self morphLines]];
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
- (void) selectNone:sender
{
[selectedLines removeAllObjects];
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
- (void) addToCurrentSelection:(id)obj
{
if (obj != nil && ![selectedLines containsObject:obj])
[selectedLines addObject:obj];
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
- (void) removeFromCurrentSelection:(id)obj
{
if (obj != nil && [selectedLines containsObject:obj])
{
[selectedLines removeObject:obj];
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
}
- (NSArray *) currentSelection
{
return selectedLines;
}
- (void) calcPreview:sender
{
NSBitmapImageRep *firstBitmap;
NSBitmapImageRep *lastBitmap;
NSBitmapImageRep *bitmap;
Morpher *morpher;
float delta;
NSArray *cells;
PreviewCell *cell;
int i;
NSSize size;
NSSize winSize;
firstBitmap = [[[self imageAtDelta:0] representations] lastObject];
lastBitmap = [[[self imageAtDelta:1] representations] lastObject];
cells = [previewMatrix cells];
size = [previewMatrix cellSize];
[progressIndicator setDoubleValue:0];
winSize = size;
winSize.height += 20;
[progressIndicator setDoubleValue:0];
[[progressIndicator window] setContentSize:winSize];
[[progressIndicator window] makeKeyAndOrderFront:nil];
[[progressIndicator window] display];
morpher = [[Morpher allocWithZone:[self zone]] initWithFirstBitmap:firstBitmap lastBitmap:lastBitmap morphLines:morphLines];
for (i = 0; i < [cells count]; ++i)
{
cell = [cells objectAtIndex:i];
delta = i / (float) ([cells count] - 1.0);
[cell setShouldDrawLines:YES];
[progressIndicator setDoubleValue:delta];
[progressIndicator display];
bitmap = [[NSBitmapImageRep allocWithZone:[self zone]] initWithBitmapDataPlanes:NULL
pixelsWide:size.width
pixelsHigh:size.height
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:(size.width + 1) * 3
bitsPerPixel:24];
[morpher calcMorphBitmap:bitmap atDelta:delta];
[cell setBitmap:bitmap];
[cell setDelta:delta];
[cell setDelegate:self];
[previewMatrix display];
[progressView lockFocus];
[bitmap draw];
[progressView unlockFocus];
[[progressView window] flushWindow];
[[NSDPSContext currentContext] flush];
[bitmap release];
}
[morpher release];
[[progressIndicator window] orderOut:nil];
return;
}
- (void) calcFramesAndSaveToPath:(NSString *)dirPath count:(unsigned int)frameCount size:(NSSize)frameSize
{
NSBitmapImageRep *firstBitmap;
NSBitmapImageRep *lastBitmap;
NSBitmapImageRep *bitmap;
NSData *data;
Morpher *morpher;
float delta;
NSString *path;
int frameNum = 0;
NSSize winSize;
winSize = frameSize;
winSize.height += 20;
[progressIndicator setDoubleValue:0];
[[progressIndicator window] setContentSize:winSize];
[[progressIndicator window] makeKeyAndOrderFront:nil];
[[progressIndicator window] display];
bitmap = [[NSBitmapImageRep allocWithZone:[self zone]] initWithBitmapDataPlanes:NULL pixelsWide:frameSize.width pixelsHigh:frameSize.height bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(frameSize.width + 1) * 3 bitsPerPixel:24];
firstBitmap = [[[self imageAtDelta:0] representations] lastObject];
lastBitmap = [[[self imageAtDelta:1] representations] lastObject];
morpher = [[Morpher allocWithZone:[self zone]] initWithFirstBitmap:firstBitmap lastBitmap:lastBitmap morphLines:morphLines];
for (frameNum = 0; frameNum < frameCount; ++frameNum)
{
delta = frameNum / (float) (frameCount - 1.0);
[progressIndicator setDoubleValue:delta];
[progressIndicator display];
[morpher calcMorphBitmap:bitmap atDelta:delta];
[progressView lockFocus];
[bitmap draw];
[progressView unlockFocus];
[[progressView window] flushWindow];
[[NSDPSContext currentContext] flush];
data = [bitmap TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:20];
path = [dirPath stringByAppendingPathComponent:[NSString stringWithFormat:@"Image_%d.tiff", frameNum]];
[data writeToFile:path atomically:NO];
}
[morpher release];
[[progressIndicator window] orderOut:nil];
}
- (void)windowDidBecomeMain:(NSNotification *)notification
{
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:NOTIFICATION_SELECTION_CHANGED object:self]
postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.