API  0.9.7
 All Classes Files Functions Variables 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 
36 @implementation CPColorWell : CPControl
37 {
38  BOOL _active;
39  BOOL _bordered;
40 
41  CPColor _color;
42 }
43 
44 + (Class)_binderClassForBinding:(CPString)aBinding
45 {
46  if (aBinding == CPValueBinding)
47  return [CPColorWellValueBinder class];
48 
49  return [super _binderClassForBinding:aBinding];
50 }
51 
52 + (CPString)defaultThemeClass
53 {
54  return @"colorwell";
55 }
56 
57 + (CPDictionary)themeAttributes
58 {
59  return @{
60  @"bezel-inset": CGInsetMakeZero(),
61  @"bezel-color": [CPNull null],
62  @"content-inset": CGInsetMake(3.0, 3.0, 3.0, 3.0),
63  @"content-border-inset": CGInsetMakeZero(),
64  @"content-border-color": [CPNull null],
65  };
66 }
67 
68 - (void)_reverseSetBinding
69 {
70  var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
71  theBinding = [binderClass getBinding:CPValueBinding forObject:self];
72 
73  [theBinding reverseSetValueFor:@"color"];
74 }
75 
76 - (id)initWithFrame:(CGRect)aFrame
77 {
78  self = [super initWithFrame:aFrame];
79 
80  if (self)
81  {
82  _active = NO;
83  _color = [CPColor whiteColor];
84  [self setBordered:YES];
85 
86  [self _registerForNotifications];
87  }
88 
89  return self;
90 }
91 
92 - (void)_registerForNotifications
93 {
94  var defaultCenter = [CPNotificationCenter defaultCenter];
95 
96  [defaultCenter
97  addObserver:self
98  selector:@selector(colorWellDidBecomeExclusive:)
99  name:_CPColorWellDidBecomeExclusiveNotification
100  object:nil];
101 
102  [defaultCenter
103  addObserver:self
104  selector:@selector(colorPanelWillClose:)
105  name:CPWindowWillCloseNotification
106  object:[CPColorPanel sharedColorPanel]];
107 }
108 
112 - (void)setBordered:(BOOL)shouldBeBordered
113 {
114  if (shouldBeBordered)
115  [self setThemeState:CPThemeStateBordered];
116  else
117  [self unsetThemeState:CPThemeStateBordered];
118 }
119 
123 - (BOOL)isBordered
124 {
125  return [self hasThemeState:CPThemeStateBordered];
126 }
127 
128 // Managing Color From Color Wells
129 
133 - (CPColor)color
134 {
135  return _color;
136 }
137 
141 - (void)setColor:(CPColor)aColor
142 {
143  if (_color == aColor)
144  return;
145 
146  _color = aColor;
147 
148  [self setNeedsLayout];
149 }
150 
155 - (void)takeColorFrom:(id)aSender
156 {
157  [self setColor:[aSender color]];
158 }
159 
160 // Activating and Deactivating Color Wells
166 - (void)activate:(BOOL)shouldBeExclusive
167 {
168  if (shouldBeExclusive)
169  // FIXME: make this queue!
171  postNotificationName:_CPColorWellDidBecomeExclusiveNotification
172  object:self];
173 
174 
175  if ([self isActive])
176  return;
177 
178  _active = YES;
179 
181  addObserver:self
183  name:CPColorPanelColorDidChangeNotification
184  object:[CPColorPanel sharedColorPanel]];
185 }
186 
190 - (void)deactivate
191 {
192  if (![self isActive])
193  return;
194 
195  _active = NO;
196 
198  removeObserver:self
199  name:CPColorPanelColorDidChangeNotification
200  object:[CPColorPanel sharedColorPanel]];
201 }
202 
206 - (BOOL)isActive
207 {
208  return _active;
209 }
210 
211 - (void)colorPanelDidChangeColor:(CPNotification)aNotification
212 {
213  [self takeColorFrom:[aNotification object]];
214 
215  [self sendAction:[self action] to:[self target]];
216 }
217 
218 - (void)colorWellDidBecomeExclusive:(CPNotification)aNotification
219 {
220  if (self != [aNotification object])
221  [self deactivate];
222 }
223 
224 - (void)colorPanelWillClose:(CPNotification)aNotification
225 {
226  [self deactivate];
227 }
228 
229 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
230 {
231  [self highlight:NO];
232 
233  if (!mouseIsUp || !CGRectContainsPoint([self bounds], aPoint) || ![self isEnabled])
234  return;
235 
236  [self activate:YES];
237 
238  var colorPanel = [CPColorPanel sharedColorPanel];
239 
240  [colorPanel setColor:_color];
241  [colorPanel orderFront:self];
242 }
243 
244 - (CGRect)contentRectForBounds:(CGRect)bounds
245 {
246  var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
247 
248  return CGRectInsetByInset(bounds, contentInset);
249 }
250 
251 - (CGRect)bezelRectForBounds:(CGRect)bounds
252 {
253  var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
254 
255  return CGRectInsetByInset(bounds, bezelInset);
256 }
257 
258 - (CGRect)contentBorderRectForBounds:(CGRect)bounds
259 {
260  var contentBorderInset = [self currentValueForThemeAttribute:@"content-border-inset"];
261 
262  return CGRectInsetByInset(bounds, contentBorderInset);
263 }
264 
265 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
266 {
267  switch (aName)
268  {
269  case "bezel-view":
270  return [self bezelRectForBounds:[self bounds]];
271  case "content-view":
272  return [self contentRectForBounds:[self bounds]];
273  case "content-border-view":
274  return [self contentBorderRectForBounds:[self bounds]];
275  }
276 
277  return [super rectForEphemeralSubviewNamed:aName];
278 }
279 
280 - (CPView)createEphemeralSubviewNamed:(CPString)aName
281 {
282  var view = [[CPView alloc] initWithFrame:CGRectMakeZero()];
283 
284  [view setHitTests:NO];
285 
286  return view;
287 }
288 
289 - (void)layoutSubviews
290 {
291  var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
292  positioned:CPWindowBelow
293  relativeToEphemeralSubviewNamed:@"content-view"];
294 
295  [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
296 
297  var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
298  positioned:CPWindowAbove
299  relativeToEphemeralSubviewNamed:@"bezel-view"];
300 
301 
302  [contentView setBackgroundColor:_color];
303 
304  var contentBorderView = [self layoutEphemeralSubviewNamed:@"content-border-view"
305  positioned:CPWindowAbove
306  relativeToEphemeralSubviewNamed:@"content-view"];
307 
308  [contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
309 }
310 
311 @end
313 {
314  id __doxygen__;
315 }
316 
317 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options
318 {
319  var placeholderColor = [CPColor blackColor];
320 
321  [self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
322  [self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
323  [self _setPlaceholder:placeholderColor forMarker:CPNotApplicableMarker isDefault:YES];
324  [self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
325 }
326 
327 - (id)valueForBinding:(CPString)aBinding
328 {
329  return [_source color];
330 }
331 
332 - (void)setValue:(id)aValue forBinding:(CPString)theBinding
333 {
334  [_source setColor:aValue];
335 }
336 
337 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
338 {
339  [_source setColor:aValue];
340 }
341 
342 @end
343 
344 var CPColorWellColorKey = "CPColorWellColorKey",
345  CPColorWellBorderedKey = "CPColorWellBorderedKey";
346 
347 @implementation CPColorWell (CPCoding)
348 
353 - (id)initWithCoder:(CPCoder)aCoder
354 {
355  self = [super initWithCoder:aCoder];
356 
357  if (self)
358  {
359  _active = NO;
360  _color = [aCoder decodeObjectForKey:CPColorWellColorKey];
361  [self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
362 
363  [self _registerForNotifications];
364  }
365 
366  return self;
367 }
368 
373 - (void)encodeWithCoder:(CPCoder)aCoder
374 {
375  [super encodeWithCoder:aCoder];
376 
377  [aCoder encodeObject:_color forKey:CPColorWellColorKey];
378  [aCoder encodeObject:[self isBordered] forKey:CPColorWellBorderedKey];
379 }
380 
381 @end