1// PXCanvas.m 2// Pixen 3// 4// Created by Joe Osborn on Sat Sep 13 2003. 5// Copyright (c) 2003 Open Sword Group. All rights reserved. 6// 7 8#import "PXCanvas.h" 9#import "PXLayer.h" 10#import "PXSelectionLayer.h" 11#ifdef __COCOA__ 12#import "PXBitmapExporter.h" 13#import "PXPSDHandler.h" 14#endif 15#import "PXPalette.h" 16 17#import "PXPoint.h" 18 19NSString * PXCanvasSizeChangedNotificationName = @"PXCanvasSizeChangedNotification"; 20NSString * PXCanvasChangedNotificationName = @"PXCanvasChangedNotification"; 21NSString * PXCanvasSelectionChangedNotificationName = @"PXCanvasSelectionChangedNotification"; 22NSString * PXCanvasLayersChangedNotificationName = @"PXCanvasLayersChangedNotification"; 23 24@implementation PXCanvas 25 26+ withContentsOfFile:aFile 27{ 28 return [[[self alloc] initWithContentsOfFile:aFile] autorelease]; 29} 30 31- initWithContentsOfFile:aFile 32{ 33 if([[aFile pathExtension] isEqualToString:@"pxi"]) 34 { 35 [self release]; 36 return self = [[NSKeyedUnarchiver unarchiveObjectWithFile:aFile] retain]; 37 } 38 else 39 { 40 return [self initWithImage:[[[NSImage alloc] initWithContentsOfFile:aFile] autorelease]]; 41 } 42 [self release]; 43 return self = nil; 44} 45 46- init 47{ 48 [super init]; 49 layers = [[NSMutableArray alloc] initWithCapacity:23]; 50 palette = [[PXPalette alloc] initWithName:NSLocalizedString(@"GENERATED_PALETTE", @"Generated Palette")]; 51 [self setLastDrawnPoint:NSMakePoint(-1, -1)]; 52 [self setDefaultGridParameters]; 53 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(canvasShouldRedraw:) name:@"PXCanvasShouldRedrawNotificationName" object:nil]; 54 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorAdded:) name:@"PXImageColorAddedNotification" object:nil]; 55 return self; 56} 57 58- (void)canvasShouldRedraw:aNotification 59{ 60 [self changedInRect:NSMakeRect(0,0,[self size].width,[self size].height)]; 61} 62 63- (void)dealloc 64{ 65 [layers release]; 66 [palette release]; 67 [mainBackgroundName release]; 68 [alternateBackgroundName release]; 69 [[NSNotificationCenter defaultCenter] removeObserver:self]; 70 [super dealloc]; 71} 72 73- (BOOL)containsPoint:(NSPoint)aPoint 74{ 75 return ([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? YES : NSPointInRect(aPoint, NSMakeRect(0, 0, [self size].width, [self size].height))); 76} 77 78- (NSPoint)correct:(NSPoint)aPoint 79{ 80 NSPoint corrected = aPoint; 81 while(corrected.x < 0) 82 { 83 corrected.x += [self size].width; 84 } 85 while(corrected.x >= [self size].width) 86 { 87 corrected.x -= [self size].width; 88 } 89 while(corrected.y < 0) 90 { 91 corrected.y += [self size].height; 92 } 93 while(corrected.y >= [self size].height) 94 { 95 corrected.y -= [self size].height; 96 } 97 return corrected; 98} 99 100- colorAtPoint:(NSPoint)aPoint 101{ 102 if(![self containsPoint:aPoint]) { return nil; } 103 return [activeLayer colorAtPoint:aPoint]; 104} 105 106- (void)changedInRect:(NSRect)rect 107{ 108 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasChangedNotificationName object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithRect:rect], @"changedRect", activeLayer, @"activeLayer", nil]]; 109 if ([self hasSelection]) 110 { 111 if ([[[layers lastObject] workingPoints] count] > 0) 112 { 113 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasChangedNotificationName object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithRect:rect], @"changedRect", lastActiveLayer, @"activeLayer", nil]]; 114 } 115 } 116} 117 118- (void)setColor:aColor atPoint:(NSPoint)aPoint 119{ 120 if(![self containsPoint:aPoint]) { return; } 121 [activeLayer setColor:aColor atPoint:aPoint]; 122} 123 124- (void)setColor:aColor atPoints:(NSArray *)points 125{ 126 [activeLayer setColor:aColor atPoints:points]; 127} 128 129- undoManager 130{ 131 return [[[NSDocumentController sharedDocumentController] currentDocument] undoManager]; 132} 133 134- (void)setLayers:newLayers fromLayers:oldLayers 135{ 136 [[[self undoManager] prepareWithInvocationTarget:self] setLayers:oldLayers fromLayers:newLayers]; 137 [self setLayers:newLayers]; 138} 139 140- (void)promoteSelection 141{ 142 id newLayer = [[PXLayer alloc] initWithName:@"New Layer" size:[self size]], lastLayer = [layers lastObject]; 143 if (![self hasSelection]) { return; } 144 [[self undoManager] beginUndoGrouping]; 145 [[self undoManager] setActionName:@"Promote Selection"]; 146 [self setLayers:[layers deepMutableCopy] fromLayers:layers]; 147 // we have to recreate the layer so it won't be a PXSelectionLayer anymore 148 // make a new layer and make it second to last - under the selection 149 [newLayer compositeUnder:lastLayer flattenOpacity:YES]; 150 [layers removeLastObject]; 151 [self addLayer:newLayer]; 152 [self activateLayer:newLayer]; 153 lastActiveLayer = nil; 154 [self layersChanged]; 155 [[self undoManager] endUndoGrouping]; 156} 157 158- activeLayer 159{ 160 return activeLayer; 161} 162 163- (void)activateLayer:aLayer 164{ 165 if((activeLayer == aLayer) || (aLayer == nil)) { return; } 166 lastActiveLayer = activeLayer; 167 activeLayer = aLayer; 168} 169 170- lastActiveLayer 171{ 172 return lastActiveLayer; 173} 174 175- (void)restoreActivateLayer:aLayer lastActiveLayer:lastLayer 176{ 177 activeLayer = aLayer; 178 lastActiveLayer = lastLayer; 179} 180 181- (void)layersChanged 182{ 183 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasLayersChangedNotificationName object:self]; 184 [self changedInRect:NSMakeRect(0, 0, [self size].width, [self size].height)]; 185} 186 187- layers 188{ 189 return layers; 190} 191 192- (int)indexOfLayer:aLayer 193{ 194 return [layers indexOfObject:aLayer]; 195} 196 197- (void)setLayers:newLayers 198{ 199 int oldActiveIndex = [layers indexOfObject:activeLayer]; 200 if([self hasSelection]) { oldActiveIndex = [layers indexOfObject:lastActiveLayer]; } 201 if([newLayers count] <= oldActiveIndex) { oldActiveIndex = 0; } 202 [self activateLayer:[newLayers objectAtIndex:oldActiveIndex]]; 203 if([[newLayers lastObject] isKindOfClass:[PXSelectionLayer class]]) { [self activateLayer:[newLayers lastObject]]; } 204 [newLayers retain]; 205 [layers release]; 206 layers = newLayers; 207 [self layersChanged]; 208} 209 210- (void)addLayer:aLayer 211{ 212 [self insertLayer:aLayer atIndex:[layers count]]; 213} 214 215- (void)insertLayer:aLayer atIndex:(int)index 216{ 217 [self deselect]; 218 [layers insertObject:aLayer atIndex:index]; 219 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasLayersChangedNotificationName object:self]; 220} 221 222- (void)removeLayer:aLayer 223{ 224 [self deselect]; 225 if([layers count] == 1) { return; } 226 [layers removeObject:aLayer]; 227 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasLayersChangedNotificationName object:self]; 228 [self activateLayer:[layers objectAtIndex:0]]; 229 [self changedInRect:NSMakeRect(0,0,[self size].width,[self size].height)]; 230} 231 232- (void)removeLayerAtIndex:(int)index 233{ 234 if(index >= [layers count]) { return; } 235 [self removeLayer:[layers objectAtIndex:index]]; 236} 237 238- (void)moveLayer:aLayer toIndex:(int)targetIndex 239{/* 240 int i, j;*/ 241 id newLayers = [layers mutableCopy]; 242 int sourceIndex = [layers indexOfObject:aLayer]; 243 244 [newLayers removeObjectAtIndex:sourceIndex]; 245 [newLayers insertObject:aLayer atIndex:targetIndex + (sourceIndex < targetIndex ? 0 : 1)]; 246 247 /* 248 for (i = 0, j = 0; [newLayers count] < [layers count]; i++, j++) 249 { 250 if (aLayer == [layers objectAtIndex:i]) { j++; } 251 if (i == targetIndex) 252 { 253 [newLayers addObject:[layers objectAtIndex:sourceIndex]]; 254 } 255 if (j == [layers count]) { break; } 256 [newLayers addObject:[layers objectAtIndex:j]]; 257 } 258 */ 259 260 261 262 [layers release]; 263 layers = newLayers; 264 265 [self layersChanged]; 266} 267 268- (NSSize)size 269{ 270 if([layers count] > 0) { return [[layers objectAtIndex:0] size]; } 271 return NSZeroSize; 272} 273 274 275- (void)setSize:(NSSize)aSize withOrigin:(NSPoint)origin backgroundColor:(NSColor *)color 276{ 277 id enumerator = [layers objectEnumerator]; 278 id current; 279 while ( ( current = [enumerator nextObject] ) ) 280 { 281 [current setSize:aSize withOrigin:origin backgroundColor:color]; 282 } 283 if([layers count] == 0) 284 { 285 [self addLayer:[[[PXLayer alloc] initWithName:@"Main" size:aSize] autorelease]]; 286 [self activateLayer:[layers objectAtIndex:0]]; 287 } 288 [self layersChanged]; 289 [self canvasShouldRedraw:nil]; 290} 291 292- (void)setSize:(NSSize)aSize 293{ 294 [self setSize:aSize withOrigin:NSMakePoint(0,0) backgroundColor:[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0]]; 295} 296 297- (NSSize)previewSize 298{ 299 if (previewSize.width == 0 && previewSize.height == 0) { 300 return [self size]; 301 } 302 return previewSize; 303} 304 305- (void)setPreviewSize:(NSSize)aSize 306{ 307 previewSize = aSize; 308} 309 310- (BOOL)hasSelection 311{ 312 return [[layers lastObject] isKindOfClass:[PXSelectionLayer class]]; 313} 314 315- (void)deselect 316{ 317 if(![self hasSelection]) { return; } 318 [self activateLayer:lastActiveLayer]; 319 lastActiveLayer = nil; 320 [activeLayer compositeUnder:[layers lastObject] flattenOpacity:NO]; 321 [layers removeLastObject]; 322 [self layersChanged]; 323} 324 325- (void)deselectPixelAtPoint:(NSPoint)point 326{ 327 if(![self hasSelection]) { return; } 328 if (![[[layers lastObject] workingPoints] objectAtCoordinates:(unsigned)point.x, (unsigned)point.y]) 329 { 330 [activeLayer setColor:[[layers lastObject] colorAtPoint:point] atPoint:point]; 331 } 332 [[layers lastObject] removeWorkingPoint:point]; 333} 334 335- (void)finalizeSelection 336{ 337 if(![self hasSelection]) { return; } 338 unsigned i, j; 339 for(i = 0; i < [[layers lastObject] size].width; i++) 340 { 341 for(j = 0; j < [[layers lastObject] size].height; j++) 342 { 343 NSPoint point = NSMakePoint(i, j); 344 if (![self pointIsSelected:point] || ([[layers lastObject] colorAtPoint:point] != nil)) { continue; } 345 id color = [activeLayer colorAtPoint:point]; 346 if(color == nil) { color = [NSColor clearColor]; } 347 [[layers lastObject] setColor:color atPoint:point]; 348 [activeLayer setColor:nil atPoint:point]; 349 } 350 } 351 [[layers lastObject] finalize]; 352 [self activateLayer:[layers lastObject]]; 353} 354 355- (void)selectPixelAtPoint:(NSPoint)point 356{ 357 if(![self hasSelection]) 358 { 359 id newLayer = [PXSelectionLayer selectionWithSize:[self size]]; 360 [self addLayer:newLayer]; 361 [newLayer setOpacity:[activeLayer opacity]]; 362 } 363 [[layers lastObject] addWorkingPoint:point]; 364} 365 366- (BOOL)pointIsSelected:(NSPoint)point 367{ 368 if(![self hasSelection]) { return NO; } 369 return ([[layers lastObject] pointIsSelected:point]); 370} 371 372- (NSData *)selectionData 373{ 374 return [NSKeyedArchiver archivedDataWithRootObject:[layers lastObject]]; 375} 376 377- (void)pasteFromPasteboard:board type:type 378{ 379 [self deselect]; 380 if ([type isEqualToString:@"PXLayer"]) 381 { 382 id layer = [NSKeyedUnarchiver unarchiveObjectWithData:[board dataForType:type]]; 383 if (!NSEqualSizes([layer size], [self size])) { 384 [layer setSize:[self size]]; 385 } 386 [self addLayer:layer]; 387 [self finalizeSelection]; 388 } 389 else if ([type isEqualToString:@"NSImage"]) 390 { 391 id image = [[[NSImage alloc] initWithPasteboard:board] autorelease]; 392 if ([image size].width > [self size].width || [image size].height > [self size].height) 393 { 394#ifdef __COCOA__ 395 switch ([[NSAlert alertWithMessageText:@"The pasted image is too big!" 396 defaultButton:@"Resize Canvas" 397 alternateButton:@"Cancel Paste" 398 otherButton:@"Paste Anyway" 399 informativeTextWithFormat:@"The pasted image is %dx%d, while the canvas is only %dx%d.", 400 (int)([image size].width), (int)([image size].height), 401 (int)([self size].width), (int)([self size].height)] 402 runModal]) 403 { 404 case NSAlertDefaultReturn: 405 [self setSize:[image size]]; 406 [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasSizeChangedNotificationName object:nil]; 407 break; 408 case NSAlertAlternateReturn: 409 return; 410 case NSAlertOtherReturn: 411 break; 412 default: 413 break; 414 } 415#else 416#warning GNUstep TODO 417#endif 418 } 419 [self addLayer:[[PXLayer alloc] initWithName:@"Pasted Image" size:[self size]]]; 420 [self activateLayer:[layers lastObject]]; 421 [self applyImage:image toLayer:[layers lastObject]]; 422 } 423 [self layersChanged]; 424} 425 426- (void)deleteSelection 427{ 428 if (![self hasSelection]) { return; } 429 [layers removeLastObject]; 430 [self layersChanged]; 431 [self activateLayer:lastActiveLayer]; 432} 433 434- (void)selectAll 435{ 436 [self deselect]; 437 int i, j; 438 for(i = 0; i < [self size].width; i++) 439 { 440 for(j = 0; j < [self size].height; j++) 441 { 442 [self selectPixelAtPoint:NSMakePoint(i, j)]; 443 } 444 } 445 [self finalizeSelection]; 446} 447 448- (NSRect)selectedRect 449{ 450 NSRect selected = NSZeroRect; 451 int i, j; 452 for(i = 0; i < [self size].width; i++) 453 { 454 for(j = 0; j < [self size].height; j++) 455 { 456 if([self pointIsSelected:NSMakePoint(i, j)]) 457 { 458 NSRect currentRect = NSMakeRect(i, j, 1, 1); 459 if (NSEqualRects(selected, NSZeroRect)) 460 selected = currentRect; 461 else 462 selected = NSUnionRect(selected, NSMakeRect(i, j, 1, 1)); 463 } 464 } 465 } 466 return selected; 467} 468 469- (BOOL)canDrawAtPoint:(NSPoint)point 470{ 471// return [activeLayer canDrawAtPoint:point]; 472 return ([[NSUserDefaults standardUserDefaults] boolForKey:@"PXShouldTile"] ? YES : [activeLayer canDrawAtPoint:point]); 473} 474 475- copyWithZone:zone 476{ 477 return [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self]]; 478} 479 480- imageDataWithType:(NSBitmapImageFileType)storageType properties:(NSDictionary *)properties 481{ 482 NSRect frame = NSMakeRect(0, 0, [self size].width, [self size].height); 483 id outputImage = [[[NSImage alloc] initWithSize:[self size]] autorelease]; 484 [outputImage lockFocus]; 485 [self drawRect:frame fixBug:YES]; 486 id rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:frame] autorelease]; 487 [outputImage unlockFocus]; 488 489 if (storageType == NSBMPFileType) 490 { 491#ifdef __COCOA__ 492 return [PXBitmapExporter BMPDataForImage:outputImage]; 493#else 494#warning GNUstep / COCOA implement that without Quicktime 495return nil; 496#endif 497 } 498 499 /*if (storageType == NSGIFFileType) 500 { 501 id oldLayers = layers; 502 id newLayers = [layers deepMutableCopy]; 503 id enumerator = [newLayers objectEnumerator], current; 504 while (current = [enumerator nextObject]) 505 { 506 int i, j; 507 id image = [current image]; 508 for (i = 0; i < [image size].width; i++) 509 { 510 for (j = 0; j < [image size].height; j++) 511 { 512 NSPoint point = NSMakePoint(i, j); 513 id color = [image colorAtPoint:point]; 514 if ([color alphaComponent] < 1 || [color alphaComponent] > 0) 515 { 516 [image setColor:[color colorWithAlphaComponent:rint([color alphaComponent])] atPoint:point]; 517 } 518 } 519 } 520 } 521 //layers = newLayers; 522 523 id data = [rep representationUsingType:storageType properties:properties]; 524 //layers = oldLayers; 525 [newLayers release]; 526 return data; 527 }*/ 528 else 529 { 530 return [rep representationUsingType:storageType properties:properties]; 531 } 532} 533 534- PICTData 535{ 536 NSRect frame = NSMakeRect(0, 0, [self size].width, [self size].height); 537 id outputImage = [[[NSImage alloc] initWithSize:[self size]] autorelease]; 538 [outputImage lockFocus]; 539 [self drawRect:frame fixBug:YES]; 540 [outputImage unlockFocus]; 541#ifdef __COCOA__ 542 return [PXBitmapExporter PICTDataForImage:outputImage]; 543#else 544#warning GNUstep/Cocoa implement that without Quicktime 545return nil; 546#endif 547} 548 549- initWithImage:(NSImage *)anImage 550{ 551 [self init]; 552 //some PNGs have ... fractional sizes. So I put in this ceilfing. 553 [self setSize:NSMakeSize(ceilf([anImage size].width), ceilf([anImage size].height))]; 554 [self applyImage:anImage toLayer:activeLayer]; 555 return self; 556} 557 558- initWithPSDData:(NSData *)data 559{ 560#ifdef __COCOA__ 561 [self init]; 562 id images = [PXPSDHandler imagesForPSDData:data]; 563 [self setSize:[[images objectAtIndex:0] size]]; 564 id enumerator = [images objectEnumerator], current; 565 while (current = [enumerator nextObject]) 566 { 567 id layer = [[[PXLayer alloc] initWithName:@"Imported Layer" size:[current size]] autorelease]; 568 [self addLayer:layer]; 569 [self applyImage:current toLayer:layer]; 570 } 571 return self; 572#else 573#warning GNUstep implement that without QUICKTIME 574 return nil; 575#endif 576} 577 578- (void)applyImage:anImage toLayer:aLayer 579{ 580 int i, j; 581 NSPoint point; 582 id pool; 583 584 [anImage lockFocus]; 585 id imageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0,0,[anImage size].width, [anImage size].height)]; 586 [anImage unlockFocus]; 587 unsigned char * bitmapData = [imageRep bitmapData]; 588 589 BOOL hasAlpha = ([imageRep samplesPerPixel] > 3); 590 for(i = 0; i < floorf([anImage size].width); i++) 591 { 592 pool = [[NSAutoreleasePool alloc] init]; 593 for(j = 0; j < floorf([anImage size].height); j++) 594 { 595 point = NSMakePoint(i, j); 596 id color; 597 if (hasAlpha) 598 { 599 unsigned long long baseIndex = (j * 4 * [anImage size].width) + (i * 4); 600 color = [NSColor colorWithCalibratedRed:bitmapData[baseIndex + 0] / 255.0f 601 green:bitmapData[baseIndex + 1] / 255.0f 602 blue:bitmapData[baseIndex + 2] / 255.0f 603 alpha:bitmapData[baseIndex + 3] / 255.0f]; 604 } 605 else 606 { 607 unsigned long long baseIndex = (j * 3 * [anImage size].width) + (i * 3); 608 color = [NSColor colorWithCalibratedRed:bitmapData[baseIndex + 0] / 255.0f 609 green:bitmapData[baseIndex + 1] / 255.0f 610 blue:bitmapData[baseIndex + 2] / 255.0f 611 alpha:1]; 612 } 613 [aLayer setColor:color atPoint:NSMakePoint(i, [anImage size].height - j - 1)]; 614 } 615 [pool release]; 616 } 617 [imageRep release]; 618} 619 620- palette 621{ 622 return palette; 623} 624 625- mainBackgroundName 626{ 627 return mainBackgroundName; 628} 629 630- (void)setMainBackgroundName:aName 631{ 632 id old = mainBackgroundName; 633 mainBackgroundName = [aName copy]; 634 [old release]; 635} 636 637- alternateBackgroundName 638{ 639 return alternateBackgroundName; 640} 641 642- (void)setAlternateBackgroundName:aName 643{ 644 id old = alternateBackgroundName; 645 alternateBackgroundName = [aName copy]; 646 [old release]; 647} 648 649- (void)replacePixelsOfColor:oldColor withColor:newColor 650{ 651 //i wish i had blocks 652 id enumerator = [layers objectEnumerator]; 653 id current; 654 while ( (current = [enumerator nextObject]) ) 655 { 656 [current replacePixelsOfColor:oldColor withColor:newColor]; 657 } 658 [self changedInRect:NSMakeRect(0, 0, [self size].width, [self size].height)]; 659} 660 661- (NSSize)gridUnitSize 662{ 663 return gridUnitSize; 664} 665 666- (void)setGridUnitSize:(NSSize)newGridUnitSize 667{ 668 gridUnitSize = newGridUnitSize; 669} 670 671- gridColor 672{ 673 return gridColor; 674} 675 676- (void)setGridColor:newGridColor 677{ 678 [newGridColor retain]; 679 [gridColor release]; 680 gridColor = newGridColor; 681} 682 683- (BOOL)gridShouldDraw 684{ 685 return gridShouldDraw; 686} 687 688- (void)setGridShouldDraw:(BOOL)newGridShouldDraw 689{ 690 gridShouldDraw = newGridShouldDraw; 691} 692 693- (void)drawRect:(NSRect)rect fixBug:(BOOL)fixBug 694{ 695 id enumerator = [layers objectEnumerator]; 696 id current; 697 698 // If fixBug is YES, we need to draw the layers in reverse order because 699 // we're using composite under. Bah. 700 701 if (fixBug) 702 { 703 int i; 704 for (i = [layers count] - 1; i >= 0; i--) 705 { 706 [[layers objectAtIndex:i] drawRect:rect fixBug:fixBug]; 707 } 708 } 709 else 710 { 711 while ( (current = [enumerator nextObject]) ) 712 { 713 [current drawRect:rect fixBug:fixBug]; 714 } 715 } 716} 717 718- (void)palette:aPalette foundDuplicateColorsAtIndex:(unsigned)first andIndex:(unsigned)second 719{ 720 id oldColor = [palette colorAtIndex:first]; 721 id newColor = [oldColor colorWithAlphaComponent:[oldColor alphaComponent] - 0.0001]; 722 [palette setColor:newColor atIndex:second]; 723} 724 725- initWithCoder:coder 726{ 727 [self init]; 728 id image; 729 if ( (image = [[coder decodeObjectForKey:@"image"] retain] ) ) 730 { 731 layers = [[NSMutableArray alloc] initWithCapacity:23]; 732 [layers addObject:image]; 733 } 734 else 735 { 736 layers = [[coder decodeObjectForKey:@"layers"] retain]; 737 if(layers == nil) 738 { 739 layers = [[coder decodeObjectForKey:@"forms"] retain]; 740 } 741 } 742 if([[layers lastObject] isKindOfClass:[PXImage class]] && ([layers count] == 1)) 743 { 744 [layers replaceObjectAtIndex:0 withObject:[[[PXLayer alloc] initWithName:@"Main" image:[layers lastObject]] autorelease]]; 745 } 746 [self setMainBackgroundName:[coder decodeObjectForKey:@"mainBackgroundName"]]; 747 [self setAlternateBackgroundName:[coder decodeObjectForKey:@"alternateBackgroundName"]]; 748 [self setGridShouldDraw:[coder decodeBoolForKey:@"gridShouldDraw"]]; 749 [self setGridUnitSize:[coder decodeSizeForKey:@"gridUnitSize"]]; 750 [self setGridColor:[coder decodeObjectForKey:@"gridColor"]]; 751 if(gridColor == nil) 752 { 753 [self setDefaultGridParameters]; 754 } 755 [self setPreviewSize:[coder decodeSizeForKey:@"previewSize"]]; 756 757 activeLayer = [layers lastObject]; 758 if(!(palette = [[coder decodeObjectForKey:@"palette"] retain])) 759 { 760 palette = [[PXPalette alloc] initWithName:NSLocalizedString(@"GENERATED_PALETTE", @"Generated Palette")]; 761 id enumerator = [layers objectEnumerator]; 762 id current; 763 while ( (current = [enumerator nextObject]) ) 764 { 765 int i, j; 766 for(i = 0; i < [self size].width; i++) 767 { 768 for(j = 0; j < [self size].height; j++) 769 { 770 [palette addColor:[current colorAtPoint:NSMakePoint(i, j)]]; 771 } 772 } 773 } 774 } 775 return self; 776} 777 778//violates law of demeter. live with it. 779- (BOOL)hasImage:anImage 780{ 781 id enumerator = [layers objectEnumerator]; 782 id current; 783 while ( (current = [enumerator nextObject] ) ) 784 { 785 if([current image] == anImage) 786 { 787 return YES; 788 } 789 } 790 return NO; 791} 792 793- (void)colorAdded:aNotification 794{ 795 if([self hasImage:[aNotification object]]) 796 { 797 [palette addColor:[[aNotification userInfo] objectForKey:@"color"]]; 798 } 799} 800 801- (void)setDefaultGridParameters 802{ 803 //maybe this should be in PXCanvasView or PXGrid instead. 804 id defaults = [NSUserDefaults standardUserDefaults]; 805 if([defaults objectForKey:@"PXGridColorData"] == nil) 806 { 807 [self setGridShouldDraw:NO]; 808 [self setGridUnitSize:NSMakeSize(1,1)]; 809 [self setGridColor:[NSColor blackColor]]; 810 } 811 else 812 { 813 [self setGridShouldDraw:[defaults boolForKey:@"PXGridShouldDraw"]]; 814 [self setGridUnitSize:NSMakeSize([defaults floatForKey:@"PXGridUnitWidth"], [defaults floatForKey:@"PXGridUnitHeight"])]; 815 [self setGridColor:[NSKeyedUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"PXGridColorData"]]]; 816 } 817} 818 819- (void)encodeWithCoder:coder 820{ 821 [coder encodeObject:layers forKey:@"layers"]; 822 [coder encodeSize:[self size] forKey:@"size"]; //even though we got rid of canvas's size, we need to keep this around so Pixens before r1v12 can read post-r1v12 pxis. 823 [coder encodeObject:mainBackgroundName forKey:@"mainBackgroundName"]; 824 [coder encodeObject:alternateBackgroundName forKey:@"alternateBackgroundName"]; 825 [coder encodeBool:gridShouldDraw forKey:@"gridShouldDraw"]; 826 [coder encodeSize:gridUnitSize forKey:@"gridUnitSize"]; 827 [coder encodeObject:gridColor forKey:@"gridColor"]; 828 [coder encodeSize:previewSize forKey:@"previewSize"]; 829 [coder encodeObject:palette forKey:@"palette"]; 830} 831 832- (void)setLastDrawnPoint:(NSPoint)point 833{ 834 lastDrawnPoint = point; 835} 836 837- (NSPoint)lastDrawnPoint 838{ 839 return lastDrawnPoint; 840} 841 842@end 843