1//
2//  PXColorPaletteController.m
3//  Pixen-XCode
4//
5// Copyright (c) 2004 Open Sword Group
6
7// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
8// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use,
9//copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
10// to whom the Software is furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
16// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
19#import "PXColorPaletteController.h"
20#import "SubviewTableViewCell.h"
21#import "PXColorWellCell.h"
22#import "PXColorWell.h"
23#import "PXDocument.h"
24#import "PXCanvas.h"
25#import "PXPalette.h"
26#import "PXPaletteSwitcher.h"
27
28#import <AppKit/NSNibLoading.h>
29
30
31static PXColorPaletteController *singleInstance = nil;
32//TODO Define  notification here
33
34@interface PXColorPaletteController (Private)
35- (void) _replaceColor:(NSColor *) oldColor withColor:(NSColor*) newColor atPaletteIndex:(unsigned)index swapping:(BOOL)swap;
36- (void) _colorWellSelected: (NSNotification *) aNotification;
37- (void) _colorAdded:(NSNotification*) aNotification;
38- (void)_colorWellColorChanged:(NSNotification *) aNotification;
39@end
40
41@implementation PXColorPaletteController (Private)
42
43- (void) _replaceColor:(NSColor *) oldColor withColor:(NSColor*) newColor atPaletteIndex:(unsigned)index swapping:(BOOL)swap
44{
45	if ([newColor isEqual:oldColor])
46		return;
47
48	[[NSNotificationCenter defaultCenter] removeObserver:self
49													name:@"PXImageColorAddedNotification"
50												  object:nil];
51
52	if( ( swap )  && ([oldColor alphaComponent] > .00125) )
53    {
54		[canvas replacePixelsOfColor:oldColor withColor:newColor];
55    }
56
57	[palette setColor:newColor atIndex:index];
58
59	[[NSNotificationCenter defaultCenter] removeObserver:self
60													name:@"PXColorWellColorChanged"
61												  object:nil];
62
63	[(PXColorWell *)[/*[*/[matrix cells] objectAtIndex:index] /*view]*/ setColor:newColor];
64
65	[[NSNotificationCenter defaultCenter] addObserver:self
66											 selector:@selector(_colorWellColorChanged:)
67												 name:@"PXColorWellColorChanged"
68											   object:nil];
69
70	[[NSNotificationCenter defaultCenter] addObserver:self
71											 selector:@selector(_colorAdded:)
72												 name:@"PXImageColorAddedNotification"
73											   object:nil];
74}
75
76- (void)_colorWellSelected:(NSNotification *) aNotification
77{
78	NSDictionary *userInfoDict = [NSDictionary dictionaryWithObjectsAndKeys:[[aNotification object] color], @"color", nil];
79
80    if([[aNotification name] isEqualToString:@"PXColorWellLeftSelected"])
81	{
82		[[NSNotificationCenter defaultCenter] postNotificationName:@"PXPaletteLeftColorChosen"
83															object:self
84														  userInfo:userInfoDict];
85		[leftMatrixWell setColor:[[aNotification object] color]];
86	}
87    else
88	{
89		[[NSNotificationCenter defaultCenter] postNotificationName:@"PXPaletteRightColorChosen"
90															object:self
91														  userInfo:userInfoDict];
92		[rightMatrixWell setColor:[[aNotification object] color]];
93	}
94}
95
96
97- (void)_colorAdded:(NSNotification*) aNotification
98{
99	if (! [canvas isKindOfClass:[PXCanvas class]] )
100		return;
101
102	if([canvas hasImage:[aNotification object]])
103    {
104		int index = [palette addColor:[[aNotification userInfo] objectForKey:@"color"]];
105		if(index != -1)
106		{
107			[[[matrix cells] objectAtIndex:index] setColor:[palette colorAtIndex:index]];
108		}
109    }
110}
111
112
113- (void)_colorWellColorChanged:(NSNotification *) aNotification
114{
115	//if( ([aNotification object] != leftMatrixWell ) && ([aNotification object] != rightMatrixWell) )
116	//	return;
117
118	NSColor *oldColor = [[aNotification userInfo] objectForKey:@"oldColor"];
119	NSColor *newColor = [[aNotification object] color];
120
121	if ([oldColor isEqual:newColor])
122		return;
123
124
125	if ([[palette colors] containsObject:newColor]) {
126		[[aNotification object] _setColorNoVerify:oldColor];
127#ifdef __COCOA__
128		NSBeep();
129#endif
130		return;
131	}
132
133	if( ![[[matrix cells] valueForKey:@"view"] containsObject:[aNotification object]])
134		return;
135	//TODO factorisation
136	if([aNotification object] == leftMatrixWell)
137    {
138		[[NSNotificationCenter defaultCenter] postNotificationName:@"PXPaletteLeftColorChosen"
139															object:self
140														  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:newColor, @"color", nil]];
141    }
142	else
143    {
144		[[NSNotificationCenter defaultCenter] postNotificationName:@"PXPaletteRightColorChosen"
145															object:self
146														  userInfo:[NSDictionary dictionaryWithObjectsAndKeys:newColor, @"color", nil]];
147    }
148
149	[self _replaceColor:oldColor
150			  withColor:newColor
151		 atPaletteIndex:[[[matrix cells] valueForKey:@"view"] indexOfObject:[aNotification object]]
152			   swapping:[[NSUserDefaults standardUserDefaults] boolForKey:@"PXSmartPaletteEnabled"]];
153}
154
155@end
156
157
158@implementation PXColorPaletteController
159
160-(id) init
161{
162	if ( singleInstance )
163    {
164		[self dealloc];
165		return singleInstance;
166    }
167
168	if ( ! (self = [super init] ) )
169		return nil;
170
171	if ( ! [NSBundle loadNibNamed:@"PXColorPalette" owner:self] )
172    {
173		//NSLog(@"warm the user here !!?!");
174		[self dealloc];
175		return nil;
176    }
177
178	singleInstance = self;
179
180	return singleInstance;
181}
182
183-(void) awakeFromNib
184{
185	[panel setBecomesKeyOnlyIfNeeded:YES];
186	[panel setFrameAutosaveName:@"PXColorPaletteFrame"];
187
188	//Create our matrix and put it in the scrollView
189	{
190		int swatchWidth = 32;
191		int swatchHeight = 32;
192		int swatchesAcross = 8;
193		int swatchesDown = 32;
194
195		NSRect matrixRect = NSMakeRect(0, -(swatchesDown*swatchHeight),
196									   (swatchWidth + 1) * swatchesAcross, (swatchHeight + 1) * swatchesDown);
197
198		id prototype = [[PXColorWellCell alloc] init];
199
200		[[NSColorPanel sharedColorPanel] setShowsAlpha:YES];
201
202		//Put it elsewhere
203
204
205		matrix = [[NSMatrix alloc] initWithFrame:matrixRect
206											mode:NSTrackModeMatrix
207									   prototype:prototype
208									numberOfRows:swatchesDown
209								 numberOfColumns:swatchesAcross];
210
211		[matrix setSelectionByRect:NO];
212		[matrix setDrawsBackground:YES];
213		[matrix setDrawsCellBackground:YES];
214		[matrix setAutosizesCells:YES];
215		[matrix setAutoresizingMask:NSViewMaxYMargin];
216		[matrix setAutosizesCells:NO];
217
218		[scrollView setDocumentView:matrix];
219	}
220
221	//Add observers
222	{
223		[[NSNotificationCenter defaultCenter] addObserver:self
224												 selector:@selector(_colorWellSelected:)
225													 name:@"PXColorWellLeftSelected"
226												   object:nil];
227
228		[[NSNotificationCenter defaultCenter] addObserver:self
229												 selector:@selector(_colorWellSelected:)
230													 name:@"PXColorWellRightSelected"
231												   object:nil];
232
233		[[NSNotificationCenter defaultCenter] addObserver:self
234												 selector:@selector(_colorWellColorChanged:)
235													 name:@"PXColorWellColorChanged"
236												   object:nil];
237
238		[[NSNotificationCenter defaultCenter] addObserver:self
239												 selector:@selector(_colorAdded:)
240													 name:@"PXImageColorAddedNotification"
241												   object:nil];
242
243	}
244}
245
246
247+ (id) sharedPaletteController
248{
249	if( ! singleInstance)
250		singleInstance = [[self alloc] init];
251
252	return singleInstance;
253}
254
255
256- (void)selectPaletteNamed:(id)aName
257{
258	[switcher selectPaletteNamed:aName];
259}
260
261- (void)selectDefaultPalette
262{
263	[switcher selectDefaultPalette];
264}
265
266- (BOOL)runReloadWarning
267{
268	[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PXColorPaletteDeletionWarningHasRun"];
269#ifdef __COCOA__
270	return ([[NSAlert alertWithMessageText:@"Discard Palette Changes?" defaultButton:@"Yes" alternateButton:@"No" otherButton:nil informativeTextWithFormat:@"Every time you switch documents, your palette changes are not automatically saved.  To prevent palette data loss, please save any modified palettes that you want to keep.  Would you really like to switch palettes?  If you choose \"No,\" you'll have to switch away and back when you're done to get it to update properly to the new canvas.  This warning will not be given again."] runModal] == NSOKButton);
271#else
272#warning TODO GNUstep
273	return NO;
274#endif
275}
276
277
278- (void)reloadDataForCanvas:(id)aCanvas
279{
280	canvas = aCanvas;
281
282	if ( ( [[NSUserDefaults standardUserDefaults] boolForKey:@"PXColorPaletteDeletionWarningHasRun"] )
283		 || ([self runReloadWarning]) )
284		[switcher populateMenuForCanvas:canvas];
285}
286
287
288- (void)keyDown:(NSEvent *)event
289{
290	int column = -1, row = 0;
291	NSString * chars = [[event charactersIgnoringModifiers] lowercaseString];
292
293	if([[NSScanner scannerWithString:chars] scanInt:&column])
294    {
295		column--;
296		if(column < 0)
297			column = 9;
298    }
299	else
300    {
301		//the characters change when shift is held down, so we can't just do a modifier check
302		//this won't work for international keyboards, either, will it?
303		NSArray * symbols = [NSArray arrayWithObjects:@"!", @"@", @"#", @"$", @"%", @"^", @"&", @"*", @"(", @")", nil];
304		if([symbols containsObject:chars])
305		{
306			column = [symbols indexOfObject:chars];
307			row = 1;
308			if([event modifierFlags] & (NSAlternateKeyMask))
309			{
310				row = 2;
311			}
312		}
313    }
314	if (column == -1)
315		return;
316
317	if ( ([event modifierFlags]) & ( NSControlKeyMask ) )
318    {
319		[[matrix cellAtRow:row column:column] rightSelect];
320    }
321	else
322    {
323		[[matrix cellAtRow:row column:column] leftSelect];
324    }
325}
326
327
328
329
330- (void)palette:(id) aPalette foundDuplicateColorsAtIndex:(unsigned)first andIndex:(unsigned)second
331{
332	NSColor *oldColor = [[palette colorAtIndex:first] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
333	NSColor *newColor = [NSColor colorWithCalibratedRed:[oldColor redComponent] green:[oldColor greenComponent] blue:[oldColor blueComponent] alpha:[oldColor alphaComponent] - 0.000001];
334
335	[self _replaceColor:oldColor
336			  withColor:newColor
337		 atPaletteIndex:second
338			   swapping:[[NSUserDefaults standardUserDefaults] boolForKey:@"PXSmartPaletteEnabled"]];
339}
340
341- (void)setPalette:(id)newPalette
342{
343	if( palette == newPalette )
344		return;
345
346	id old = palette;
347	palette = [newPalette retain];
348	[old autorelease];
349	[palette setDelegate:self];
350	unsigned int i;
351
352	for(i = 0; ((i < [[palette colors] count]) || (i < [[old colors] count])) && (i < 256); i++)
353    {
354		NSColor *oldColor = (i < [[old colors] count]) ? [[old colors] objectAtIndex:i] : [NSColor clearColor];
355		NSColor  *newColor = (i < [[palette colors] count]) ? [[palette colors] objectAtIndex:i] : [[NSColor clearColor] colorWithAlphaComponent:.001];
356
357		//When ObjC looks like Perl :)
358		// STFU N00B, I WILL WRITE A COMMENT
359		// Replace the old color with the new color, determining whether to swap by:
360		// 1) Is the index less than the number of old colors?  If not, there's no point in trying to replace it, since it's out of the bounds anyway.
361		// 2) Is the new palette the generated palette?
362		// 3) Is the old palette the generated palette?
363		// 4) Has the user enabled this functionality?
364
365		[self _replaceColor:oldColor
366				  withColor:newColor
367			 atPaletteIndex:i
368				   swapping:(i < [[old colors] count]) &&
369			![[palette name] isEqual:NSLocalizedString(@"GENERATED_PALETTE", @"Generated Palette")] &&
370			![[old name] isEqual:NSLocalizedString(@"GENERATED_PALETTE", @"Generated Palette")] &&
371			[[NSUserDefaults standardUserDefaults] boolForKey:@"PXSmartPaletteEnabled"]];
372    }
373	//[[[matrix cells] objectAtIndex:0] leftSelect];
374}
375
376
377//Accessor
378-(NSPanel *) palettePanel
379{
380	return panel;
381}
382
383@end
384