API  1.0.0
CPColorWell.j
Go to the documentation of this file.
1 /*
2  * CPColorWell.j
3  * AppKit
4  *
5  * Created by Ross Boucher.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
27 
35 @implementation CPColorWell : CPControl
36 {
37  BOOL _active;
38  BOOL _bordered;
39 
40  CPColor _color;
41 }
42 
43 + (Class)_binderClassForBinding:(CPString)aBinding
44 {
45  if (aBinding == CPValueBinding)
47 
48  return [super _binderClassForBinding:aBinding];
49 }
50 
51 + (CPString)defaultThemeClass
52 {
53  return @"colorwell";
54 }
55 
56 + (CPDictionary)themeAttributes
57 {
58  return @{
59  @"bezel-inset": CGInsetMakeZero(),
60  @"bezel-color": [CPNull null],
61  @"content-inset": CGInsetMake(3.0, 3.0, 3.0, 3.0),
62  @"content-border-inset": CGInsetMakeZero(),
63  @"content-border-color": [CPNull null],
64  };
65 }
66 
67 - (void)_reverseSetBinding
68 {
69  var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
70  theBinding = [binderClass getBinding:CPValueBinding forObject:self];
71 
72  [theBinding reverseSetValueFor:@"color"];
73 }
74 
75 - (id)initWithFrame:(CGRect)aFrame
76 {
77  self = [super initWithFrame:aFrame];
78 
79  if (self)
80  {
81  _active = NO;
82  _color = [CPColor whiteColor];
83  [self setBordered:YES];
84  }
85 
86  return self;
87 }
88 
89 - (void)_registerNotifications
90 {
91  var defaultCenter = [CPNotificationCenter defaultCenter];
92 
93  [defaultCenter
94  addObserver:self
95  selector:@selector(colorWellDidBecomeExclusive:)
96  name:_CPColorWellDidBecomeExclusiveNotification
97  object:nil];
98 
99  [defaultCenter
100  addObserver:self
101  selector:@selector(colorPanelWillClose:)
102  name:CPWindowWillCloseNotification
103  object:[CPColorPanel sharedColorPanel]];
104 }
105 
106 - (void)_removeNotifications
107 {
108  var defaultCenter = [CPNotificationCenter defaultCenter];
109 
110  [defaultCenter
111  removeObserver:self
112  name:_CPColorWellDidBecomeExclusiveNotification
113  object:nil];
114 
115  [defaultCenter
116  removeObserver:self
117  name:CPWindowWillCloseNotification
118  object:[CPColorPanel sharedColorPanel]];
119 
120 }
121 
125 - (void)setBordered:(BOOL)shouldBeBordered
126 {
127  if (shouldBeBordered)
128  [self setThemeState:CPThemeStateBordered];
129  else
130  [self unsetThemeState:CPThemeStateBordered];
131 }
132 
136 - (BOOL)isBordered
137 {
138  return [self hasThemeState:CPThemeStateBordered];
139 }
140 
141 // Managing Color From Color Wells
142 
146 - (CPColor)color
147 {
148  return _color;
149 }
150 
154 - (void)setColor:(CPColor)aColor
155 {
156  if (_color == aColor)
157  return;
158 
159  _color = aColor;
160 
161  [self setNeedsLayout];
162 }
163 
168 - (void)takeColorFrom:(id)aSender
169 {
170  [self setColor:[aSender color]];
171 }
172 
173 // Activating and Deactivating Color Wells
179 - (void)activate:(BOOL)shouldBeExclusive
180 {
181  if (shouldBeExclusive)
182  // FIXME: make this queue!
184  postNotificationName:_CPColorWellDidBecomeExclusiveNotification
185  object:self];
186 
187 
188  if ([self isActive])
189  return;
190 
191  _active = YES;
192 
194  addObserver:self
196  name:CPColorPanelColorDidChangeNotification
198 }
199 
203 - (void)deactivate
204 {
205  if (![self isActive])
206  return;
207 
208  _active = NO;
209 
211  removeObserver:self
212  name:CPColorPanelColorDidChangeNotification
214 }
215 
219 - (BOOL)isActive
220 {
221  return _active;
222 }
223 
224 - (void)colorPanelDidChangeColor:(CPNotification)aNotification
225 {
226  [self takeColorFrom:[aNotification object]];
227 
228  [self sendAction:[self action] to:[self target]];
229 }
230 
231 - (void)colorWellDidBecomeExclusive:(CPNotification)aNotification
232 {
233  if (self != [aNotification object])
234  [self deactivate];
235 }
236 
237 - (void)colorPanelWillClose:(CPNotification)aNotification
238 {
239  [self deactivate];
240 }
241 
242 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
243 {
244  [self highlight:NO];
245 
246  if (!mouseIsUp || !CGRectContainsPoint([self bounds], aPoint) || ![self isEnabled])
247  return;
248 
249  [self activate:YES];
250 
251  var colorPanel = [CPColorPanel sharedColorPanel];
252 
253  [colorPanel setPlatformWindow:[[self window] platformWindow]];
254 
255  [colorPanel setColor:_color];
256  [colorPanel orderFront:self];
257 }
258 
259 - (CGRect)contentRectForBounds:(CGRect)bounds
260 {
261  var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
262 
263  return CGRectInsetByInset(bounds, contentInset);
264 }
265 
266 - (CGRect)bezelRectForBounds:(CGRect)bounds
267 {
268  var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
269 
270  return CGRectInsetByInset(bounds, bezelInset);
271 }
272 
273 - (CGRect)contentBorderRectForBounds:(CGRect)bounds
274 {
275  var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
276 
277  return CGRectInsetByInset(bounds, contentBorderInset);
278 }
279 
280 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
281 {
282  switch (aName)
283  {
284  case "bezel-view":
285  return [self bezelRectForBounds:[self bounds]];
286  case "content-view":
287  return [self contentRectForBounds:[self bounds]];
288  case "content-border-view":
289  return [self contentBorderRectForBounds:[self bounds]];
290  }
291 
292  return [super rectForEphemeralSubviewNamed:aName];
293 }
294 
295 - (CPView)createEphemeralSubviewNamed:(CPString)aName
296 {
297  var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
298 
299  [view setHitTests:NO];
300 
301  return view;
302 }
303 
304 - (void)layoutSubviews
305 {
306  var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
307  positioned:CPWindowBelow
308  relativeToEphemeralSubviewNamed:@"content-view"];
309 
310  [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
311 
312  var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
313  positioned:CPWindowAbove
314  relativeToEphemeralSubviewNamed:@"bezel-view"];
315 
316 
317  [contentView setBackgroundColor:_color];
318 
319  var contentBorderView = [self layoutEphemeralSubviewNamed:@"content-border-view"
320  positioned:CPWindowAbove
321  relativeToEphemeralSubviewNamed:@"content-view"];
322 
323  [contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
324 }
325 
326 
327 #pragma mark -
328 #pragma mark Observers method
329 
330 - (void)_addObservers
331 {
332  if (_isObserving)
333  return;
334 
335  [super _addObservers];
336  [self _registerNotifications];
337 }
338 
339 - (void)_removeObservers
340 {
341  if (!_isObserving)
342  return;
343 
344  [super _removeObservers];
345  [self _removeNotifications];
346 }
347 
348 @end
350 {
351  id __doxygen__;
352 }
353 
354 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options
355 {
356  var placeholderColor = [CPColor blackColor];
357 
358  [self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
359  [self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
360  [self _setPlaceholder:placeholderColor forMarker:CPNotApplicableMarker isDefault:YES];
361  [self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
362 }
363 
364 - (id)valueForBinding:(CPString)aBinding
365 {
366  return [_source color];
367 }
368 
369 - (void)setValue:(id)aValue forBinding:(CPString)theBinding
370 {
371  [_source setColor:aValue];
372 }
373 
374 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
375 {
376  [_source setColor:aValue];
377 }
378 
379 @end
380 
381 var CPColorWellColorKey = "CPColorWellColorKey",
382  CPColorWellBorderedKey = "CPColorWellBorderedKey";
383 
384 @implementation CPColorWell (CPCoding)
385 
390 - (id)initWithCoder:(CPCoder)aCoder
391 {
392  self = [super initWithCoder:aCoder];
393 
394  if (self)
395  {
396  _active = NO;
397  _color = [aCoder decodeObjectForKey:CPColorWellColorKey];
398  [self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
399  }
400 
401  return self;
402 }
403 
408 - (void)encodeWithCoder:(CPCoder)aCoder
409 {
410  [super encodeWithCoder:aCoder];
411 
412  [aCoder encodeObject:_color forKey:CPColorWellColorKey];
413  [aCoder encodeObject:[self isBordered] forKey:CPColorWellBorderedKey];
414 }
415 
416 @end
BOOL setThemeState:(ThemeState aState)
Definition: CPView.j:3255
CPColorPanel sharedColorPanel()
Definition: CPColorPanel.j:93
An object representation of nil.
Definition: CPNull.h:2
CGRect contentRectForBounds:(CGRect bounds)
Definition: CPColorWell.j:259
void setColor:(CPColor aColor)
Definition: CPColorWell.j:154
var CPColorWellColorKey
Definition: CPColorWell.j:381
void setBordered:(BOOL shouldBeBordered)
Definition: CPColorWell.j:125
void addObserver:selector:name:object:(id anObserver, [selector] SEL aSelector, [name] CPString aNotificationName, [object] id anObject)
CPColor whiteColor()
Definition: CPColor.j:361
id initWithFrame:(CGRect aFrame)
Definition: CPControl.j:183
CGRect bounds()
Definition: CPView.j:1326
void postNotificationName:object:(CPString aNotificationName, [object] id anObject)
CGRect bezelRectForBounds:(CGRect bounds)
Definition: CPColorWell.j:266
CGRect contentBorderRectForBounds:(CGRect bounds)
Definition: CPColorWell.j:273
CPNotificationCenter defaultCenter()
A mutable key-value pair collection.
Definition: CPDictionary.h:2
BOOL isBordered()
Definition: CPColorWell.j:136
void deactivate()
Definition: CPColorWell.j:203
CGRect bounds()
Definition: CALayer.j:203
CPWindow window()
Definition: CPView.j:527
CPColor blackColor()
Definition: CPColor.j:284
void takeColorFrom:(id aSender)
Definition: CPColorWell.j:168
An immutable string (collection of characters).
Definition: CPString.h:2
CPNull null()
Definition: CPNull.j:51
BOOL sendAction:to:(SEL anAction, [to] id anObject)
Definition: CPControl.j:319
SEL action()
Definition: CPControl.j:290
var CPColorWellBorderedKey
Definition: CPColorWell.j:382
id initWithCoder:(CPCoder aCoder)
Definition: CPControl.j:1092
void activate:(BOOL shouldBeExclusive)
Definition: CPColorWell.j:179
A notification that can be posted to a CPNotificationCenter.
Definition: CPNotification.h:2
void setNeedsLayout()
Definition: CPView.j:2748
id target()
Definition: CPControl.j:308
void highlight:(BOOL shouldHighlight)
Definition: CPControl.j:980
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
BOOL unsetThemeState:(ThemeState aState)
Definition: CPView.j:3268
Sends messages (CPNotification) between objects.
void removeObserver:name:object:(id anObserver, [name] CPString aNotificationName, [object] id anObject)
Class class()
Definition: CPObject.j:179
CPPlatformWindow platformWindow()
Definition: CPWindow.j:389
void encodeWithCoder:(CPCoder aCoder)
Definition: CPControl.j:1121
CPView layoutEphemeralSubviewNamed:positioned:relativeToEphemeralSubviewNamed:(CPString aViewName, [positioned] CPWindowOrderingMode anOrderingMode, [relativeToEphemeralSubviewNamed] CPString relativeToViewName)
Definition: CPView.j:3407
CGRect rectForEphemeralSubviewNamed:(CPString aViewName)
Definition: CPView.j:3402
Definition: CPView.j:137