/** NSColorPanel System generic color panel Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include "AppKit/NSButtonCell.h" #include "AppKit/NSColor.h" #include "AppKit/NSColorPanel.h" #include "AppKit/NSColorPicker.h" #include "AppKit/NSColorPicking.h" #include "AppKit/NSColorWell.h" #include "AppKit/NSImage.h" #include "AppKit/NSPasteboard.h" #include "AppKit/NSWindow.h" #include "GNUstepGUI/IMLoading.h" #define MAX_ALPHA_VALUE 100.0 static NSLock *_gs_gui_color_panel_lock = nil; static NSColorPanel *_gs_gui_color_panel = nil; static int _gs_gui_color_picker_mask = NSColorPanelAllModesMask; // FIXME: This should be NSWheelModeColorPanel static int _gs_gui_color_picker_mode = NSRGBModeColorPanel; @implementation NSApplication (NSColorPanel) - (void) orderFrontColorPanel: sender { NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; if (colorPanel) [colorPanel orderFront: nil]; else NSBeep(); } @end @interface NSColorPanel (PrivateMethods) - (void) _loadPickers; - (void) _loadPickerAtPath: (NSString *)path; - (void) _fixupMatrix; - (void) _setupPickers; - (void) _showNewPicker: (id)sender; - (id) _initWithoutGModel; @end @implementation NSColorPanel (PrivateMethods) - (void) _loadPickers { NSArray *paths; NSString *path; NSEnumerator *pathEnumerator; NSArray *bundles; NSEnumerator *bundleEnumerator; NSString *bundleName; _pickers = [NSMutableArray new]; paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES); pathEnumerator = [paths objectEnumerator]; while ((path = [pathEnumerator nextObject])) { path = [path stringByAppendingPathComponent: @"ColorPickers"]; bundles = [[NSFileManager defaultManager] directoryContentsAtPath: path]; bundleEnumerator = [bundles objectEnumerator]; while ((bundleName = [bundleEnumerator nextObject])) { [self _loadPickerAtPath: [path stringByAppendingPathComponent: bundleName]]; } } paths = [[NSBundle mainBundle] pathsForResourcesOfType: @"bundle" inDirectory: @"ColorPickers"]; pathEnumerator = [paths objectEnumerator]; while ((path = [pathEnumerator nextObject])) { [self _loadPickerAtPath: path]; } } - (void) _loadPickerAtPath: (NSString *)path { NSBundle *bundle; Class pickerClass; NSColorPicker *picker; bundle = [NSBundle bundleWithPath: path]; if (bundle && (pickerClass = [bundle principalClass])) { picker = [[pickerClass alloc] initWithPickerMask:_gs_gui_color_picker_mask colorPanel: self]; if (picker && [picker conformsToProtocol:@protocol(NSColorPickingCustom)]) { [(id)picker provideNewView: YES]; [_pickers addObject: picker]; } else { NSLog(@"%@ does not contain a valid color picker.", path); } } } // FIXME - this is a HACK to get around problems in the gmodel code - (void) _fixupMatrix { NSButtonCell *prototype; [_pickerMatrix setFrame: NSMakeRect(4, 190, 192, 36)]; prototype = [[NSButtonCell alloc] initImageCell: nil]; [prototype setButtonType: NSOnOffButton]; [_pickerMatrix setPrototype: prototype]; RELEASE(prototype); } - (void) _setupPickers { id picker; NSButtonCell *cell; NSMutableArray *cells = [NSMutableArray new]; int i, count; NSSize size = [_pickerMatrix frame].size; count = [_pickers count]; for (i = 0; i < count; i++) { cell = [[_pickerMatrix prototype] copy]; [cell setTag: i]; picker = [_pickers objectAtIndex: i]; [picker insertNewButtonImage: [picker provideNewButtonImage] in: cell]; [cells addObject: cell]; } [_pickerMatrix addRowWithCells: cells]; RELEASE(cells); [_pickerMatrix setCellSize: NSMakeSize(size.width / count, size.height)]; [_pickerMatrix setTarget: self]; [_pickerMatrix setAction: @selector(_showNewPicker:)]; // use the space occupied by the matrix of color picker buttons if the // button matrix is useless, i.e. it contains only one button if (count < 2) { [_pickerBox setFrame: NSUnionRect([_pickerBox frame], [_pickerMatrix frame])]; [_pickerBox setNeedsDisplay: YES]; // Display the only picker if (count == 1) [self _showNewPicker: _pickerMatrix]; } } - (void) _showNewPicker: (id)sender { _currentPicker = [_pickers objectAtIndex: [sender selectedColumn]]; [_currentPicker setColor: [_colorWell color]]; [_pickerBox setContentView: [_currentPicker provideNewView: NO]]; } - (id) _initWithoutGModel { NSRect contentRect = {{352, 519}, {200, 270}}; NSRect topViewRect = {{0, 0}, {200, 270}}; NSRect magnifyRect = {{4, 230}, {50, 36}}; NSRect wellRect = {{58, 230}, {138, 36}}; NSRect matrixRect = {{4, 190}, {192, 36}}; NSRect splitRect = {{0, 0}, {200, 190}}; NSRect pickerViewRect = {{0, 40}, {200, 150}}; NSRect pickerRect = {{0, 20}, {200, 130}}; NSRect alphaRect = {{4, 4}, {160, 16}}; NSRect swatchRect = {{4, 4}, {200, 30}}; NSView *v; NSButtonCell *pickerButton; NSView *pickerView; NSView *swatchView; NSColorWell *well; int i; unsigned int style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask; self = [super initWithContentRect: contentRect styleMask: style backing: NSBackingStoreRetained defer: NO screen: nil]; [self setTitle: @"Colors"]; v = [self contentView]; _topView = [[NSView alloc] initWithFrame: topViewRect]; [_topView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; [v addSubview: _topView]; RELEASE(_topView); _magnifyButton = [[NSButton alloc] initWithFrame: magnifyRect]; [_magnifyButton setAutoresizingMask: (NSViewMaxXMargin | NSViewMinYMargin)]; [_magnifyButton setImage: [NSImage imageNamed: @"MagnifyGlass"]]; [_magnifyButton setBordered: YES]; [_magnifyButton setAction: @selector(_magnify:)]; [_magnifyButton setTarget: self]; [_topView addSubview: _magnifyButton]; _colorWell = [[NSColorWell alloc] initWithFrame: wellRect]; [_colorWell setAutoresizingMask: (NSViewWidthSizable | NSViewMinYMargin)]; [_colorWell setBordered: NO]; [_colorWell setTarget: self]; [_colorWell setAction: @selector(_updatePicker:)]; [_topView addSubview: _colorWell]; // Prototype cell for the matrix pickerButton = [[NSButtonCell alloc] initImageCell: nil]; [pickerButton setButtonType: NSOnOffButton]; [pickerButton setBordered: YES]; _pickerMatrix = [[NSMatrix alloc] initWithFrame: matrixRect mode: NSRadioModeMatrix prototype: pickerButton numberOfRows: 0 numberOfColumns: 0]; RELEASE(pickerButton); [_pickerMatrix setAutoresizingMask: (NSViewWidthSizable | NSViewMinYMargin)]; [_pickerMatrix setCellSize: matrixRect.size]; [_pickerMatrix setIntercellSpacing: NSMakeSize(1, 0)]; [_pickerMatrix setAutosizesCells: YES]; [_topView addSubview: _pickerMatrix]; _splitView = [[NSSplitView alloc] initWithFrame: splitRect]; [_splitView setVertical: NO]; [_splitView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; [_topView addSubview: _splitView]; pickerView = [[NSView alloc] initWithFrame: pickerViewRect]; [pickerView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; _pickerBox = [[NSBox alloc] initWithFrame: pickerRect]; [_pickerBox setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; [_pickerBox setBorderType: NSNoBorder]; [_pickerBox setTitle: @""]; [_pickerBox setTitlePosition: NSNoTitle]; [pickerView addSubview: _pickerBox]; _alphaSlider = [[NSSlider alloc] initWithFrame: alphaRect]; [_alphaSlider setAutoresizingMask: (NSViewWidthSizable | NSViewMaxYMargin)]; [_alphaSlider setMinValue: 0.0]; [_alphaSlider setMaxValue: MAX_ALPHA_VALUE]; [_alphaSlider setFloatValue: MAX_ALPHA_VALUE]; [_alphaSlider setContinuous: YES]; [_alphaSlider setTitle: @"Opacity"]; [[_alphaSlider cell] setBezeled: YES]; [_alphaSlider setTarget: self]; [_alphaSlider setAction: @selector(_alphaChanged:)]; [pickerView addSubview: _alphaSlider]; _showsAlpha = YES; swatchView = [[NSView alloc] initWithFrame: swatchRect]; [swatchView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; // Add all the subviews at the end [_splitView addSubview: pickerView]; [_splitView addSubview: swatchView]; RELEASE(pickerView); RELEASE(swatchView); // FIXME: This should be loaded form somewhere. // Perhaps a colour list called "custom"? for (i = 0; i < 14; i++) { NSColor *colour; switch (i) { default: case 0: colour = [NSColor greenColor]; break; case 1: colour = [NSColor whiteColor]; break; case 2: colour = [NSColor blackColor]; break; case 3: colour = [NSColor blueColor]; break; case 4: colour = [NSColor brownColor]; break; case 5: colour = [NSColor cyanColor]; break; case 6: colour = [NSColor darkGrayColor]; break; case 7: colour = [NSColor grayColor]; break; case 8: colour = [NSColor lightGrayColor]; break; case 9: colour = [NSColor magentaColor]; break; case 10: colour = [NSColor orangeColor]; break; case 11: colour = [NSColor purpleColor]; break; case 12: colour = [NSColor redColor]; break; case 13: colour = [NSColor yellowColor]; break; } well = [[NSColorWell alloc] initWithFrame: NSMakeRect(i * 13 + 5, 5, 12, 12)]; [well setColor: colour]; [well setBordered: NO]; [well setEnabled: NO]; [well setTarget: _colorWell]; [well setAction: @selector(_bottomWellAction:)]; [swatchView addSubview: well]; RELEASE(well); } return self; } - (void) _alphaChanged: (id) sender { [self setColor: [[self color] colorWithAlphaComponent: [self alpha]]]; } - (void) _apply: (id) sender { // This is currently not used [NSApp sendAction: @selector(changeColor:) to: nil from: self]; if ((_action) && (_target != nil)) [NSApp sendAction: _action to: _target from: self]; } - (void) _maginify: (id) sender { NSLog(@"Magnification is not implemented"); } - (void) _updatePicker: (id) sender { [_currentPicker setColor: [_colorWell color]]; } - (void) _bottomWellAction: (id) sender { [self setColor: [sender color]]; } @end @implementation NSColorPanel /* * Class methods */ + (void) initialize { if (self == [NSColorPanel class]) { // Initial version [self setVersion: 1]; _gs_gui_color_panel_lock = [NSLock new]; } } + (NSColorPanel *)sharedColorPanel { if (_gs_gui_color_panel == nil) { [_gs_gui_color_panel_lock lock]; if (!_gs_gui_color_panel) { // Keep this two lines separated so the check in [init] works. _gs_gui_color_panel = [self alloc]; [_gs_gui_color_panel init]; } [_gs_gui_color_panel_lock unlock]; } return _gs_gui_color_panel; } + (BOOL) sharedColorPanelExists { return (_gs_gui_color_panel == nil) ? NO : YES; } + (void) setPickerMask: (int)mask { _gs_gui_color_picker_mask = mask; } + (void) setPickerMode: (int)mode { _gs_gui_color_picker_mode = mode; } + (BOOL) dragColor: (NSColor *)aColor withEvent: (NSEvent *)anEvent fromView: (NSView *)sourceView { NSPasteboard *pb = [NSPasteboard pasteboardWithName: NSDragPboard]; NSImage *image = [NSImage imageNamed: @"common_ColorSwatch"]; [pb declareTypes: [NSArray arrayWithObjects: NSColorPboardType, nil] owner: aColor]; [aColor writeToPasteboard: pb]; [image setBackgroundColor: aColor]; [sourceView dragImage: image at: [sourceView bounds].origin offset: NSMakeSize(0,0) event: anEvent pasteboard: pb source: sourceView slideBack: NO]; return YES; } /* * Instance methods */ - (id) init { if (self != _gs_gui_color_panel) { RELEASE(self); return _gs_gui_color_panel; } // if (![NSBundle loadNibNamed: @"ColorPanel" owner: self]); [self _initWithoutGModel]; [self _loadPickers]; [self _setupPickers]; [self setMode: _gs_gui_color_picker_mode]; [self setShowsAlpha: ![NSColor ignoresAlpha]]; return self; } - (void) dealloc { // As there is only one this will never be called RELEASE(_topView); RELEASE(_colorWell); RELEASE(_magnifyButton); RELEASE(_pickerMatrix); RELEASE(_pickerBox); RELEASE(_alphaSlider); RELEASE(_splitView); RELEASE(_pickers); [super dealloc]; } - (NSView *) accessoryView { return _accessoryView; } - (BOOL) isContinuous { return _isContinuous; } - (int) mode { if (_currentPicker != nil) return [_currentPicker currentMode]; else return 0; } - (void) setAccessoryView: (NSView *)aView { if (_accessoryView == aView) return; if (_accessoryView != nil) [_splitView removeSubview: _accessoryView]; _accessoryView = aView; [_splitView addSubview: _accessoryView]; } - (void) setAction: (SEL)aSelector { _action = aSelector; } - (void) setContinuous: (BOOL)flag { _isContinuous = flag; } - (void) setMode: (int)mode { int i, count; if (mode == [self mode]) return; count = [_pickers count]; for (i = 0; i < count; i++) { if ([[_pickers objectAtIndex: i] supportsMode: mode]) { [_pickerMatrix selectCellWithTag: i]; [self _showNewPicker: _pickerMatrix]; [_currentPicker setMode: mode]; break; } } } - (void) setShowsAlpha: (BOOL)flag { if (flag == _showsAlpha) return; if (flag) { NSRect newFrame = [_pickerBox frame]; float offset = [_alphaSlider frame].size.height + 4; [_alphaSlider setFrameOrigin: newFrame.origin]; [[_pickerBox superview] addSubview: _alphaSlider]; newFrame.origin.y += offset; newFrame.size.height -= offset; [_pickerBox setFrame: newFrame]; } else { // Remove the alpha slider, and add its size to the pickeBox [_alphaSlider removeFromSuperview]; [_pickerBox setFrame: NSUnionRect([_pickerBox frame], [_alphaSlider frame])]; } _showsAlpha = flag; [_pickers makeObjectsPerformSelector: @selector(alphaControlAddedOrRemoved:) withObject: self]; [_topView setNeedsDisplay: YES]; } - (void) setTarget: (id)anObject { _target = anObject; } - (BOOL) showsAlpha { return _showsAlpha; } // // Attaching a Color List // - (void) attachColorList: (NSColorList *)aColorList { [_pickers makeObjectsPerformSelector: @selector(attachColorList:) withObject: aColorList]; } - (void) detachColorList: (NSColorList *)aColorList { [_pickers makeObjectsPerformSelector: @selector(detachColorList:) withObject: aColorList]; } // // Setting Color // - (float) alpha { if ([self showsAlpha]) return [_alphaSlider floatValue] / MAX_ALPHA_VALUE; else return 1.0; } - (NSColor *) color { return [_colorWell color]; } - (void) setColor: (NSColor *)aColor { [_colorWell setColor: aColor]; [_currentPicker setColor: aColor]; if ([self showsAlpha]) [_alphaSlider setFloatValue: [aColor alphaComponent] * MAX_ALPHA_VALUE]; if (_isContinuous && (_action) && (_target != nil)) [NSApp sendAction: _action to: _target from: self]; [[NSNotificationCenter defaultCenter] postNotificationName: NSColorPanelColorChangedNotification object: (id)self]; } // // NSCoding protocol // - (void) encodeWithCoder: (NSCoder*)aCoder { [super encodeWithCoder: aCoder]; } - (id) initWithCoder: (NSCoder*)aDecoder { [super initWithCoder: aDecoder]; return self; } @end