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