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