File: NSColorPanel.m

package info (click to toggle)
gnustep-gui 0.9.5-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 9,464 kB
  • ctags: 4,689
  • sloc: objc: 104,993; ansic: 28,794; cpp: 3,058; makefile: 353; yacc: 298; sh: 37
file content (636 lines) | stat: -rw-r--r-- 16,974 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
/** <title>NSColorPanel</title>

   <abstract>System generic color panel</abstract>

   Copyright (C) 1996 Free Software Foundation, Inc.

   Author: Scott Christley <scottc@net-community.com>
   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 <Foundation/NSBundle.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSPathUtilities.h>
#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<NSColorPickingCustom>)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<NSColorPickingDefault, NSColorPickingCustom> 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