/** 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 Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, see or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #import "config.h" #import #import #import #import #import #import #import #import #import #import #import "AppKit/NSBezierPath.h" #import "AppKit/NSColor.h" #import "AppKit/NSColorList.h" #import "AppKit/NSColorSpace.h" #import "AppKit/NSPasteboard.h" #import "AppKit/NSView.h" #import "AppKit/NSImage.h" #import "AppKit/NSGraphics.h" #import "AppKit/PSOperators.h" #import "GNUstepGUI/GSTheme.h" #import "GSGuiPrivate.h" static Class NSColorClass; /* This interface must be provided in NSColorList to let us manage * system colors. */ @interface NSColorList (GNUstepPrivate) + (void) _setDefaultSystemColorList: (NSColorList*)aList; + (void) _setThemeSystemColorList: (NSColorList*)aList; @end @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 { CGFloat _white_component; CGFloat _alpha_component; } @end @interface GSDeviceWhiteColor : GSWhiteColor - (NSColor*) initWithDeviceWhite: (CGFloat)white alpha: (CGFloat)alpha; @end @interface GSCalibratedWhiteColor : GSWhiteColor - (NSColor*) initWithCalibratedWhite: (CGFloat)white alpha: (CGFloat)alpha; @end @interface GSDeviceCMYKColor : NSColor { CGFloat _cyan_component; CGFloat _magenta_component; CGFloat _yellow_component; CGFloat _black_component; CGFloat _alpha_component; } - (NSColor*) initWithDeviceCyan: (CGFloat)cyan magenta: (CGFloat)magenta yellow: (CGFloat)yellow black: (CGFloat)black alpha: (CGFloat)alpha; @end @interface GSRGBColor : NSColor { CGFloat _red_component; CGFloat _green_component; CGFloat _blue_component; CGFloat _hue_component; CGFloat _saturation_component; CGFloat _brightness_component; CGFloat _alpha_component; } @end @interface GSDeviceRGBColor : GSRGBColor - (NSColor*) initWithDeviceRed: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)alpha; - (NSColor*) initWithDeviceHue: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)alpha; @end @interface GSCalibratedRGBColor : GSRGBColor - (NSColor*) initWithCalibratedRed: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)alpha; - (NSColor*) initWithCalibratedHue: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)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; + (void) themeDidActivate: (NSNotification*)notification; @end // Class variables static BOOL gnustep_gui_ignores_alpha = YES; static NSColorList *systemColors = nil; static NSColorList *defaultSystemColors = 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: @"%g %g %g", (double)NSWhite, (double)NSWhite, (double)NSWhite]; lightGray = [NSString stringWithFormat: @"%g %g %g", (double)NSLightGray, (double)NSLightGray, (double)NSLightGray]; gray = [NSString stringWithFormat: @"%g %g %g", (double)NSGray, (double)NSGray, (double)NSGray]; darkGray = [NSString stringWithFormat: @"%g %g %g", (double)NSDarkGray, (double)NSDarkGray, (double)NSDarkGray]; black = [NSString stringWithFormat: @"%g %g %g", (double)NSBlack, (double)NSBlack, (double)NSBlack]; colorStrings = [[NSMutableDictionary alloc] initWithObjectsAndKeys: black, @"alternateSelectedControlColor", white, @"alternateSelectedControlTextColor", lightGray, @"controlBackgroundColor", lightGray, @"controlColor", black, @"controlDarkShadowColor", lightGray, @"controlHighlightColor", white, @"controlLightHighlightColor", darkGray, @"controlShadowColor", black, @"controlTextColor", darkGray, @"disabledControlTextColor", gray, @"gridColor", lightGray, @"headerColor", black, @"headerTextColor", white, @"highlightColor", black, @"keyboardFocusIndicatorColor", lightGray, @"knobColor", black, @"labelColor", black, @"quaternaryLabelColor", gray, @"scrollBarColor", black, @"secondaryLabelColor", lightGray, @"secondarySelectedControlColor", white, @"selectedControlColor", black, @"selectedControlTextColor", lightGray, @"selectedKnobColor", white, @"selectedMenuItemColor", black, @"selectedMenuItemTextColor", lightGray, @"selectedTextBackgroundColor", black, @"selectedTextColor", black, @"shadowColor", black, @"tertiaryLabelColor", white, @"textBackgroundColor", black, @"textColor", lightGray, @"windowBackgroundColor", black, @"windowFrameColor", white, @"windowFrameTextColor", white, @"rowBackgroundColor", lightGray, @"alternateRowBackgroundColor", nil]; systemColors = RETAIN([NSColorList colorListNamed: @"System"]); defaultSystemColors = [[NSColorList alloc] initWithName: @"System"]; [NSColorList _setDefaultSystemColorList: defaultSystemColors]; if (systemColors == nil) { ASSIGN(systemColors, defaultSystemColors); } { NSEnumerator *enumerator; NSString *key; // Set up default system colors enumerator = [colorStrings keyEnumerator]; while ((key = (NSString *)[enumerator nextObject])) { NSColor *color; if ((color = [systemColors colorWithKey: key]) == nil) { NSString *aColorString; aColorString = [colorStrings objectForKey: key]; color = [NSColorClass colorFromString: aColorString]; NSCAssert1(color, @"couldn't get default system color %@", key); [systemColors setColor: color forKey: key]; } if (defaultSystemColors != systemColors) { [defaultSystemColors setColor: color forKey: key]; } } } 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; } /** *

