/** NSColor The colorful color class Copyright (C) 1996, 1998, 2001, 2002 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 Author: Fred Kiefer Date: 2001, 2002 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "AppKit/NSColor.h" #include "AppKit/NSColorList.h" #include "AppKit/NSPasteboard.h" #include "AppKit/NSView.h" #include "AppKit/NSImage.h" #include "AppKit/NSGraphics.h" #include "AppKit/PSOperators.h" static Class NSColorClass; @interface GSNamedColor : NSColor { NSString *_catalog_name; NSString *_color_name; NSString *_cached_name_space; NSColor *_cached_color; } - (NSColor*) initWithCatalogName: (NSString *)listName colorName: (NSString *)colorName; - (void) recache; @end @interface GSWhiteColor : NSColor { float _white_component; float _alpha_component; } @end @interface GSDeviceWhiteColor : GSWhiteColor - (NSColor*) initWithDeviceWhite: (float)white alpha: (float)alpha; @end @interface GSCalibratedWhiteColor : GSWhiteColor - (NSColor*) initWithCalibratedWhite: (float)white alpha: (float)alpha; @end @interface GSDeviceCMYKColor : NSColor { float _cyan_component; float _magenta_component; float _yellow_component; float _black_component; float _alpha_component; } - (NSColor*) initWithDeviceCyan: (float)cyan magenta: (float)magenta yellow: (float)yellow black: (float)black alpha: (float)alpha; @end @interface GSRGBColor : NSColor { float _red_component; float _green_component; float _blue_component; float _hue_component; float _saturation_component; float _brightness_component; float _alpha_component; } @end @interface GSDeviceRGBColor : GSRGBColor - (NSColor*) initWithDeviceRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha; - (NSColor*) initWithDeviceHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha; @end @interface GSCalibratedRGBColor : GSRGBColor - (NSColor*) initWithCalibratedRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha; - (NSColor*) initWithCalibratedHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha; @end // FIXME: This is not described in the specification @interface GSPatternColor : NSColor { NSImage *_pattern; } - (NSColor*) initWithPatternImage: (NSImage*) pattern; @end @interface NSColor (GNUstepPrivate) + (NSColor*) colorFromString: (NSString*)string; + (void) defaultsDidChange: (NSNotification*)notification; @end // Class variables static BOOL gnustep_gui_ignores_alpha = YES; static NSColorList *systemColors = nil; static NSMutableDictionary *colorStrings = nil; static NSMutableDictionary *systemDict = nil; static void initSystemColors(void) { NSString *white; NSString *lightGray; NSString *gray; NSString *darkGray; NSString *black; // Set up a dictionary containing the names of all the system colors // as keys and with colors in string format as values. white = [NSString stringWithFormat: @"%f %f %f", NSWhite, NSWhite, NSWhite]; lightGray = [NSString stringWithFormat: @"%f %f %f", NSLightGray, NSLightGray, NSLightGray]; gray = [NSString stringWithFormat: @"%f %f %f", NSGray, NSGray, NSGray]; darkGray = [NSString stringWithFormat: @"%f %f %f", NSDarkGray, NSDarkGray, NSDarkGray]; black = [NSString stringWithFormat: @"%f %f %f", NSBlack, NSBlack, NSBlack]; colorStrings = [[NSMutableDictionary alloc] initWithObjectsAndKeys: lightGray, @"controlBackgroundColor", lightGray, @"controlColor", lightGray, @"controlHighlightColor", white, @"controlLightHighlightColor", darkGray, @"controlShadowColor", black, @"controlDarkShadowColor", black, @"controlTextColor", darkGray, @"disabledControlTextColor", gray, @"gridColor", lightGray, @"headerColor", black, @"headerTextColor", white, @"highlightColor", black, @"keyboardFocusIndicatorColor", lightGray, @"knobColor", gray, @"scrollBarColor", white, @"selectedControlColor", black, @"selectedControlTextColor", lightGray, @"selectedKnobColor", white, @"selectedMenuItemColor", black, @"selectedMenuItemTextColor", lightGray, @"selectedTextBackgroundColor", black, @"selectedTextColor", black, @"shadowColor", white, @"textBackgroundColor", black, @"textColor", lightGray, @"windowBackgroundColor", black, @"windowFrameColor", white, @"windowFrameTextColor", black, @"alternateSelectedControlColor", white, @"alternateSelectedControlTextColor", white, @"rowBackgroundColor", lightGray, @"alternateRowBackgroundColor", lightGray, @"secondarySelectedControlColor", //gray, @"windowFrameColor", //black, @"windowFrameTextColor", nil]; systemColors = [NSColorList colorListNamed: @"System"]; if (systemColors == nil) { systemColors = [[NSColorList alloc] initWithName: @"System"]; } { NSEnumerator *e; NSString *r; BOOL changed = NO; // Set up default system colors e = [colorStrings keyEnumerator]; while ((r = (NSString *)[e nextObject])) { NSString *cs; NSColor *c; if ([systemColors colorWithKey: r]) continue; cs = [colorStrings objectForKey: r]; c = [NSColorClass colorFromString: cs]; NSCAssert1(c, @"couldn't get default system color %@", r); [systemColors setColor: c forKey: r]; changed = YES; } if (changed) [systemColors writeToFile: nil]; } systemDict = [NSMutableDictionary new]; } static NSColor* systemColorWithName(NSString *name) { NSColor* col = [systemDict objectForKey: name]; if (col == nil) { col = [NSColor colorWithCatalogName: @"System" colorName: name]; [systemDict setObject: col forKey: name]; } return col; } @implementation NSColor // // Class methods // + (void) initialize { if (self == [NSColor class]) { NSColorClass = self; // Set the version number [self setVersion: 3]; // ignore alpha by default gnustep_gui_ignores_alpha = YES; // Load or define the system colour list initSystemColors(); // ensure user defaults are loaded, then use them and watch for changes. [self defaultsDidChange: nil]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(defaultsDidChange:) name: NSUserDefaultsDidChangeNotification object: nil]; } } // // Creating an NSColor from Component Values // + (NSColor*) colorWithCalibratedHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha { id c; c = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithCalibratedHue: hue saturation: saturation brightness: brightness alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithCalibratedRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha { id c; c = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithCalibratedRed: red green: green blue: blue alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithCalibratedWhite: (float)white alpha: (float)alpha { id c; c = [GSCalibratedWhiteColor allocWithZone: NSDefaultMallocZone()] ; c = [c initWithCalibratedWhite: white alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithCatalogName: (NSString *)listName colorName: (NSString *)colorName { id c; c = [GSNamedColor allocWithZone: NSDefaultMallocZone()] ; c = [c initWithCatalogName: listName colorName: colorName]; return AUTORELEASE(c); } + (NSColor*) colorWithDeviceCyan: (float)cyan magenta: (float)magenta yellow: (float)yellow black: (float)black alpha: (float)alpha { id c; c = [GSDeviceCMYKColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithDeviceCyan: cyan magenta: magenta yellow: yellow black: black alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithDeviceHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha { id c; c = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithDeviceHue: hue saturation: saturation brightness: brightness alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithDeviceRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha { id c; c = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithDeviceRed: red green: green blue: blue alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorWithDeviceWhite: (float)white alpha: (float)alpha { id c; c = [GSDeviceWhiteColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithDeviceWhite: white alpha: alpha]; return AUTORELEASE(c); } + (NSColor*) colorForControlTint: (NSControlTint)controlTint { // TODO return nil; } + (NSColor*) colorWithPatternImage: (NSImage*)image { id c; c = [GSPatternColor allocWithZone: NSDefaultMallocZone()]; c = [c initWithPatternImage: image]; return AUTORELEASE(c); } // // Creating an NSColor With Preset Components // + (NSColor*) blackColor { return [self colorWithCalibratedWhite: NSBlack alpha: 1.0]; } + (NSColor*) blueColor { return [self colorWithCalibratedRed: 0.0 green: 0.0 blue: 1.0 alpha: 1.0]; } + (NSColor*) brownColor { return [self colorWithCalibratedRed: 0.6 green: 0.4 blue: 0.2 alpha: 1.0]; } + (NSColor*) clearColor { return [self colorWithCalibratedWhite: 0.0 alpha: 0.0]; } + (NSColor*) cyanColor { return [self colorWithCalibratedRed: 0.0 green: 1.0 blue: 1.0 alpha: 1.0]; } + (NSColor*) darkGrayColor { return [self colorWithCalibratedWhite: NSDarkGray alpha: 1.0]; } + (NSColor*) grayColor { return [self colorWithCalibratedWhite: NSGray alpha: 1.0]; } + (NSColor*) greenColor { return [self colorWithCalibratedRed: 0.0 green: 1.0 blue: 0.0 alpha: 1.0]; } + (NSColor*) lightGrayColor { return [self colorWithCalibratedWhite: NSLightGray alpha: 1]; } + (NSColor*) magentaColor { return [self colorWithCalibratedRed: 1.0 green: 0.0 blue: 1.0 alpha: 1.0]; } + (NSColor*) orangeColor { return [self colorWithCalibratedRed: 1.0 green: 0.5 blue: 0.0 alpha: 1.0]; } + (NSColor*) purpleColor { return [self colorWithCalibratedRed: 0.5 green: 0.0 blue: 0.5 alpha: 1.0]; } + (NSColor*) redColor { return [self colorWithCalibratedRed: 1.0 green: 0.0 blue: 0.0 alpha: 1.0]; } + (NSColor*) whiteColor { return [self colorWithCalibratedWhite: NSWhite alpha: 1.0]; } + (NSColor*) yellowColor { return [self colorWithCalibratedRed: 1.0 green: 1.0 blue: 0.0 alpha: 1.0]; } // // Ignoring Alpha Components // + (BOOL) ignoresAlpha { return gnustep_gui_ignores_alpha; } + (void) setIgnoresAlpha: (BOOL)flag { gnustep_gui_ignores_alpha = flag; } // // Copying and Pasting // + (NSColor*) colorFromPasteboard: (NSPasteboard *)pasteBoard { NSData *d = [pasteBoard dataForType: NSColorPboardType]; // FIXME: This should better use the description format if (d != nil) return [NSUnarchiver unarchiveObjectWithData: d]; return nil; } // // System colors stuff. // + (NSColor*) alternateSelectedControlColor { return systemColorWithName(@"alternateSelectedControlColor"); } + (NSColor*) alternateSelectedControlTextColor { return systemColorWithName(@"alternateSelectedControlTextColor"); } + (NSColor*) controlBackgroundColor { return systemColorWithName(@"controlBackgroundColor"); } + (NSColor*) controlColor { return systemColorWithName(@"controlColor"); } + (NSColor*) controlHighlightColor { return systemColorWithName(@"controlHighlightColor"); } + (NSColor*) controlLightHighlightColor { return systemColorWithName(@"controlLightHighlightColor"); } + (NSColor*) controlShadowColor { return systemColorWithName(@"controlShadowColor"); } + (NSColor*) controlDarkShadowColor { return systemColorWithName(@"controlDarkShadowColor"); } + (NSColor*) controlTextColor { return systemColorWithName(@"controlTextColor"); } + (NSColor*) disabledControlTextColor { return systemColorWithName(@"disabledControlTextColor"); } + (NSColor*) gridColor { return systemColorWithName(@"gridColor"); } + (NSColor*) headerColor { return systemColorWithName(@"headerColor"); } + (NSColor*) headerTextColor { return systemColorWithName(@"headerTextColor"); } + (NSColor*) highlightColor { return systemColorWithName(@"highlightColor"); } + (NSColor*) keyboardFocusIndicatorColor { return systemColorWithName(@"keyboardFocusIndicatorColor"); } + (NSColor*) knobColor { return systemColorWithName(@"knobColor"); } + (NSColor*) scrollBarColor { return systemColorWithName(@"scrollBarColor"); } + (NSColor*) secondarySelectedControlColor { return systemColorWithName(@"secondarySelectedControlColor"); } + (NSColor*) selectedControlColor { return systemColorWithName(@"selectedControlColor"); } + (NSColor*) selectedControlTextColor { return systemColorWithName(@"selectedControlTextColor"); } + (NSColor*) selectedKnobColor { return systemColorWithName(@"selectedKnobColor"); } + (NSColor*) selectedMenuItemColor { return systemColorWithName(@"selectedMenuItemColor"); } + (NSColor*) selectedMenuItemTextColor { return systemColorWithName(@"selectedMenuItemTextColor"); } + (NSColor*) selectedTextBackgroundColor { return systemColorWithName(@"selectedTextBackgroundColor"); } + (NSColor*) selectedTextColor { return systemColorWithName(@"selectedTextColor"); } + (NSColor*) shadowColor { return systemColorWithName(@"shadowColor"); } + (NSColor*) textBackgroundColor { return systemColorWithName(@"textBackgroundColor"); } + (NSColor*) textColor { return systemColorWithName(@"textColor"); } + (NSColor *)windowBackgroundColor { return systemColorWithName(@"windowBackgroundColor"); } + (NSColor*) windowFrameColor { return systemColorWithName(@"windowFrameColor"); } + (NSColor*) windowFrameTextColor { return systemColorWithName(@"windowFrameTextColor"); } + (NSArray*) controlAlternatingRowBackgroundColors { return [NSArray arrayWithObjects: systemColorWithName(@"rowBackgroundColor"), systemColorWithName(@"alternateRowBackgroundColor"), nil]; } //////////////////////////////////////////////////////////// // // Instance methods // - (id) copyWithZone: (NSZone*)aZone { if (NSShouldRetainWithZone(self, aZone)) { return RETAIN(self); } else { return NSCopyObject(self, 0, aZone); } } - (NSString*) description { [self subclassResponsibility: _cmd]; return nil; } // // Retrieving a Set of Components // - (void) getCyan: (float*)cyan magenta: (float*)magenta yellow: (float*)yellow black: (float*)black alpha: (float*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getCyan:magenta:yellow:black:alpha: on non-CMYK colour"]; } - (void) getHue: (float*)hue saturation: (float*)saturation brightness: (float*)brightness alpha: (float*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getHue:saturation:brightness:alpha: on non-RGB colour"]; } - (void) getRed: (float*)red green: (float*)green blue: (float*)blue alpha: (float*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getRed:green:blue:alpha: on non-RGB colour"]; } - (void) getWhite: (float*)white alpha: (float*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getWhite:alpha: on non-grayscale colour"]; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: NSColorClass] == NO) return NO; else { [self subclassResponsibility: _cmd]; return NO; } } // // Retrieving Individual Components // - (float) alphaComponent { return 1.0; } - (float) blackComponent { [NSException raise: NSInternalInconsistencyException format: @"Called blackComponent on non-CMYK colour"]; return 0.0; } - (float) blueComponent { [NSException raise: NSInternalInconsistencyException format: @"Called blueComponent on non-RGB colour"]; return 0.0; } - (float) brightnessComponent { [NSException raise: NSInternalInconsistencyException format: @"Called brightnessComponent on non-RGB colour"]; return 0.0; } - (NSString *) catalogNameComponent { [NSException raise: NSInternalInconsistencyException format: @"Called catalogNameComponent on colour with name"]; return nil; } - (NSString *) colorNameComponent { [NSException raise: NSInternalInconsistencyException format: @"Called colorNameComponent on colour with name"]; return nil; } - (float) cyanComponent { [NSException raise: NSInternalInconsistencyException format: @"Called cyanComponent on non-CMYK colour"]; return 0.0; } - (float) greenComponent { [NSException raise: NSInternalInconsistencyException format: @"Called greenComponent on non-RGB colour"]; return 0.0; } - (float) hueComponent { [NSException raise: NSInternalInconsistencyException format: @"Called hueComponent on non-RGB colour"]; return 0.0; } - (NSString *) localizedCatalogNameComponent { [NSException raise: NSInternalInconsistencyException format: @"Called localizedCatalogNameComponent on colour with name"]; return nil; } - (NSString *) localizedColorNameComponent { [NSException raise: NSInternalInconsistencyException format: @"Called localizedColorNameComponent on colour with name"]; return nil; } - (float) magentaComponent { [NSException raise: NSInternalInconsistencyException format: @"Called magentaComponent on non-CMYK colour"]; return 0.0; } - (float) redComponent { [NSException raise: NSInternalInconsistencyException format: @"Called redComponent on non-RGB colour"]; return 0.0; } - (float) saturationComponent { [NSException raise: NSInternalInconsistencyException format: @"Called saturationComponent on non-RGB colour"]; return 0.0; } - (float) whiteComponent { [NSException raise: NSInternalInconsistencyException format: @"Called whiteComponent on non-grayscale colour"]; return 0.0; } - (NSImage*) patternImage { [NSException raise: NSInternalInconsistencyException format: @"Called patternImage on non-pattern colour"]; return nil; } - (float) yellowComponent { [NSException raise: NSInternalInconsistencyException format: @"Called yellowComponent on non-CMYK colour"]; return 0.0; } // // Converting to Another Color Space // - (NSString *) colorSpaceName { [self subclassResponsibility: _cmd]; return nil; } - (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace { return [self colorUsingColorSpaceName: colorSpace device: nil]; } - (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace device: (NSDictionary *)deviceDescription { if (colorSpace == nil) { if (deviceDescription != nil) colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName]; if (colorSpace == nil) colorSpace = NSDeviceRGBColorSpace; } if ([colorSpace isEqualToString: [self colorSpaceName]]) { return self; } if ([colorSpace isEqualToString: NSNamedColorSpace]) { // FIXME: We cannot convert to named color space. return nil; } [self subclassResponsibility: _cmd]; return nil; } // // Changing the Color // - (NSColor*) blendedColorWithFraction: (float)fraction ofColor: (NSColor*)aColor { NSColor *myColor = [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace]; NSColor *other = [aColor colorUsingColorSpaceName: NSCalibratedRGBColorSpace]; float mr, mg, mb, ma, or, og, ob, oa, red, green, blue, alpha; if (fraction <= 0.0) { return self; } if (fraction >= 1.0) { return aColor; } if (myColor == nil || other == nil) { return nil; } [myColor getRed: &mr green: &mg blue: &mb alpha: &ma]; [other getRed: &or green: &og blue: &ob alpha: &oa]; red = fraction * or + (1 - fraction) * mr; green = fraction * og + (1 - fraction) * mg; blue = fraction * ob + (1 - fraction) * mb; alpha = fraction * oa + (1 - fraction) * ma; return [NSColorClass colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } - (NSColor*) colorWithAlphaComponent: (float)alpha { return self; } - (NSColor*) highlightWithLevel: (float)level { return [self blendedColorWithFraction: level ofColor: [NSColorClass highlightColor]]; } - (NSColor*) shadowWithLevel: (float)level { return [self blendedColorWithFraction: level ofColor: [NSColorClass shadowColor]]; } // // Copying and Pasting // - (void) writeToPasteboard: (NSPasteboard *)pasteBoard { // FIXME: We should better use the description NSData *d = [NSArchiver archivedDataWithRootObject: self]; if (d != nil) [pasteBoard setData: d forType: NSColorPboardType]; } // // Drawing // - (void) drawSwatchInRect: (NSRect)rect { [self set]; NSRectFill(rect); } - (void) set { // This is here to keep old code working [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] set]; } // // NSCoding protocol // - (Class) classForCoder { return NSColorClass; } - (void) encodeWithCoder: (NSCoder*)aCoder { [self subclassResponsibility: _cmd]; } - (id) initWithCoder: (NSCoder*)aDecoder { if ([aDecoder allowsKeyedCoding]) { int colorSpace = [aDecoder decodeIntForKey: @"NSColorSpace"]; DESTROY(self); if ((colorSpace == 1) || (colorSpace == 2)) { unsigned length; const uint8_t *data; float red = 0.0; float green = 0.0; float blue = 0.0; float alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSRGB"]) { data = [aDecoder decodeBytesForKey: @"NSRGB" returnedLength: &length]; str = [[NSString alloc] initWithCString: data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanFloat: &red]; [scanner scanFloat: &green]; [scanner scanFloat: &blue]; RELEASE(scanner); RELEASE(str); } if (colorSpace == 1) { self = [NSColor colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } else { self = [NSColor colorWithDeviceRed: red green: green blue: blue alpha: alpha]; } } else if ((colorSpace == 3) || (colorSpace == 4)) { unsigned length; const uint8_t *data; float white = 0.0; float alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSWhite"]) { data = [aDecoder decodeBytesForKey: @"NSWhite" returnedLength: &length]; str = [[NSString alloc] initWithCString: data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanFloat: &white]; RELEASE(scanner); RELEASE(str); } if (colorSpace == 3) { self = [NSColor colorWithCalibratedWhite: white alpha: alpha]; } else { self = [NSColor colorWithDeviceWhite: white alpha: alpha]; } } else if (colorSpace == 5) { unsigned length; const uint8_t *data; float cyan = 0.0; float yellow = 0.0; float magenta = 0.0; float black = 0.0; float alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSCYMK"]) { data = [aDecoder decodeBytesForKey: @"NSCYMK" returnedLength: &length]; str = [[NSString alloc] initWithCString: data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanFloat: &cyan]; [scanner scanFloat: &yellow]; [scanner scanFloat: &magenta]; [scanner scanFloat: &black]; RELEASE(scanner); RELEASE(str); } self = [NSColor colorWithDeviceCyan: cyan magenta: magenta yellow: yellow black: black alpha: alpha]; } else if (colorSpace == 6) { NSString *catalog = [aDecoder decodeObjectForKey: @"NSCatalogName"]; NSString *name = [aDecoder decodeObjectForKey: @"NSColorName"]; //NSColor *color = [aDecoder decodeObjectForKey: @"NSColor"]; self = [NSColor colorWithCatalogName: catalog colorName: name]; } else if (colorSpace == 10) { NSImage *image = [aDecoder decodeObjectForKey: @"NSImage"]; self = [NSColor colorWithPatternImage: image]; } return self; } else if ([aDecoder versionForClassName: @"NSColor"] < 3) { float red; float green; float blue; float cyan; float magenta; float yellow; float black; float hue; float saturation; float brightness; float alpha; float white; int active_component; int valid_components; NSString *colorspace_name; NSString *catalog_name; NSString *color_name; BOOL is_clear; DESTROY(self); // Version 1 [aDecoder decodeValueOfObjCType: @encode(float) at: &red]; [aDecoder decodeValueOfObjCType: @encode(float) at: &green]; [aDecoder decodeValueOfObjCType: @encode(float) at: &blue]; [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &is_clear]; // Version 2 [aDecoder decodeValueOfObjCType: @encode(id) at: &colorspace_name]; [aDecoder decodeValueOfObjCType: @encode(id) at: &catalog_name]; [aDecoder decodeValueOfObjCType: @encode(id) at: &color_name]; [aDecoder decodeValueOfObjCType: @encode(float) at: &cyan]; [aDecoder decodeValueOfObjCType: @encode(float) at: &magenta]; [aDecoder decodeValueOfObjCType: @encode(float) at: &yellow]; [aDecoder decodeValueOfObjCType: @encode(float) at: &black]; [aDecoder decodeValueOfObjCType: @encode(float) at: &hue]; [aDecoder decodeValueOfObjCType: @encode(float) at: &saturation]; [aDecoder decodeValueOfObjCType: @encode(float) at: &brightness]; [aDecoder decodeValueOfObjCType: @encode(float) at: &white]; [aDecoder decodeValueOfObjCType: @encode(int) at: &active_component]; [aDecoder decodeValueOfObjCType: @encode(int) at: &valid_components]; if ([colorspace_name isEqualToString: @"NSDeviceCMYKColorSpace"]) { self = [NSColorClass colorWithDeviceCyan: cyan magenta: magenta yellow: yellow black: black alpha: alpha]; } else if ([colorspace_name isEqualToString: @"NSDeviceWhiteColorSpace"]) { self = [NSColorClass colorWithDeviceWhite: white alpha: alpha]; } else if ([colorspace_name isEqualToString: @"NSCalibratedWhiteColorSpace"]) { self = [NSColorClass colorWithCalibratedWhite:white alpha: alpha]; } else if ([colorspace_name isEqualToString: @"NSDeviceRGBColorSpace"]) { self = [NSColorClass colorWithDeviceRed: red green: green blue: blue alpha: alpha]; } else if ([colorspace_name isEqualToString: @"NSCalibratedRGBColorSpace"]) { self = [NSColorClass colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } else if ([colorspace_name isEqualToString: @"NSNamedColorSpace"]) { self = [NSColorClass colorWithCatalogName: catalog_name colorName: color_name]; } return RETAIN(self); } else { NSString *csName = [aDecoder decodeObject]; RELEASE(self); if ([csName isEqualToString: @"NSDeviceCMYKColorSpace"]) { self = [GSDeviceCMYKColor alloc]; } else if ([csName isEqualToString: @"NSDeviceRGBColorSpace"]) { self = [GSDeviceRGBColor alloc]; } else if ([csName isEqualToString: @"NSDeviceWhiteColorSpace"]) { self = [GSDeviceWhiteColor alloc]; } else if ([csName isEqualToString: @"NSCalibratedWhiteColorSpace"]) { self = [GSCalibratedWhiteColor alloc]; } else if ([csName isEqualToString: @"NSCalibratedRGBColorSpace"]) { self = [GSCalibratedRGBColor alloc]; } else if ([csName isEqualToString: @"NSNamedColorSpace"]) { self = [GSNamedColor alloc]; } else { NSLog(@"Unknown colorspace name in decoded color"); return nil; } return [self initWithCoder: aDecoder]; } } @end // // Private methods // @implementation NSColor (GNUstepPrivate) + (NSColor*) colorFromString: (NSString*)str { if ([str hasPrefix: @"{"]) { NSDictionary *dict; NSString *space; float alpha; dict = [str propertyList]; if (dict == nil) return nil; if ((space = [dict objectForKey: @"ColorSpace"]) == nil) return nil; str = [dict objectForKey: @"Alpha"]; if (str == nil || [str isEqualToString: @""]) { alpha = 1.0; } else { alpha = [str floatValue]; } if ([space isEqual: NSCalibratedWhiteColorSpace]) { float white = [[dict objectForKey: @"W"] floatValue]; return [self colorWithCalibratedWhite: white alpha: alpha]; } if ([space isEqual: NSCalibratedBlackColorSpace]) { float white = [[dict objectForKey: @"W"] floatValue]; return [self colorWithCalibratedWhite: white alpha: alpha]; } if ([space isEqual: NSCalibratedRGBColorSpace]) { if ([dict objectForKey: @"H"] != nil) { float hue = [[dict objectForKey: @"H"] floatValue]; float saturation = [[dict objectForKey: @"S"] floatValue]; float brightness = [[dict objectForKey: @"B"] floatValue]; return [self colorWithCalibratedHue: hue saturation: saturation brightness: brightness alpha: alpha]; } else { float red = [[dict objectForKey: @"R"] floatValue]; float green = [[dict objectForKey: @"G"] floatValue]; float blue = [[dict objectForKey: @"B"] floatValue]; return [self colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } } if ([space isEqual: NSDeviceCMYKColorSpace]) { float cyan = [[dict objectForKey: @"C"] floatValue]; float magenta = [[dict objectForKey: @"M"] floatValue]; float yellow = [[dict objectForKey: @"Y"] floatValue]; float black = [[dict objectForKey: @"B"] floatValue]; return [self colorWithDeviceCyan: cyan magenta: magenta yellow: yellow black: black alpha: alpha]; } if ([space isEqual: NSNamedColorSpace]) { NSString *cat = [dict objectForKey: @"Catalog"]; NSString *col = [dict objectForKey: @"Color"]; return [self colorWithCatalogName: cat colorName: col]; } } else if (str != nil) { float r, g, b; NSScanner *scanner = [[NSScanner alloc] initWithString: str]; if ([scanner scanFloat: &r] && [scanner scanFloat: &g] && [scanner scanFloat: &b] && [scanner isAtEnd]) { RELEASE(scanner); return [self colorWithCalibratedRed: r green: g blue: b alpha: 1.0]; } RELEASE(scanner); } return nil; } /* * Go through all the names of system colors - for each color where * there is a value in the defaults database, see if the current * value of the color differs from the old one. * Where there is a difference, update the color strings dictionary * and update the system colors list to contain the new color. * Finally, issue a notification if appropriate. */ + (void) defaultsDidChange: (NSNotification*)notification { NSUserDefaults *defs; NSEnumerator *enumerator; NSString *key; BOOL didChange = NO; defs = [NSUserDefaults standardUserDefaults]; enumerator = [colorStrings keyEnumerator]; while ((key = [enumerator nextObject]) != nil) { NSString *def = [[defs objectForKey: key] description]; if (def != nil) { NSColor *old = [systemColors colorWithKey: key]; NSColor *color = [NSColor colorFromString: def]; if (color == nil) { NSLog(@"System color '%@' has bad string rep - '%@'\n", key, def); } else if ([color isEqual: old] == NO) { didChange = YES; [colorStrings setObject: def forKey: key]; [systemColors setColor: color forKey: key]; // Refresh the cache for this named colour [[systemDict objectForKey: key] recache]; } } } if (didChange) { [[NSNotificationCenter defaultCenter] postNotificationName: NSSystemColorsDidChangeNotification object: nil]; } } @end // Named colours @implementation GSNamedColor - (NSColor*) initWithCatalogName: (NSString *)listName colorName: (NSString *)colorName { ASSIGN(_catalog_name, listName); ASSIGN(_color_name, colorName); return self; } - (void) dealloc { RELEASE(_catalog_name); RELEASE(_color_name); RELEASE(_cached_name_space); RELEASE(_cached_color); [super dealloc]; } - (NSString *)colorSpaceName { return NSNamedColorSpace; } - (id) copyWithZone: (NSZone*)aZone { if (NSShouldRetainWithZone(self, aZone)) { return RETAIN(self); } else { GSNamedColor *aCopy = NSCopyObject(self, 0, aZone); aCopy->_catalog_name = [_catalog_name copyWithZone: aZone]; aCopy->_color_name = [_color_name copyWithZone: aZone]; aCopy->_cached_name_space = nil; aCopy->_cached_color = nil; return aCopy; } } - (NSString*) description { NSMutableString *desc; /* * We encode information in a dictionary * format with meaningful keys. */ desc = [NSMutableString stringWithCapacity: 128]; [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]]; [desc appendFormat: @" Catalog = \"%@\";", _catalog_name]; [desc appendFormat: @" Color = \"%@\"; }", _color_name]; return desc; } - (NSString *) catalogNameComponent { return _catalog_name; } - (NSString *) colorNameComponent { return _color_name; } - (NSString *) localizedCatalogNameComponent { // FIXME: How do we localize? return NSLocalizedString(_catalog_name, @"colour list name"); } - (NSString *) localizedColorNameComponent { // FIXME: How do we localize? return NSLocalizedString(_color_name, @"colour name"); } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO) return NO; else { GSNamedColor *col = (GSNamedColor*)other; if (![[col catalogNameComponent] isEqualToString: _catalog_name]) return NO; if (![[col colorNameComponent] isEqualToString: _color_name]) return NO; return YES; } return NO; } - (NSColor *)colorUsingColorSpaceName: (NSString *)colorSpace device: (NSDictionary *)deviceDescription { NSColorList *list; NSColor *real; if (colorSpace == nil) { if (deviceDescription != nil) colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName]; // FIXME: If the deviceDescription is nil, we should get it from the // current view or printer if (colorSpace == nil) colorSpace = NSCalibratedRGBColorSpace; } if ([colorSpace isEqualToString: [self colorSpaceName]]) { return self; } // Is there a cache hit? // FIXME How would we detect that the cache has become invalid by a // change to the colour list? if ([colorSpace isEqualToString: _cached_name_space]) { return _cached_color; } list = [NSColorList colorListNamed: _catalog_name]; real = [list colorWithKey: _color_name]; ASSIGN(_cached_color, [real colorUsingColorSpaceName: colorSpace device: deviceDescription]); ASSIGN(_cached_name_space, colorSpace); return _cached_color; } - (void) recache { DESTROY(_cached_name_space); DESTROY(_cached_color); } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { [aCoder encodeInt: 6 forKey: @"NSColorSpace"]; [aCoder encodeObject: _catalog_name forKey: @"NSCatalogName"]; [aCoder encodeObject: _color_name forKey: @"NSColorName"]; } else { [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeObject: _catalog_name]; [aCoder encodeObject: _color_name]; } } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(id) at: &_catalog_name]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_color_name]; return self; } @end // Grayscale colours @implementation GSWhiteColor - (float) alphaComponent { return _alpha_component; } - (float) whiteComponent { return _white_component; } - (NSString*) description { NSMutableString *desc; /* * We encode information in a dictionary * format with meaningful keys. */ desc = [NSMutableString stringWithCapacity: 128]; [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]]; [desc appendFormat: @" W = \"%f\";", _white_component]; [desc appendFormat: @" Alpha = \"%f\"; }", _alpha_component]; return desc; } - (void) getWhite: (float*)white alpha: (float*)alpha { // Only set what is wanted if (white) *white = _white_component; if (alpha) *alpha = _alpha_component; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO) return NO; else { GSWhiteColor *col = (GSWhiteColor*)other; if (col->_white_component != _white_component || col->_alpha_component != _alpha_component) return NO; return YES; } return NO; } - (NSColor*) colorWithAlphaComponent: (float)alpha { GSWhiteColor *aCopy; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; if (alpha == _alpha_component) return self; aCopy = (GSWhiteColor*)NSCopyObject(self, 0, NSDefaultMallocZone()); if (aCopy) { aCopy->_alpha_component = alpha; } return aCopy; } - (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace device: (NSDictionary *)deviceDescription { if (colorSpace == nil) { if (deviceDescription != nil) colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName]; if (colorSpace == nil) colorSpace = NSCalibratedRGBColorSpace; } if ([colorSpace isEqualToString: [self colorSpaceName]]) { return self; } if ([colorSpace isEqualToString: NSNamedColorSpace]) { // FIXME: We cannot convert to named color space. return nil; } if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace] || [colorSpace isEqualToString: NSDeviceBlackColorSpace]) { return [NSColor colorWithDeviceWhite: _white_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace] || [colorSpace isEqualToString: NSCalibratedBlackColorSpace]) { return [NSColor colorWithCalibratedWhite: _white_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace]) { return [NSColor colorWithCalibratedRed: _white_component green: _white_component blue: _white_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceRGBColorSpace]) { return [NSColor colorWithDeviceRed: _white_component green: _white_component blue: _white_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceCMYKColorSpace]) { return [NSColor colorWithDeviceCyan: 0.0 magenta: 0.0 yellow: 0.0 black: 1.0 - _white_component alpha: _alpha_component]; } return nil; } - (void) set { // This should be in GSDeviceWhiteColor, but is here to keep old code working NSDebugLLog(@"NSColor", @"Gray %f\n", _white_component); PSsetgray(_white_component); // Should we check the ignore flag here? PSsetalpha(_alpha_component); } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { NSString *str; if ([[self colorSpaceName] isEqualToString: NSCalibratedWhiteColorSpace]) { [aCoder encodeInt: 3 forKey: @"NSColorSpace"]; } else { [aCoder encodeInt: 4 forKey: @"NSColorSpace"]; } // FIXME: Missing handling of alpha value str = [[NSString alloc] initWithFormat: @"%f", _white_component]; [aCoder encodeBytes: [str cString] length: [str cStringLength] forKey: @"NSWhite"]; RELEASE(str); } else { [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &_white_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_alpha_component]; } } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(float) at: &_white_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_alpha_component]; return self; } @end @implementation GSDeviceWhiteColor - (NSString *)colorSpaceName { return NSDeviceWhiteColorSpace; } - (NSColor*) initWithDeviceWhite: (float)white alpha: (float)alpha { if (white < 0.0) white = 0.0; else if (white > 1.0) white = 1.0; _white_component = white; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } @end @implementation GSCalibratedWhiteColor - (NSString *)colorSpaceName { return NSCalibratedWhiteColorSpace; } - (NSColor*) initWithCalibratedWhite: (float)white alpha: (float)alpha { if (white < 0.0) white = 0.0; else if (white > 1.0) white = 1.0; _white_component = white; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } @end @implementation GSDeviceCMYKColor - (NSColor*) initWithDeviceCyan: (float)cyan magenta: (float)magenta yellow: (float)yellow black: (float)black alpha: (float)alpha { if (cyan < 0.0) cyan = 0.0; else if (cyan > 1.0) cyan = 1.0; _cyan_component = cyan; if (magenta < 0.0) magenta = 0.0; else if (magenta > 1.0) magenta = 1.0; _magenta_component = magenta; if (yellow < 0.0) yellow = 0.0; else if (yellow > 1.0) yellow = 1.0; _yellow_component = yellow; if (black < 0.0) black = 0.0; else if (black > 1.0) black = 1.0; _black_component = black; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } - (NSString *)colorSpaceName { return NSDeviceCMYKColorSpace; } - (float) alphaComponent { return _alpha_component; } - (float) blackComponent { return _black_component; } - (float) cyanComponent { return _cyan_component; } - (float) magentaComponent { return _magenta_component; } - (float) yellowComponent { return _yellow_component; } - (NSString*) description { NSMutableString *desc; /* * We encode information in a dictionary * format with meaningful keys. */ desc = [NSMutableString stringWithCapacity: 128]; [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]]; [desc appendFormat: @" C = \"%f\";", _cyan_component]; [desc appendFormat: @" M = \"%f\";", _magenta_component]; [desc appendFormat: @" Y = \"%f\";", _yellow_component]; [desc appendFormat: @" K = \"%f\";", _black_component]; [desc appendFormat: @" Alpha = \"%f\"; }", _alpha_component]; return desc; } - (void) getCyan: (float*)cyan magenta: (float*)magenta yellow: (float*)yellow black: (float*)black alpha: (float*)alpha { // Only set what is wanted if (cyan) *cyan = _cyan_component; if (magenta) *magenta = _magenta_component; if (yellow) *yellow = _yellow_component; if (black) *black = _black_component; if (alpha) *alpha = _alpha_component; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO) return NO; else { GSDeviceCMYKColor *col = (GSDeviceCMYKColor*)other; if (col->_cyan_component != _cyan_component || col->_magenta_component != _magenta_component || col->_yellow_component != _yellow_component || col->_black_component != _black_component || col->_alpha_component != _alpha_component) return NO; return YES; } return NO; } - (NSColor*) colorWithAlphaComponent: (float)alpha { GSDeviceCMYKColor *aCopy; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; if (alpha == _alpha_component) return self; aCopy = (GSDeviceCMYKColor*)NSCopyObject(self, 0, NSDefaultMallocZone()); if (aCopy) { aCopy->_alpha_component = alpha; } return aCopy; } - (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace device: (NSDictionary *)deviceDescription { if (colorSpace == nil) { if (deviceDescription != nil) colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName]; if (colorSpace == nil) colorSpace = NSCalibratedRGBColorSpace; } if ([colorSpace isEqualToString: [self colorSpaceName]]) { return self; } if ([colorSpace isEqualToString: NSNamedColorSpace]) { // FIXME: We cannot convert to named color space. return nil; } if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace]) { double c = _cyan_component; double m = _magenta_component; double y = _yellow_component; double white = 1 - _black_component; return [NSColor colorWithCalibratedRed: (c > white ? 0 : white - c) green: (m > white ? 0 : white - m) blue: (y > white ? 0 : white - y) alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceRGBColorSpace]) { double c = _cyan_component; double m = _magenta_component; double y = _yellow_component; double white = 1 - _black_component; return [NSColor colorWithDeviceRed: (c > white ? 0 : white - c) green: (m > white ? 0 : white - m) blue: (y > white ? 0 : white - y) alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace] || [colorSpace isEqualToString: NSCalibratedBlackColorSpace]) { return [NSColor colorWithCalibratedWhite: 1 - _black_component - (_cyan_component + _magenta_component + _yellow_component)/3 alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace] || [colorSpace isEqualToString: NSDeviceBlackColorSpace]) { return [NSColor colorWithDeviceWhite: 1 - _black_component - (_cyan_component + _magenta_component + _yellow_component)/3 alpha: _alpha_component]; } return nil; } - (void) set { NSDebugLLog(@"NSColor", @"CMYK %f %f %f %f\n", _cyan_component, _magenta_component, _yellow_component, _black_component); PSsetcmykcolor(_cyan_component, _magenta_component, _yellow_component, _black_component); // Should we check the ignore flag here? PSsetalpha(_alpha_component); } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { NSString *str; // FIXME: Missing handling of alpha value [aCoder encodeInt: 5 forKey: @"NSColorSpace"]; str = [[NSString alloc] initWithFormat: @"%f %f %f %f", _cyan_component, _magenta_component, _yellow_component, _black_component]; [aCoder encodeBytes: [str cString] length: [str cStringLength] forKey: @"NSCYMK"]; RELEASE(str); } else { [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &_cyan_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_magenta_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_yellow_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_black_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_alpha_component]; } } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(float) at: &_cyan_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_magenta_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_yellow_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_black_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_alpha_component]; return self; } @end // RGB/HSB colours @implementation GSRGBColor - (float) alphaComponent { return _alpha_component; } - (float) redComponent { return _red_component; } - (float) greenComponent { return _green_component; } - (float) blueComponent { return _blue_component; } - (float) hueComponent { return _hue_component; } - (float) saturationComponent { return _saturation_component; } - (float) brightnessComponent { return _brightness_component; } - (void) getHue: (float*)hue saturation: (float*)saturation brightness: (float*)brightness alpha: (float*)alpha { // Only set what is wanted if (hue) *hue = _hue_component; if (saturation) *saturation = _saturation_component; if (brightness) *brightness = _brightness_component; if (alpha) *alpha = _alpha_component; } - (void) getRed: (float*)red green: (float*)green blue: (float*)blue alpha: (float*)alpha { // Only set what is wanted if (red) *red = _red_component; if (green) *green = _green_component; if (blue) *blue = _blue_component; if (alpha) *alpha = _alpha_component; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO) return NO; else { GSRGBColor *col = (GSRGBColor*)other; if (col->_red_component != _red_component || col->_green_component != _green_component || col->_blue_component != _blue_component) return NO; return YES; } return NO; } - (NSColor*) colorWithAlphaComponent: (float)alpha { GSRGBColor *aCopy; if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; if (alpha == _alpha_component) return self; aCopy = (GSRGBColor*)NSCopyObject(self, 0, NSDefaultMallocZone()); if (aCopy) { aCopy->_alpha_component = alpha; } return aCopy; } - (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace device: (NSDictionary *)deviceDescription { if (colorSpace == nil) { if (deviceDescription != nil) colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName]; if (colorSpace == nil) colorSpace = NSCalibratedRGBColorSpace; } if ([colorSpace isEqualToString: [self colorSpaceName]]) { return self; } if ([colorSpace isEqualToString: NSNamedColorSpace]) { // FIXME: We cannot convert to named color space. return nil; } if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace]) { return [NSColor colorWithCalibratedRed: _red_component green: _green_component blue: _blue_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceRGBColorSpace]) { return [NSColor colorWithDeviceRed: _red_component green: _green_component blue: _blue_component alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace] || [colorSpace isEqualToString: NSCalibratedBlackColorSpace]) { return [NSColor colorWithCalibratedWhite: (_red_component + _green_component + _blue_component)/3 alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace] || [colorSpace isEqualToString: NSDeviceBlackColorSpace]) { return [NSColor colorWithDeviceWhite: (_red_component + _green_component + _blue_component)/3 alpha: _alpha_component]; } if ([colorSpace isEqualToString: NSDeviceCMYKColorSpace]) { return [NSColor colorWithDeviceCyan: 1 - _red_component magenta: 1 - _green_component yellow: 1 - _blue_component black: 0.0 alpha: _alpha_component]; } return nil; } - (NSString*) description { NSMutableString *desc; /* * For a simple RGB color without alpha, we use a shorthand description * consisting of the three component values in a quoted string. */ if (_alpha_component == 1.0) return [NSString stringWithFormat: @"%f %f %f", _red_component, _green_component, _blue_component]; /* * For more complex color values - we encode information in a dictionary * format with meaningful keys. */ desc = [NSMutableString stringWithCapacity: 128]; [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]]; [desc appendFormat: @" R = \"%f\";", _red_component]; [desc appendFormat: @" G = \"%f\";", _green_component]; [desc appendFormat: @" B = \"%f\";", _blue_component]; [desc appendFormat: @" Alpha = \"%f\"; }", _alpha_component]; return desc; } - (void) set { // This should only be in GSDeviceRGBColor, but is here to keep old code working. NSDebugLLog(@"NSColor", @"RGB %f %f %f\n", _red_component, _green_component, _blue_component); PSsetrgbcolor(_red_component, _green_component, _blue_component); // Should we check the ignore flag here? PSsetalpha(_alpha_component); } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { NSString *str; if ([[self colorSpaceName] isEqualToString: NSCalibratedRGBColorSpace]) { [aCoder encodeInt: 1 forKey: @"NSColorSpace"]; } else { [aCoder encodeInt: 2 forKey: @"NSColorSpace"]; } // FIXME: Missing handling of alpha value str = [[NSString alloc] initWithFormat: @"%f %f %f", _red_component, _green_component, _blue_component]; [aCoder encodeBytes: [str cString] length: [str cStringLength] forKey: @"NSRGB"]; RELEASE(str); } else { [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &_red_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_green_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_blue_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_hue_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_saturation_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_brightness_component]; [aCoder encodeValueOfObjCType: @encode(float) at: &_alpha_component]; } } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(float) at: &_red_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_green_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_blue_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_hue_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_saturation_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_brightness_component]; [aDecoder decodeValueOfObjCType: @encode(float) at: &_alpha_component]; return self; } @end @implementation GSDeviceRGBColor - (NSString *)colorSpaceName { return NSDeviceRGBColorSpace; } - (NSColor*) initWithDeviceRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha { if (red < 0.0) red = 0.0; else if (red > 1.0) red = 1.0; _red_component = red; if (green < 0.0) green = 0.0; else if (green > 1.0) green = 1.0; _green_component = green; if (blue < 0.0) blue = 0.0; else if (blue > 1.0) blue = 1.0; _blue_component = blue; { float r = _red_component; float g = _green_component; float b = _blue_component; if (r == g && r == b) { _hue_component = 0; _saturation_component = 0; _brightness_component = r; } else { double H; double V; double Temp; double diff; V = (r > g ? r : g); V = (b > V ? b : V); Temp = (r < g ? r : g); Temp = (b < Temp ? b : Temp); diff = V - Temp; if (V == r) { H = (g - b)/diff; } else if (V == g) { H = (b - r)/diff + 2; } else { H = (r - g)/diff + 4; } if (H < 0) { H += 6; } _hue_component = H/6; _saturation_component = diff/V; _brightness_component = V; } } if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } - (NSColor*) initWithDeviceHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha; { if (hue < 0.0) hue = 0.0; else if (hue > 1.0) hue = 1.0; _hue_component = hue; if (saturation < 0.0) saturation = 0.0; else if (saturation > 1.0) saturation = 1.0; _saturation_component = saturation; if (brightness < 0.0) brightness = 0.0; else if (brightness > 1.0) brightness = 1.0; _brightness_component = brightness; { int I = (int)(hue * 6); double V = brightness; double S = saturation; double F = (hue * 6) - I; double M = V * (1 - S); double N = V * (1 - S * F); double K = M - N + V; double R, G, B; switch (I) { default: R = V; G = K; B = M; break; case 1: R = N; G = V; B = M; break; case 2: R = M; G = V; B = K; break; case 3: R = M; G = N; B = V; break; case 4: R = K; G = M; B = V; break; case 5: R = V; G = M; B = N; break; } _red_component = (float)R; _green_component = (float)G; _blue_component = (float)B; } if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } @end @implementation GSCalibratedRGBColor - (NSString *)colorSpaceName { return NSCalibratedRGBColorSpace; } - (NSColor*) initWithCalibratedRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha { if (red < 0.0) red = 0.0; else if (red > 1.0) red = 1.0; _red_component = red; if (green < 0.0) green = 0.0; else if (green > 1.0) green = 1.0; _green_component = green; if (blue < 0.0) blue = 0.0; else if (blue > 1.0) blue = 1.0; _blue_component = blue; { float r = _red_component; float g = _green_component; float b = _blue_component; if (r == g && r == b) { _hue_component = 0; _saturation_component = 0; _brightness_component = r; } else { double H; double V; double Temp; double diff; V = (r > g ? r : g); V = (b > V ? b : V); Temp = (r < g ? r : g); Temp = (b < Temp ? b : Temp); diff = V - Temp; if (V == r) { H = (g - b)/diff; } else if (V == g) { H = (b - r)/diff + 2; } else { H = (r - g)/diff + 4; } if (H < 0) { H += 6; } _hue_component = H/6; _saturation_component = diff/V; _brightness_component = V; } } if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } - (NSColor*) initWithCalibratedHue: (float)hue saturation: (float)saturation brightness: (float)brightness alpha: (float)alpha; { if (hue < 0.0) hue = 0.0; else if (hue > 1.0) hue = 1.0; _hue_component = hue; if (saturation < 0.0) saturation = 0.0; else if (saturation > 1.0) saturation = 1.0; _saturation_component = saturation; if (brightness < 0.0) brightness = 0.0; else if (brightness > 1.0) brightness = 1.0; _brightness_component = brightness; { int I = (int)(hue * 6); double V = brightness; double S = saturation; double F = (hue * 6) - I; double M = V * (1 - S); double N = V * (1 - S * F); double K = M - N + V; double R, G, B; switch (I) { default: R = V; G = K; B = M; break; case 1: R = N; G = V; B = M; break; case 2: R = M; G = V; B = K; break; case 3: R = M; G = N; B = V; break; case 4: R = K; G = M; B = V; break; case 5: R = V; G = M; B = N; break; } _red_component = (float)R; _green_component = (float)G; _blue_component = (float)B; } if (alpha < 0.0) alpha = 0.0; else if (alpha > 1.0) alpha = 1.0; _alpha_component = alpha; return self; } @end @implementation GSPatternColor - (NSColor*) initWithPatternImage: (NSImage*) pattern; { ASSIGN(_pattern, pattern); return self; } - (void) dealloc { RELEASE(_pattern); [super dealloc]; } - (NSString *)colorSpaceName { return NSPatternColorSpace; } - (NSImage*) patternImage { return _pattern; } - (NSString*) description { NSMutableString *desc; /* * We encode information in a dictionary * format with meaningful keys. */ desc = [NSMutableString stringWithCapacity: 128]; [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]]; [desc appendFormat: @" Pattern = \"%@\"; }", [_pattern description]]; return desc; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO) return NO; else { GSPatternColor *col = (GSPatternColor*)other; if ([col->_pattern isEqual: _pattern] == NO) return NO; return YES; } return NO; } - (id) copyWithZone: (NSZone*)aZone { if (NSShouldRetainWithZone(self, aZone)) { return RETAIN(self); } else { GSPatternColor *aCopy = NSCopyObject(self, 0, aZone); aCopy->_pattern = [_pattern copyWithZone: aZone]; return aCopy; } } - (void) set { // FIXME: We need another PS command for this } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { [aCoder encodeInt: 10 forKey: @"NSColorSpace"]; [aCoder encodeObject: _pattern forKey: @"NSImage"]; } else { [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeObject: _pattern]; } } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(id) at: &_pattern]; return self; } @end // // Implementation of the NSCoder additions // @implementation NSCoder (NSCoderAdditions) // // Converting an archived NXColor to an NSColor // - (NSColor*) decodeNXColor { // FIXME return nil; } @end