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