TODO NSColor description

* */ @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]; // watch for themes which may provide new system color lists [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(themeDidActivate:) name: GSThemeDidActivateNotification object: nil]; } } /**

Creates and returns a new NSColor in a NSCalibratedRGBColorSpace space name, with hue, saturation, brightness and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithCalibratedHue: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)alpha { id color; color = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithCalibratedHue: hue saturation: saturation brightness: brightness alpha: alpha]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSCalibratedRGBColorSpace space name, with red, green, blue and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithCalibratedRed: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)alpha { id color; color = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithCalibratedRed: red green: green blue: blue alpha: alpha]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSCalibratedWhiteColorSpace space name, with red, green, blue and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithCalibratedWhite: (CGFloat)white alpha: (CGFloat)alpha { id color; color = [GSCalibratedWhiteColor allocWithZone: NSDefaultMallocZone()] ; color = [color initWithCalibratedWhite: white alpha: alpha]; return AUTORELEASE(color); } /** *

TODO

*/ + (NSColor*) colorWithCatalogName: (NSString *)listName colorName: (NSString *)colorName { id color; color = [GSNamedColor allocWithZone: NSDefaultMallocZone()] ; color = [color initWithCatalogName: listName colorName: colorName]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space name, with cyan, magenta, yellow, black and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithDeviceCyan: (CGFloat)cyan magenta: (CGFloat)magenta yellow: (CGFloat)yellow black: (CGFloat)black alpha: (CGFloat)alpha { id color; color = [GSDeviceCMYKColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithDeviceCyan: cyan magenta: magenta yellow: yellow black: black alpha: alpha]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space name, with hue, saturation, brightness and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithDeviceHue: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)alpha { id color; color = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithDeviceHue: hue saturation: saturation brightness: brightness alpha: alpha]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space name, with red, green, blue and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithDeviceRed: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)alpha { id color; color = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithDeviceRed: red green: green blue: blue alpha: alpha]; return AUTORELEASE(color); } /**

Creates and returns a new NSColor in a NSDeviceWhiteColorSpace space name, with red, green, blue and alpha as specified. Valid values are the range 0.0 to 1.0. Out of range values will be clipped.

*/ + (NSColor*) colorWithDeviceWhite: (CGFloat)white alpha: (CGFloat)alpha { id color; color = [GSDeviceWhiteColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithDeviceWhite: white alpha: alpha]; return AUTORELEASE(color); } + (NSColor*) colorForControlTint: (NSControlTint)controlTint { switch (controlTint) { default: case NSDefaultControlTint: return [self colorForControlTint: [self currentControlTint]]; case NSGraphiteControlTint: // FIXME case NSClearControlTint: // FIXME case NSBlueControlTint: return [NSColor blueColor]; } } + (NSControlTint) currentControlTint { // FIXME: should be made a system setting return NSBlueControlTint; } + (NSColor*) colorWithPatternImage: (NSImage*)image { id color; color = [GSPatternColor allocWithZone: NSDefaultMallocZone()]; color = [color initWithPatternImage: image]; return AUTORELEASE(color); } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as NSBlack and 1.0 respectively.

See Also : +colorWithCalibratedWhite:alpha:

*/ + (NSColor*) blackColor { return [self colorWithCalibratedWhite: NSBlack alpha: 1.0]; } /**

Returns an NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 0.0, 0.0, 1.0 and 1.0 respectively.

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) blueColor { return [self colorWithCalibratedRed: 0.0 green: 0.0 blue: 1.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 0.6, 0.4, 0.2 and 1.0 respectively.

See Also: +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) brownColor { return [self colorWithCalibratedRed: 0.6 green: 0.4 blue: 0.2 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as 0.0 and 1.0 respectively.

See Also : +colorWithCalibratedWhite:alpha:

*/ + (NSColor*) clearColor { return [self colorWithCalibratedWhite: 0.0 alpha: 0.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 0.0, 1.0, 1.0 and 1.0 respectively.

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) cyanColor { return [self colorWithCalibratedRed: 0.0 green: 1.0 blue: 1.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as NSDarkGray and 1.0 respectively.

See Also : +colorWithCalibratedWhite:alpha:

*/ + (NSColor*) darkGrayColor { return [self colorWithCalibratedWhite: NSDarkGray alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as NSGray and 1.0 respectively.

See Also: +colorWithCalibratedWhite:alpha:

*/ + (NSColor*) grayColor { return [self colorWithCalibratedWhite: NSGray alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 0.0, 1.0, 0.0 and 1.0 respectively

See Also: +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) greenColor { return [self colorWithCalibratedRed: 0.0 green: 1.0 blue: 0.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as NSLightGray and 1.0 respectively

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) lightGrayColor { return [self colorWithCalibratedWhite: NSLightGray alpha: 1]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 1.0, 0.0, 1.0 and 1.0 respectively.

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) magentaColor { return [self colorWithCalibratedRed: 1.0 green: 0.0 blue: 1.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 1.0, 0.5, 0.0 and 1.0 respectively.

See Also: +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) orangeColor { return [self colorWithCalibratedRed: 1.0 green: 0.5 blue: 0.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 0.5, 0.0, 0.5 and 1.0 respectively.

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) purpleColor { return [self colorWithCalibratedRed: 0.5 green: 0.0 blue: 0.5 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 1.0, 0.0, 0.0 and 1.0 respectively

See Also: +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) redColor { return [self colorWithCalibratedRed: 1.0 green: 0.0 blue: 0.0 alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedWhiteColorSpace space name. with white and alpha values set as NSWhite and 1.0 respectively.

See Also : +colorWithCalibratedWhite:alpha:

*/ + (NSColor*) whiteColor { return [self colorWithCalibratedWhite: NSWhite alpha: 1.0]; } /**

Returns a NSColor in a NSCalibratedRGBColorSpace space name. with red, green, blue and alpha values set as 1.0, 0.0, 0.0 and 1.0 respectively.

See Also : +colorWithCalibratedRed:green:blue:alpha:

*/ + (NSColor*) yellowColor { return [self colorWithCalibratedRed: 1.0 green: 1.0 blue: 0.0 alpha: 1.0]; } /** Returns whether TODO *

See Also: +setIgnoresAlpha:

*/ + (BOOL) ignoresAlpha { return gnustep_gui_ignores_alpha; } /** TODO *

See Also: +ignoresAlpha

*/ + (void) setIgnoresAlpha: (BOOL)flag { gnustep_gui_ignores_alpha = flag; } /**

Returns the NSColor on the NSPasteboard pasteBoard or nil if it does not exists.

See Also: -writeToPasteboard:

*/ + (NSColor*) colorFromPasteboard: (NSPasteboard *)pasteBoard { NSData *colorData = [pasteBoard dataForType: NSColorPboardType]; // FIXME: This should better use the description format if (colorData != nil) return [NSUnarchiver unarchiveObjectWithData: colorData]; 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*) controlDarkShadowColor { return systemColorWithName(@"controlDarkShadowColor"); } + (NSColor*) controlHighlightColor { return systemColorWithName(@"controlHighlightColor"); } + (NSColor*) controlLightHighlightColor { return systemColorWithName(@"controlLightHighlightColor"); } + (NSColor*) controlShadowColor { return systemColorWithName(@"controlShadowColor"); } + (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*) labelColor { return systemColorWithName(@"labelColor"); } + (NSColor*) quaternaryLabelColor { return systemColorWithName(@"quaternaryLabelColor"); } + (NSColor*) scrollBarColor { return systemColorWithName(@"scrollBarColor"); } + (NSColor*) secondaryLabelColor { return systemColorWithName(@"secondaryLabelColor"); } + (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*) tertiaryLabelColor { return systemColorWithName(@"tertiaryLabelColor"); } + (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; } /**

Gets the cyan, magenta, yellow,black and alpha values from the NSColor. Raises a NSInternalInconsistencyException if the NSColor is not a CYMK color

*/ - (void) getCyan: (CGFloat*)cyan magenta: (CGFloat*)magenta yellow: (CGFloat*)yellow black: (CGFloat*)black alpha: (CGFloat*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getCyan:magenta:yellow:black:alpha: on non-CMYK colour"]; } /**

Gets the hue, saturation, brightness and alpha values from the NSColor. Raises a NSInternalInconsistencyException if the NSColor is not a RGB color

*/ - (void) getHue: (CGFloat*)hue saturation: (CGFloat*)saturation brightness: (CGFloat*)brightness alpha: (CGFloat*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getHue:saturation:brightness:alpha: on non-RGB colour"]; } /**

Gets the red, green, blue and alpha values from the NSColor. Raises a NSInternalInconsistencyException if the NSColor is not a RGB color

*/ -(void) getRed: (CGFloat*)red green: (CGFloat*)green blue: (CGFloat*)blue alpha: (CGFloat*)alpha { [NSException raise: NSInternalInconsistencyException format: @"Called getRed:green:blue:alpha: on non-RGB colour"]; } /**

Gets the white alpha values from the NSColor. Raises a NSInternalInconsistencyException if the NSColor is not a greyscale color

*/ - (void) getWhite: (CGFloat*)white alpha: (CGFloat*)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; } } /**

Returns the alpha component.

*/ - (CGFloat) alphaComponent { return 1.0; } /**

Returns the black component. Raises a NSInternalInconsistencyException if NSColor is not a CMYK color.

*/ - (CGFloat) blackComponent { [NSException raise: NSInternalInconsistencyException format: @"Called blackComponent on non-CMYK colour"]; return 0.0; } /**

Returns the blue component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color.

*/ - (CGFloat) blueComponent { [NSException raise: NSInternalInconsistencyException format: @"Called blueComponent on non-RGB colour"]; return 0.0; } /**

Returns the brightness component. Raises a NSInternalInconsistencyException if NSColor space is not a RGB color

*/ - (CGFloat) 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; } /**

Returns the cyan component. Raises a NSInternalInconsistencyException if NSColor is not a CYMK color

*/ - (CGFloat) cyanComponent { [NSException raise: NSInternalInconsistencyException format: @"Called cyanComponent on non-CMYK colour"]; return 0.0; } /**

Returns the green component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color

*/ - (CGFloat) greenComponent { [NSException raise: NSInternalInconsistencyException format: @"Called greenComponent on non-RGB colour"]; return 0.0; } /**

Returns the hue component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color

*/ - (CGFloat) 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; } /**

Returns the magenta component. Raises a NSInternalInconsistencyException if NSColor is not a CMYK color

*/ - (CGFloat) magentaComponent { [NSException raise: NSInternalInconsistencyException format: @"Called magentaComponent on non-CMYK colour"]; return 0.0; } /**

Returns the red component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color

*/ - (CGFloat) redComponent { [NSException raise: NSInternalInconsistencyException format: @"Called redComponent on non-RGB colour"]; return 0.0; } /**

Returns the saturation component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color

*/ - (CGFloat) saturationComponent { [NSException raise: NSInternalInconsistencyException format: @"Called saturationComponent on non-RGB colour"]; return 0.0; } /**

Returns the white component. Raises a NSInternalInconsistencyException if NSColor is not a grayscale color

*/ - (CGFloat) 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; } /**

Returns the yellow component. Raises a NSInternalInconsistencyException if NSColor is not a RGB color

*/ - (CGFloat) 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; } + (NSColor *) colorWithColorSpace: (NSColorSpace *)space components: (const CGFloat *)comp count: (NSInteger)number { // FIXME if (space == [NSColorSpace genericRGBColorSpace] && (number == 4)) { return [self colorWithCalibratedRed: comp[0] green: comp[1] blue: comp[2] alpha: comp[3]]; } if (space == [NSColorSpace deviceRGBColorSpace] && (number == 4)) { return [self colorWithDeviceRed: comp[0] green: comp[1] blue: comp[2] alpha: comp[3]]; } if (space == [NSColorSpace genericGrayColorSpace] && (number == 2)) { return [NSColor colorWithCalibratedWhite: comp[0] alpha: comp[1]]; } if (space == [NSColorSpace deviceGrayColorSpace] && (number == 2)) { return [NSColor colorWithDeviceWhite: comp[0] alpha: comp[1]]; } if (space == [NSColorSpace genericCMYKColorSpace] && (number == 5)) { return [NSColor colorWithDeviceCyan: comp[0] magenta: comp[1] yellow: comp[2] black: comp[3] alpha: comp[4]]; } if (space == [NSColorSpace deviceCMYKColorSpace] && (number == 5)) { return [NSColor colorWithDeviceCyan: comp[0] magenta: comp[1] yellow: comp[2] black: comp[3] alpha: comp[4]]; } return nil; } /* FIXME: This method does it the wrong way around. We should store the actual colour space and get the colour space name from there. */ - (NSColorSpace *) colorSpace { NSString *name = [self colorSpaceName]; if ([name isEqualToString: NSCalibratedRGBColorSpace]) return [NSColorSpace genericRGBColorSpace]; if ([name isEqualToString: NSDeviceRGBColorSpace]) return [NSColorSpace deviceRGBColorSpace]; if ([name isEqualToString: NSCalibratedBlackColorSpace] || [name isEqualToString: NSCalibratedWhiteColorSpace]) return [NSColorSpace genericGrayColorSpace]; if ([name isEqualToString: NSDeviceBlackColorSpace] || [name isEqualToString: NSDeviceWhiteColorSpace]) return [NSColorSpace deviceGrayColorSpace]; if ([name isEqualToString: NSDeviceCMYKColorSpace]) return [NSColorSpace deviceCMYKColorSpace]; return nil; } - (NSColor *) colorUsingColorSpace: (NSColorSpace *)space { // FIXME NSString *colorSpaceName; if (space == [self colorSpace]) { return self; } switch ([space colorSpaceModel]) { default: case NSUnknownColorSpaceModel: return nil; case NSGrayColorSpaceModel: colorSpaceName = NSDeviceWhiteColorSpace; break; case NSRGBColorSpaceModel: colorSpaceName = NSDeviceRGBColorSpace; break; case NSCMYKColorSpaceModel: colorSpaceName = NSDeviceCMYKColorSpace; break; case NSLABColorSpaceModel: return nil; case NSDeviceNColorSpaceModel: return nil; } return [self colorUsingColorSpaceName: colorSpaceName device: nil]; } - (NSUInteger) hash { int nums = [self numberOfComponents]; CGFloat floats[nums]; NSUInteger h = 0; unsigned i; [self getComponents: &floats[0]]; for (i = 0; i < sizeof(floats); i++) { h = (h << 5) + h + *(uint8_t*)(((uintptr_t)&floats[0])+(i*sizeof(uint8_t))); } return h; } - (NSInteger) numberOfComponents { [NSException raise: NSInternalInconsistencyException format: @"Called numberOfComponents on non-standard colour"]; return 0; } - (void) getComponents: (CGFloat *)components { [NSException raise: NSInternalInconsistencyException format: @"Called getComponents: on non-standard colour"]; } // // Changing the Color // - (NSColor*) blendedColorWithFraction: (CGFloat)fraction ofColor: (NSColor*)aColor { NSColor *myColor = [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace]; NSColor *other = [aColor colorUsingColorSpaceName: NSCalibratedRGBColorSpace]; CGFloat 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: (CGFloat)alpha { return self; } - (NSColor*) highlightWithLevel: (CGFloat)level { return [self blendedColorWithFraction: level ofColor: [NSColorClass highlightColor]]; } - (NSColor*) shadowWithLevel: (CGFloat)level { return [self blendedColorWithFraction: level ofColor: [NSColorClass shadowColor]]; } /**

Writes the NSColor into the NSPasteboard specified by pasteBoard

*

See Also: +colorFromPasteboard:

*/ - (void) writeToPasteboard: (NSPasteboard *)pasteBoard { // FIXME: We should better use the description NSData *colorData = [NSArchiver archivedDataWithRootObject: self]; if (colorData != nil) [pasteBoard setData: colorData forType: NSColorPboardType]; } // // Drawing // - (void) drawSwatchInRect: (NSRect)rect { if ([self alphaComponent] < 1.0) { NSBezierPath *triangle = [NSBezierPath bezierPath]; [[NSColor whiteColor] set]; NSRectFill(rect); [triangle moveToPoint: NSMakePoint(rect.origin.x, rect.origin.y + rect.size.height)]; [triangle lineToPoint: NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height)]; [triangle lineToPoint: rect.origin]; [triangle closePath]; [[NSColor blackColor] set]; [triangle fill]; } [self set]; NSRectFill(rect); } - (void) set { // This is here to keep old code working [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] set]; } - (void) setFill { [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] setFill]; } - (void) setStroke { [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] setStroke]; } // // 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)) { NSUInteger length; const uint8_t *data; double red = 0.0; double green = 0.0; double blue = 0.0; double alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSRGB"]) { data = [aDecoder decodeBytesForKey: @"NSRGB" returnedLength: &length]; str = [[NSString alloc] initWithCString: (const char*)data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanDouble: &red]; [scanner scanDouble: &green]; [scanner scanDouble: &blue]; [scanner scanDouble: &alpha]; RELEASE(scanner); RELEASE(str); } if (colorSpace == 1) { self = RETAIN([NSColor colorWithCalibratedRed: red green: green blue: blue alpha: alpha]); } else { self = RETAIN([NSColor colorWithDeviceRed: red green: green blue: blue alpha: alpha]); } } else if ((colorSpace == 3) || (colorSpace == 4)) { NSUInteger length; const uint8_t *data; double white = 0.0; double alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSWhite"]) { data = [aDecoder decodeBytesForKey: @"NSWhite" returnedLength: &length]; str = [[NSString alloc] initWithCString: (const char*)data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanDouble: &white]; [scanner scanDouble: &alpha]; RELEASE(scanner); RELEASE(str); } if (colorSpace == 3) { self = RETAIN([NSColor colorWithCalibratedWhite: white alpha: alpha]); } else { self = RETAIN([NSColor colorWithDeviceWhite: white alpha: alpha]); } } else if (colorSpace == 5) { NSUInteger length; const uint8_t *data; double cyan = 0.0; double yellow = 0.0; double magenta = 0.0; double black = 0.0; double alpha = 1.0; NSString *str; NSScanner *scanner; if ([aDecoder containsValueForKey: @"NSCYMK"]) { data = [aDecoder decodeBytesForKey: @"NSCYMK" returnedLength: &length]; str = [[NSString alloc] initWithCString: (const char*)data length: length]; scanner = [[NSScanner alloc] initWithString: str]; [scanner scanDouble: &cyan]; [scanner scanDouble: &yellow]; [scanner scanDouble: &magenta]; [scanner scanDouble: &black]; [scanner scanDouble: &alpha]; RELEASE(scanner); RELEASE(str); } self = RETAIN([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 = RETAIN([NSColor colorWithCatalogName: catalog colorName: name]); } else if (colorSpace == 10) { NSImage *image = [aDecoder decodeObjectForKey: @"NSImage"]; self = RETAIN([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; CGFloat 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 doubleValue]; } if ([space isEqual: NSCalibratedWhiteColorSpace]) { CGFloat white = [[dict objectForKey: @"W"] doubleValue]; return [self colorWithCalibratedWhite: white alpha: alpha]; } if ([space isEqual: NSCalibratedBlackColorSpace]) { CGFloat white = [[dict objectForKey: @"W"] doubleValue]; return [self colorWithCalibratedWhite: white alpha: alpha]; } if ([space isEqual: NSCalibratedRGBColorSpace]) { if ([dict objectForKey: @"H"] != nil) { CGFloat hue = [[dict objectForKey: @"H"] doubleValue]; CGFloat saturation = [[dict objectForKey: @"S"] doubleValue]; CGFloat brightness = [[dict objectForKey: @"B"] doubleValue]; return [self colorWithCalibratedHue: hue saturation: saturation brightness: brightness alpha: alpha]; } else { CGFloat red = [[dict objectForKey: @"R"] doubleValue]; CGFloat green = [[dict objectForKey: @"G"] doubleValue]; CGFloat blue = [[dict objectForKey: @"B"] doubleValue]; return [self colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } } if ([space isEqual: NSDeviceCMYKColorSpace]) { CGFloat cyan = [[dict objectForKey: @"C"] doubleValue]; CGFloat magenta = [[dict objectForKey: @"M"] doubleValue]; CGFloat yellow = [[dict objectForKey: @"Y"] doubleValue]; CGFloat black = [[dict objectForKey: @"B"] doubleValue]; 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) { double r, g, b; NSScanner *scanner = [[NSScanner alloc] initWithString: str]; if ([scanner scanDouble: &r] && [scanner scanDouble: &g] && [scanner scanDouble: &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]; } } /* * Handle activation of a new theme ... look for a 'System' color list * in the theme bundle and use it instead of the default system color * list if it is present. */ + (void) themeDidActivate: (NSNotification*)notification { GSTheme *theme = [notification object]; NSColorList *list = [theme colors]; NSEnumerator *enumerator; NSString *name; if (list == nil) { list = defaultSystemColors; } NSAssert([[list name] isEqual: @"System"], NSInvalidArgumentException); [NSColorList _setThemeSystemColorList: list]; /* We always update the system dictionary and send a notification, since * the theme may have given us a pre-existing color list, but have changed * one or more of the colors in it. */ list = [NSColorList colorListNamed: @"System"]; ASSIGN(systemColors, list); enumerator = [systemDict keyEnumerator]; while ((name = [enumerator nextObject]) != nil) { [[systemDict objectForKey: name] recache]; } [[NSNotificationCenter defaultCenter] postNotificationName: NSSystemColorsDidChangeNotification object: nil]; } @end // Named colours @implementation GSNamedColor static NSMutableDictionary *namedColors = nil; static NSRecursiveLock *namedColorLock = nil; + (void) initialize { namedColorLock = [NSRecursiveLock new]; namedColors = [NSMutableDictionary new]; } - (NSColor*) initWithCatalogName: (NSString *)listName colorName: (NSString *)colorName { NSMutableDictionary *d; NSColor *c; _catalog_name = [listName copy]; _color_name = [colorName copy]; [namedColorLock lock]; d = [namedColors objectForKey: _catalog_name]; if (d == nil) { d = [NSMutableDictionary new]; [namedColors setObject: d forKey: _catalog_name]; [d release]; } c = [d objectForKey: _color_name]; if (c == nil) { [d setObject: self forKey: _color_name]; } else { [self release]; self = (GSNamedColor*)[c retain]; } [namedColorLock unlock]; 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 { return RETAIN(self); } - (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"); } - (NSUInteger) hash { return [_catalog_name hash] + [_color_name hash]; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO || [[other catalogNameComponent] isEqualToString: _catalog_name] == NO || [[other colorNameComponent] isEqualToString: _color_name] == NO) { return NO; } return YES; } - (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? [namedColorLock lock]; if (NO == [colorSpace isEqualToString: _cached_name_space]) { list = [NSColorList colorListNamed: _catalog_name]; real = [list colorWithKey: _color_name]; ASSIGN(_cached_color, [real colorUsingColorSpaceName: colorSpace device: deviceDescription]); ASSIGN(_cached_name_space, colorSpace); } real = [[_cached_color retain] autorelease]; [namedColorLock unlock]; return real; } - (void) recache { [namedColorLock lock]; DESTROY(_cached_name_space); DESTROY(_cached_color); [namedColorLock unlock]; } // // 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 { NSString *listName; NSString *colorName; listName = [aDecoder decodeObject]; colorName = [aDecoder decodeObject]; return [self initWithCatalogName: listName colorName: colorName]; } @end // Grayscale colours @implementation GSWhiteColor - (CGFloat) alphaComponent { return _alpha_component; } - (CGFloat) whiteComponent { return _white_component; } - (void) getComponents: (CGFloat *)components; { components[0] = _white_component; components[1] = _alpha_component; } - (NSInteger) numberOfComponents { return 2; } - (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 = \"%g\";", (double)_white_component]; [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component]; return desc; } - (void) getWhite: (CGFloat*)white alpha: (CGFloat*)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 || [other whiteComponent] != _white_component || [other alphaComponent] != _alpha_component) { return NO; } return YES; } - (NSColor*) colorWithAlphaComponent: (CGFloat)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 AUTORELEASE(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 %g\n", (double)_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"]; } if (_alpha_component == 1.0) { str = [[NSString alloc] initWithFormat: @"%g", (double)_white_component]; } else { str = [[NSString alloc] initWithFormat: @"%g %g", (double)_white_component, (double)_alpha_component]; } [aCoder encodeBytes: (const uint8_t*)[str cString] length: [str cStringLength] forKey: @"NSWhite"]; RELEASE(str); } else { float white = _white_component; float alpha = _alpha_component; [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &white]; [aCoder encodeValueOfObjCType: @encode(float) at: &alpha]; } } - (id) initWithCoder: (NSCoder*)aDecoder { float white, alpha; [aDecoder decodeValueOfObjCType: @encode(float) at: &white]; [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha]; _white_component = white; _alpha_component = alpha; return self; } @end @implementation GSDeviceWhiteColor - (NSString *) colorSpaceName { return NSDeviceWhiteColorSpace; } - (NSColor*) initWithDeviceWhite: (CGFloat)white alpha: (CGFloat)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: (CGFloat)white alpha: (CGFloat)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: (CGFloat)cyan magenta: (CGFloat)magenta yellow: (CGFloat)yellow black: (CGFloat)black alpha: (CGFloat)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; } - (CGFloat) alphaComponent { return _alpha_component; } - (CGFloat) blackComponent { return _black_component; } - (CGFloat) cyanComponent { return _cyan_component; } - (CGFloat) magentaComponent { return _magenta_component; } - (CGFloat) yellowComponent { return _yellow_component; } - (void) getComponents: (CGFloat *)components; { components[0] = _cyan_component; components[1] = _magenta_component; components[2] = _yellow_component; components[3] = _black_component; components[4] = _alpha_component; } - (NSInteger) numberOfComponents { return 5; } - (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 = \"%g\";", (double)_cyan_component]; [desc appendFormat: @" M = \"%g\";", (double)_magenta_component]; [desc appendFormat: @" Y = \"%g\";", (double)_yellow_component]; [desc appendFormat: @" K = \"%g\";", (double)_black_component]; [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component]; return desc; } - (void) getCyan: (CGFloat*)cyan magenta: (CGFloat*)magenta yellow: (CGFloat*)yellow black: (CGFloat*)black alpha: (CGFloat*)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 || [other cyanComponent] != _cyan_component || [other magentaComponent] != _magenta_component || [other yellowComponent] != _yellow_component || [other blackComponent] != _black_component || [other alphaComponent] != _alpha_component) { return NO; } return YES; } - (NSColor*) colorWithAlphaComponent: (CGFloat)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 AUTORELEASE(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 %g %g %g %g\n", (double)_cyan_component, (double)_magenta_component, (double)_yellow_component, (double)_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; [aCoder encodeInt: 5 forKey: @"NSColorSpace"]; if (_alpha_component == 1.0) { str = [[NSString alloc] initWithFormat: @"%g %g %g %g", (double)_cyan_component, (double)_magenta_component, (double)_yellow_component, (double)_black_component]; } else { str = [[NSString alloc] initWithFormat: @"%g %g %g %g %g", (double)_cyan_component, (double)_magenta_component, (double)_yellow_component, (double)_black_component, (double)_alpha_component]; } [aCoder encodeBytes: (const uint8_t*)[str cString] length: [str cStringLength] forKey: @"NSCYMK"]; RELEASE(str); } else { float c = _cyan_component; float m = _magenta_component; float y = _yellow_component; float k = _black_component; float a = _alpha_component; [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &c]; [aCoder encodeValueOfObjCType: @encode(float) at: &m]; [aCoder encodeValueOfObjCType: @encode(float) at: &y]; [aCoder encodeValueOfObjCType: @encode(float) at: &k]; [aCoder encodeValueOfObjCType: @encode(float) at: &a]; } } - (id) initWithCoder: (NSCoder*)aDecoder { // FIXME: Implement keyed decoding! float c, m, y, k, a; [aDecoder decodeValueOfObjCType: @encode(float) at: &c]; [aDecoder decodeValueOfObjCType: @encode(float) at: &m]; [aDecoder decodeValueOfObjCType: @encode(float) at: &y]; [aDecoder decodeValueOfObjCType: @encode(float) at: &k]; [aDecoder decodeValueOfObjCType: @encode(float) at: &a]; _cyan_component = c; _magenta_component = m; _yellow_component = y; _black_component = k; _alpha_component = a; return self; } @end // RGB/HSB colours @implementation GSRGBColor - (CGFloat) alphaComponent { return _alpha_component; } - (CGFloat) redComponent { return _red_component; } - (CGFloat) greenComponent { return _green_component; } - (CGFloat) blueComponent { return _blue_component; } - (CGFloat) hueComponent { return _hue_component; } - (CGFloat) saturationComponent { return _saturation_component; } - (CGFloat) brightnessComponent { return _brightness_component; } - (void) getComponents: (CGFloat *)components; { components[0] = _red_component; components[1] = _green_component; components[2] = _blue_component; components[3] = _alpha_component; } - (NSInteger) numberOfComponents { return 4; } - (void) getHue: (CGFloat*)hue saturation: (CGFloat*)saturation brightness: (CGFloat*)brightness alpha: (CGFloat*)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: (CGFloat*)red green: (CGFloat*)green blue: (CGFloat*)blue alpha: (CGFloat*)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 || [other redComponent] != _red_component || [other greenComponent] != _green_component || [other blueComponent] != _blue_component || [other alphaComponent] != _alpha_component) { return NO; } return YES; } - (NSColor*) colorWithAlphaComponent: (CGFloat)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 AUTORELEASE(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: @"%g %g %g", (double)_red_component, (double)_green_component, (double)_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 = \"%g\";", (double)_red_component]; [desc appendFormat: @" G = \"%g\";", (double)_green_component]; [desc appendFormat: @" B = \"%g\";", (double)_blue_component]; [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component]; return desc; } - (void) set { /* This should only be in GSDeviceRGBColor, * but is here to keep old code working. */ NSDebugLLog(@"NSColor", @"RGB %g %g %g\n", (double)_red_component, (double)_green_component, (double)_blue_component); PSsetrgbcolor(_red_component, _green_component, _blue_component); // Should we check the ignore flag here? PSsetalpha(_alpha_component); } - (void) setFill { int num = [self numberOfComponents]; CGFloat values[num]; NSGraphicsContext *ctxt = GSCurrentContext(); [ctxt GSSetFillColorspace: [self colorSpace]]; [self getComponents: values]; [ctxt GSSetFillColor: values]; } - (void) setStroke { int num = [self numberOfComponents]; CGFloat values[num]; NSGraphicsContext *ctxt = GSCurrentContext(); [ctxt GSSetStrokeColorspace: [self colorSpace]]; [self getComponents: values]; [ctxt GSSetStrokeColor: values]; } // // 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"]; } if (_alpha_component == 1.0) { str = [[NSString alloc] initWithFormat: @"%g %g %g", (double)_red_component, (double)_green_component, (double)_blue_component]; } else { str = [[NSString alloc] initWithFormat: @"%g %g %g %g", (double)_red_component, (double)_green_component, (double)_blue_component, (double)_alpha_component]; } [aCoder encodeBytes: (const uint8_t*)[str cString] length: [str cStringLength] forKey: @"NSRGB"]; RELEASE(str); } else { float red = _red_component; float green = _green_component; float blue = _blue_component; float hue = _hue_component; float saturation = _saturation_component; float brightness = _brightness_component; float alpha = _alpha_component; [aCoder encodeObject: [self colorSpaceName]]; [aCoder encodeValueOfObjCType: @encode(float) at: &red]; [aCoder encodeValueOfObjCType: @encode(float) at: &green]; [aCoder encodeValueOfObjCType: @encode(float) at: &blue]; [aCoder encodeValueOfObjCType: @encode(float) at: &hue]; [aCoder encodeValueOfObjCType: @encode(float) at: &saturation]; [aCoder encodeValueOfObjCType: @encode(float) at: &brightness]; [aCoder encodeValueOfObjCType: @encode(float) at: &alpha]; } } - (id) initWithCoder: (NSCoder*)aDecoder { float red, green, blue, hue, saturation, brightness, alpha; [aDecoder decodeValueOfObjCType: @encode(float) at: &red]; [aDecoder decodeValueOfObjCType: @encode(float) at: &green]; [aDecoder decodeValueOfObjCType: @encode(float) at: &blue]; [aDecoder decodeValueOfObjCType: @encode(float) at: &hue]; [aDecoder decodeValueOfObjCType: @encode(float) at: &saturation]; [aDecoder decodeValueOfObjCType: @encode(float) at: &brightness]; [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha]; _red_component = red; _green_component = green; _blue_component = blue; _hue_component = hue; _saturation_component = saturation; _brightness_component = brightness; _alpha_component = alpha; return self; } @end @implementation GSDeviceRGBColor - (NSString *) colorSpaceName { return NSDeviceRGBColorSpace; } - (NSColor*) initWithDeviceRed: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)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; { CGFloat r = _red_component; CGFloat g = _green_component; CGFloat 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: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)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 = (CGFloat)R; _green_component = (CGFloat)G; _blue_component = (CGFloat)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: (CGFloat)red green: (CGFloat)green blue: (CGFloat)blue alpha: (CGFloat)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; { CGFloat r = _red_component; CGFloat g = _green_component; CGFloat 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: (CGFloat)hue saturation: (CGFloat)saturation brightness: (CGFloat)brightness alpha: (CGFloat)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 = (CGFloat)R; _green_component = (CGFloat)G; _blue_component = (CGFloat)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; } - (NSUInteger) hash { return [_pattern hash]; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [self class]] == NO || [[other patternImage] isEqual: _pattern] == NO) { return NO; } return YES; } - (id) copyWithZone: (NSZone*)aZone { if (NSShouldRetainWithZone(self, aZone)) { return RETAIN(self); } else { GSPatternColor *aCopy = (GSPatternColor*)NSCopyObject(self, 0, aZone); aCopy->_pattern = [_pattern copyWithZone: aZone]; return aCopy; } } - (void) set { [GSCurrentContext() GSSetPatterColor: _pattern]; } // // 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