1#import "PXPaletteSwitcher.h"
2#import "PXPalette.h"
3#import "PXNamePrompter.h"
4#import "PXCanvas.h"
5#import "PXDocument.h"
6#import "PXColorPaletteController.h"
7#import "PXGradientBuilderController.h"
8#import <math.h>
9
10#ifdef __COCOA__
11static NSString *COLORPALLETTESPRESET = @"Application Support/Pixen/Palettes/Presets";
12#else
13static NSString *COLORPALLETTESPRESET = @"Pixen/Palettes/Presets";
14#endif
15
16/**************************/
17/** Private categories ****/
18/**************************/
19
20@interface PXPaletteSwitcher (Private)
21- (void) _populatePopup: (NSPopUpButton *) aPopup withDefaultPalettesUsingSelectionAction:(SEL)aSelector;
22- (void) _populatePopup:(NSPopUpButton *) aPopup withUserPalettesUsingSelectionAction:(SEL)aSelector;
23@end
24
25@implementation PXPaletteSwitcher (Private)
26
27- (void) _populatePopup:(NSPopUpButton *) aPopup withDefaultPalettesUsingSelectionAction:(SEL)aSelector
28{
29	if( [defaultPalettes count] == 0 )
30    {
31		defaultPalettes = [[[self class] defaultPalettes] deepMutableCopy];
32    }
33
34	id enumerator = [defaultPalettes objectEnumerator];
35	id current;
36
37	while ( ( current = [enumerator nextObject] ) )
38    {
39		id item = [[[NSMenuItem alloc] initWithTitle:[current name] action:aSelector keyEquivalent:@""] autorelease];
40		[item setRepresentedObject:current];
41		[item setTarget:self];
42		[[aPopup menu] addItem:item];
43    }
44}
45
46- (void) _populatePopup:(NSPopUpButton *)aPopup withUserPalettesUsingSelectionAction:(SEL)aSelector
47{
48	if([userPalettes count] == 0)
49    {
50		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
51		if ( [paths count] > 0 )
52		{
53			id current;
54			NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:COLORPALLETTESPRESET];
55
56			id enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path];
57
58			while( ( current = [enumerator nextObject] ) )
59			{
60				if([[current pathExtension] isEqualToString:@"pxpalette"])
61				{
62					id aPalette = [NSKeyedUnarchiver unarchiveObjectWithFile:[path stringByAppendingPathComponent:current]];
63					id item = [[[NSMenuItem alloc] initWithTitle:[current stringByDeletingPathExtension]
64														  action:aSelector
65												   keyEquivalent:@""] autorelease];
66
67					[item setRepresentedObject:aPalette];
68					[item setTarget:self];
69					[[aPopup menu] addItem:item];
70					[userPalettes addObject:aPalette];
71				}
72			}
73		}
74    }
75	else
76    {
77		id enumerator = [userPalettes objectEnumerator];
78		id current;
79		while ( ( current = [enumerator nextObject] ) )
80		{
81			id item = [[[NSMenuItem alloc] initWithTitle:[current name]
82												  action:aSelector
83										   keyEquivalent:@""] autorelease];
84
85			[item setRepresentedObject:current];
86			[item setTarget:self];
87			[[aPopup menu] addItem:item];
88		}
89    }
90
91	if([userPalettes count] == 0)
92    {
93		[aPopup setAutoenablesItems:NO];
94		id item = [[[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"NO_USER_PALETTES", @"No User Palettes")
95											  action:nil keyEquivalent:@""] autorelease];
96		[item setTarget:nil];
97		[item setEnabled:NO];
98		[[aPopup menu] addItem:item];
99    }
100}
101
102
103@end
104
105
106@implementation PXPaletteSwitcher
107
108+ defaultPalettes
109{
110	static id palettes = nil;
111	if(palettes == nil)
112    {
113		palettes = [[NSMutableArray alloc] initWithCapacity:48];
114		id enumerator = [[NSColorList availableColorLists] objectEnumerator];
115		id current;
116		while( ( current = [enumerator nextObject]) )
117		{
118			id colors = [NSMutableArray arrayWithCapacity:128];
119			id colorEnumerator = [[current allKeys] objectEnumerator];
120			id currentColor;
121			while( ( currentColor = [colorEnumerator nextObject] )  )
122			{
123				[colors addObject:[current colorWithKey:currentColor]];
124			}
125			[palettes addObject:[[[PXPalette alloc] initWithName:[current name] colors:colors] autorelease]];
126		}
127
128		float rgb = 0;
129		float alpha = 1;
130		id grays = [NSMutableArray arrayWithCapacity:256];
131		id color;
132
133		int i = 0;
134		for (i=0; i<64; i++) {
135			rgb = (float)i / 64.0;
136			color = [NSColor colorWithCalibratedRed:rgb green:rgb blue:rgb alpha:alpha];
137			[grays addObject:color];
138		}
139		rgb = 0;
140		for (i=0; i<64; i++) {
141			alpha = log2(64 - i) * 0.1667;
142			color = [NSColor colorWithCalibratedRed:rgb green:rgb blue:rgb alpha:alpha];
143			[grays addObject:color];
144		}
145		rgb = .5;
146		for (i=0; i<64; i++) {
147			alpha = log2(64 - i) * 0.1667;
148			color = [NSColor colorWithCalibratedRed:rgb green:rgb blue:rgb alpha:alpha];
149			[grays addObject:color];
150		}
151		rgb = 1;
152		for (i=0; i<64; i++) {
153			alpha = log2(64 - i) * 0.1667;
154			color = [NSColor colorWithCalibratedRed:rgb green:rgb blue:rgb alpha:alpha];
155			[grays addObject:color];
156		}
157		[palettes addObject:[[[PXPalette alloc] initWithName:NSLocalizedString(@"GRAYSCALE", @"Grayscale") colors:grays] autorelease]];
158    }
159	return palettes;
160}
161
162-(id) init
163{
164	if (! ( self = [super init] )  )
165		return nil;
166
167	namePrompter = [[PXNamePrompter alloc] init];
168	[namePrompter setDelegate:self];
169	defaultPalettes = [[NSMutableArray alloc] initWithCapacity:32];
170	userPalettes = [[NSMutableArray alloc] initWithCapacity:32];
171	gradientBuilder = [[PXGradientBuilderController alloc] initWithPaletteSwitcher:self];
172
173	return self;
174}
175
176
177- (void)dealloc
178{
179	[userPalettes release];
180	[defaultPalettes release];
181	[namePrompter release];
182	[super dealloc];
183}
184
185
186- (void) populateMenuForCanvas: (id) aCanvas
187{
188	[paletteChooser setEnabled:YES];
189	canvas = aCanvas;
190	id selected = [[[paletteChooser titleOfSelectedItem] retain] autorelease];
191	[paletteChooser removeAllItems];
192	id menu = [paletteChooser menu];
193	[self _populatePopup:paletteChooser withDefaultPalettesUsingSelectionAction:@selector(selectPalette:)];
194	[menu addItem:[NSMenuItem separatorItem]];
195	[self _populatePopup:paletteChooser withUserPalettesUsingSelectionAction:@selector(selectPalette:)];
196	[menu addItem:[NSMenuItem separatorItem]];
197	id canvasPalette = [canvas palette];
198
199	if(canvasPalette != nil)
200    {
201		id item = [[[NSMenuItem alloc] initWithTitle:[canvasPalette name]
202											  action:@selector(selectPalette:)
203									   keyEquivalent:@""] autorelease];
204
205		[item setRepresentedObject:canvasPalette];
206		[item setTarget:self];
207		[[paletteChooser menu] addItem:item];
208		[menu addItem:[NSMenuItem separatorItem]];
209    }
210
211	[menu addItemWithTitle:NSLocalizedString(@"PALETTE_SAVE_AS", @"Palette Save As")
212					action:@selector(saveCurrentPalette:)
213			 keyEquivalent:@""];
214	[[menu itemWithTitle:NSLocalizedString(@"PALETTE_SAVE_AS", @"Palette Save As")] setTarget:self];
215
216	[menu addItemWithTitle:NSLocalizedString(@"PALETTE_SET_DEFAULT", @"Set As Default")
217					action:@selector(setCurrentPaletteAsDefault:)
218			 keyEquivalent:@""];
219	[[menu itemWithTitle:NSLocalizedString(@"PALETTE_SET_DEFAULT", @"Set As Default")] setTarget:self];
220
221	[menu addItemWithTitle:NSLocalizedString(@"PALETTE_DELETE", @"Palette Delete")
222					action:@selector(deleteCurrentPalette:)
223			 keyEquivalent:@""];
224	[[menu itemWithTitle:NSLocalizedString(@"PALETTE_DELETE", @"Palette Delete")] setTarget:self];
225
226	[menu addItemWithTitle:NSLocalizedString(@"PALETTE_MAKE_GRADIENT", @"Make Gradient")
227					action:@selector(makeGradient:)
228			 keyEquivalent:@""];
229	[[menu itemWithTitle:NSLocalizedString(@"PALETTE_MAKE_GRADIENT", @"Make Gradient")] setTarget:self];
230
231	if(![[paletteChooser itemTitles] containsObject:selected]
232	   || [[paletteChooser titleOfSelectedItem] isEqualToString:NSLocalizedString(@"PALETTE_DELETE", @"Palette Delete")]
233	   || (selected == nil)
234	   || [selected isEqual:@""])
235    {
236		[self selectDefaultPalette];
237#warning safer ?
238		if ( ! [paletteChooser selectedItem] )
239			[self performSelector:[[paletteChooser itemAtIndex:0] action] withObject:[paletteChooser selectedItem]];
240		else
241			[self performSelector:[[paletteChooser selectedItem] action] withObject:[paletteChooser selectedItem]];
242    }
243
244	else if(![selected isEqualToString:NSLocalizedString(@"PALETTE_SAVE_AS", @"Palette Save As")]
245			&& ![selected isEqualToString:NSLocalizedString(@"PALETTE_MAKE_GRADIENT", @"Make Gradient")])
246    {
247		[paletteChooser selectItemWithTitle:selected];
248		[self performSelector:[[paletteChooser selectedItem] action] withObject:[paletteChooser selectedItem]];
249    }
250}
251
252
253
254
255- (unsigned)indexOfPalette:aPalette
256{
257	unsigned index = [userPalettes indexOfObject:aPalette];
258	if (index != NSNotFound)
259		return index;
260
261
262	for (index = 0; index < [userPalettes count]; index++)
263    {
264		if ( [[aPalette name] isEqualToString:[[userPalettes objectAtIndex:index] name]] )
265		{
266			return index;
267		}
268	}
269
270	return NSNotFound;
271}
272
273- (void)addNewPalette:(id) newPalette withName:(NSString *) name replacingPaletteAtIndex:(unsigned)index
274{
275	[(PXPalette *)newPalette setName:name];
276
277	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
278
279	if ( [paths count] ==  0 )
280		return;
281
282    //Construct the file path
283	NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:COLORPALLETTESPRESET];
284	path = [[path  stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"pxpalette"];
285
286	[NSKeyedArchiver archiveRootObject:newPalette toFile:path];
287	if ( index == NSNotFound )
288    {
289		[userPalettes addObject:newPalette];
290    }
291	else
292    {
293		[userPalettes replaceObjectAtIndex:index withObject:newPalette];
294    }
295
296	[self populateMenuForCanvas:canvas];
297	[paletteChooser selectItemWithTitle:name];
298
299	[self performSelector:[[paletteChooser itemWithTitle:name] action] withObject:[paletteChooser itemWithTitle:name]];
300
301}
302
303
304
305- (void)selectDefaultPalette
306{
307	if ([[NSUserDefaults standardUserDefaults] stringForKey:@"PXDefaultPalette"] == nil)
308    {
309		[[NSUserDefaults standardUserDefaults] setObject:@"Crayons" forKey:@"PXDefaultPalette"];
310    }
311
312	NSString *defaultPaletteName = [[NSUserDefaults standardUserDefaults] objectForKey:@"PXDefaultPalette"];
313
314	if ([paletteChooser itemWithTitle:defaultPaletteName] == nil)
315    {
316		[self selectPaletteNamed:@"Crayons"];
317    }
318	else
319    {
320		[self selectPaletteNamed:defaultPaletteName];
321    }
322}
323
324- (void)selectPaletteNamed:(NSString *) aName
325{
326	[paletteChooser setEnabled:YES];
327
328	if([paletteChooser itemWithTitle:aName] == nil)
329		return;
330
331	[paletteChooser selectItemWithTitle:aName];
332
333	[self performSelector:[[paletteChooser selectedItem] action] withObject:[paletteChooser selectedItem]];
334}
335
336- (void)setDelegate: (id) aDelegate
337{
338	_delegate = aDelegate;
339}
340
341
342//
343// IBActions
344//
345
346- (IBAction)deleteCurrentPalette:sender
347{
348	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
349	//Should never happen
350	if ( [paths count] == 0 )
351		return;
352
353	NSString *apath = [[paths objectAtIndex:0] stringByAppendingPathComponent:COLORPALLETTESPRESET];
354	NSString *path = [[apath stringByAppendingPathComponent:[palette name]] stringByAppendingPathExtension:@"pxpalette"];
355
356#warning Should check if readable ? Should check if isDirectory ?
357
358	if( ! [[NSFileManager defaultManager] fileExistsAtPath:path] )
359    {
360		[self selectDefaultPalette];
361		return;
362    }
363
364	[[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
365	[userPalettes removeObject:palette];
366	[self populateMenuForCanvas:canvas];
367}
368
369
370- (IBAction)makeGradient:(id)sender
371{
372	[gradientBuilder beginSheetInWindow:[[PXColorPaletteController sharedPaletteController] palettePanel]];
373}
374
375
376- (IBAction)selectPalette:(id) sender
377{
378	palette = [sender representedObject];
379	[_delegate setPalette:palette];
380}
381
382- (IBAction)saveCurrentPalette:(id) sender
383{
384	[namePrompter promptInWindow:[_delegate palettePanel] context:palette
385					promptString:NSLocalizedString(@"NEW_PALETTE_PROMPT", @"New Palette Prompt")
386					defaultEntry:[palette name]];
387}
388
389- (IBAction)setCurrentPaletteAsDefault:(id) sender
390{
391	[[NSUserDefaults standardUserDefaults] setObject:[palette name] forKey:@"PXDefaultPalette"];
392	[self selectDefaultPalette];
393}
394
395@end
396
397
398
399@implementation PXPaletteSwitcher ( NamePrompterDelegate )
400
401- (void)prompter:aPrompter didFinishWithName:name context:contextObject
402{
403	[self addNewPalette:[[contextObject copy] autorelease]
404			   withName:name
405replacingPaletteAtIndex:[self indexOfPalette:contextObject]];
406}
407
408- (void)prompter:aPrompter didCancelWithContext:contextObject
409{
410	[paletteChooser selectItemWithTitle:[palette name]];
411
412	[self performSelector:[[paletteChooser itemWithTitle:[palette name]] action]
413			   withObject:[paletteChooser itemWithTitle:[palette name]]];
414}
415
416
417@end
418