API  0.9.8
 All Classes Files Functions Variables Typedefs Macros Groups Pages
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 setColor:_color];
254  [colorPanel orderFront:self];
255 }
256 
257 - (CGRect)contentRectForBounds:(CGRect)bounds
258 {
259  var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
260 
261  return CGRectInsetByInset(bounds, contentInset);
262 }
263 
264 - (CGRect)bezelRectForBounds:(CGRect)bounds
265 {
266  var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
267 
268  return CGRectInsetByInset(bounds, bezelInset);
269 }
270 
271 - (CGRect)contentBorderRectForBounds:(CGRect)bounds
272 {
273  var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
274 
275  return CGRectInsetByInset(bounds, contentBorderInset);
276 }
277 
278 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
279 {
280  switch (aName)
281  {
282  case "bezel-view":
283  return [self bezelRectForBounds:[self bounds]];
284  case "content-view":
285  return [self contentRectForBounds:[self bounds]];
286  case "content-border-view":
287  return [self contentBorderRectForBounds:[self bounds]];
288  }
289 
290  return [super rectForEphemeralSubviewNamed:aName];
291 }
292 
293 - (CPView)createEphemeralSubviewNamed:(CPString)aName
294 {
295  var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
296 
297  [view setHitTests:NO];
298 
299  return view;
300 }
301 
302 - (void)layoutSubviews
303 {
304  var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
305  positioned:CPWindowBelow
306  relativeToEphemeralSubviewNamed:@"content-view"];
307 
308  [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
309 
310  var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
311  positioned:CPWindowAbove
312  relativeToEphemeralSubviewNamed:@"bezel-view"];
313 
314 
315  [contentView setBackgroundColor:_color];
316 
317  var contentBorderView = [self layoutEphemeralSubviewNamed:@"content-border-view"
318  positioned:CPWindowAbove
319  relativeToEphemeralSubviewNamed:@"content-view"];
320 
321  [contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
322 }
323 
324 
325 #pragma mark -
326 #pragma mark Observers method
327 
328 - (void)_addObservers
329 {
330  if (_isObserving)
331  return;
332 
333  [super _addObservers];
334  [self _registerNotifications];
335 }
336 
337 - (void)_removeObservers
338 {
339  if (!_isObserving)
340  return;
341 
342  [super _removeObservers];
343  [self _removeNotifications];
344 }
345 
346 @end
348 {
349  id __doxygen__;
350 }
351 
352 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options
353 {
354  var placeholderColor = [CPColor blackColor];
355 
356  [self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
357  [self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
358  [self _setPlaceholder:placeholderColor forMarker:CPNotApplicableMarker isDefault:YES];
359  [self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
360 }
361 
362 - (id)valueForBinding:(CPString)aBinding
363 {
364  return [_source color];
365 }
366 
367 - (void)setValue:(id)aValue forBinding:(CPString)theBinding
368 {
369  [_source setColor:aValue];
370 }
371 
372 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
373 {
374  [_source setColor:aValue];
375 }
376 
377 @end
378 
379 var CPColorWellColorKey = "CPColorWellColorKey",
380  CPColorWellBorderedKey = "CPColorWellBorderedKey";
381 
382 @implementation CPColorWell (CPCoding)
383 
388 - (id)initWithCoder:(CPCoder)aCoder
389 {
390  self = [super initWithCoder:aCoder];
391 
392  if (self)
393  {
394  _active = NO;
395  _color = [aCoder decodeObjectForKey:CPColorWellColorKey];
396  [self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
397  }
398 
399  return self;
400 }
401 
406 - (void)encodeWithCoder:(CPCoder)aCoder
407 {
408  [super encodeWithCoder:aCoder];
409 
410  [aCoder encodeObject:_color forKey:CPColorWellColorKey];
411  [aCoder encodeObject:[self isBordered] forKey:CPColorWellBorderedKey];
412 }
413 
414 @end