API  1.0.0
CPRadio.j
Go to the documentation of this file.
1 /*
2  * CPRadio.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2009, 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 @global CPApp
27 
29 
67 @implementation CPRadio : CPButton
68 {
69  CPRadioGroup _radioGroup;
70 }
71 
72 + (id)radioWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
73 {
74  return [self buttonWithTitle:aTitle theme:aTheme];
75 }
76 
77 + (id)radioWithTitle:(CPString)aTitle
78 {
79  return [self buttonWithTitle:aTitle];
80 }
81 
82 + (CPButton)standardButtonWithTitle:(CPString)aTitle
83 {
84  var button = [[CPRadio alloc] init];
85 
86  [button setTitle:aTitle];
87 
88  return button;
89 }
90 
91 + (CPString)defaultThemeClass
92 {
93  return @"radio";
94 }
95 
96 // Designated Initializer
97 - (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
98 {
99  self = [super initWithFrame:aFrame];
100 
101  if (self)
102  {
103  [self setRadioGroup:aRadioGroup];
104 
105  [self setHighlightsBy:CPContentsCellMask];
106  [self setShowsStateBy:CPContentsCellMask];
107 
108  // Defaults?
109  [self setImagePosition:CPImageLeft];
110  [self setAlignment:CPLeftTextAlignment];
111 
112  [self setBordered:YES];
113  }
114 
115  return self;
116 }
117 
118 - (id)initWithFrame:(CGRect)aFrame
119 {
120  return [self initWithFrame:aFrame radioGroup:[CPRadioGroup new]];
121 }
122 
123 - (CPInteger)nextState
124 {
125  return CPOnState;
126 }
127 
128 - (void)setRadioGroup:(CPRadioGroup)aRadioGroup
129 {
130  if (_radioGroup === aRadioGroup)
131  return;
132 
133  [_radioGroup _removeRadio:self];
134  _radioGroup = aRadioGroup;
135  [_radioGroup _addRadio:self];
136 }
137 
138 - (CPRadioGroup)radioGroup
139 {
140  return _radioGroup;
141 }
142 
143 - (void)setObjectValue:(id)aValue
144 {
145  [super setObjectValue:aValue];
146 
147  if ([self state] === CPOnState)
148  [_radioGroup _setSelectedRadio:self];
149 }
150 
151 - (BOOL)sendAction:(SEL)anAction to:(id)anObject
152 {
153  [super sendAction:anAction to:anObject];
154 
155  if (_radioGroup)
156  [CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
157 }
158 
159 @end
160 
161 var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
162 
163 @implementation CPRadio (CPCoding)
164 
165 - (id)initWithCoder:(CPCoder)aCoder
166 {
167  self = [super initWithCoder:aCoder];
168 
169  if (self)
170  _radioGroup = [aCoder decodeObjectForKey:CPRadioRadioGroupKey];
171 
172  return self;
173 }
174 
175 - (void)encodeWithCoder:(CPCoder)aCoder
176 {
177  [super encodeWithCoder:aCoder];
178 
179  [aCoder encodeObject:_radioGroup forKey:CPRadioRadioGroupKey];
180 }
181 
182 - (CPImage)image
183 {
184  return [self currentValueForThemeAttribute:@"image"];
185 }
186 
187 - (CPImage)alternateImage
188 {
189  return [self currentValueForThemeAttribute:@"image"];
190 }
191 
192 - (BOOL)startTrackingAt:(CGPoint)aPoint
193 {
194  var startedTracking = [super startTrackingAt:aPoint];
195  [self highlight:YES];
196  return startedTracking;
197 }
198 
199 @end
200 
201 @implementation CPRadioGroup : CPObject
202 {
203  CPArray _radios;
204  CPRadio _selectedRadio;
205 
206  BOOL _enabled;
207  BOOL _hidden;
208 
209  id _target;
210  SEL _action;
211 }
212 
213 + (void)initialize
214 {
215  if (self !== [CPRadioGroup class])
216  return;
217 
218  [self exposeBinding:CPSelectedValueBinding];
219  [self exposeBinding:CPSelectedTagBinding];
220  [self exposeBinding:CPSelectedIndexBinding];
221 
222  [self exposeBinding:CPEnabledBinding];
223  [self exposeBinding:CPHiddenBinding];
224 }
225 
226 - (id)init
227 {
228  self = [super init];
229 
230  if (self)
231  {
232  _radios = [];
233  _selectedRadio = nil;
234  _enabled = YES;
235  _hidden = NO;
236  }
237 
238  return self;
239 }
240 
245 - (void)selectRadioAtIndex:(int)index
246 {
247  if (index === -1)
248  [self _setSelectedRadio:nil];
249  else
250  {
251  var radio = [_radios objectAtIndex:index];
252 
253  [self _setSelectedRadio:radio];
254  [radio setState:CPOnState];
255  }
256 }
257 
263 - (BOOL)selectRadioWithTag:(int)tag
264 {
265  var index = [_radios indexOfObjectPassingTest:function(radio)
266  {
267  return [radio tag] === tag;
268  }];
269 
270  if (index !== CPNotFound)
271  {
272  [self selectRadioAtIndex:index];
273  return YES;
274  }
275  else
276  return NO;
277 }
278 
283 - (CPRadio)selectedRadio
284 {
285  return _selectedRadio;
286 }
287 
293 - (int)selectedRadioIndex
294 {
295  return [_radios indexOfObject:_selectedRadio];
296 }
297 
298 - (CPArray)radios
299 {
300  return _radios;
301 }
302 
303 - (void)setEnabled:(BOOL)enabled
304 {
305  [_radios makeObjectsPerformSelector:@selector(setEnabled:) withObject:enabled];
306 }
307 
308 - (void)setHidden:(BOOL)hidden
309 {
310  [_radios makeObjectsPerformSelector:@selector(setHidden:) withObject:hidden];
311 }
312 
313 #pragma mark Private
314 
315 - (void)_addRadio:(CPRadio)aRadio
316 {
317  if ([_radios indexOfObject:aRadio] === CPNotFound)
318  [_radios addObject:aRadio];
319 
320  if ([aRadio state] === CPOnState)
321  [self _setSelectedRadio:aRadio];
322 }
323 
324 - (void)_removeRadio:(CPRadio)aRadio
325 {
326  if (_selectedRadio === aRadio)
327  _selectedRadio = nil;
328 
329  [_radios removeObject:aRadio];
330 }
331 
337 - (void)_selectRadioWithTitle:(CPString)aTitle
338 {
339  var index = [_radios indexOfObjectPassingTest:function(radio)
340  {
341  return [radio title] === aTitle;
342  }];
343 
344  [self selectRadioAtIndex:index];
345 }
346 
347 - (void)_setSelectedRadio:(CPRadio)aRadio
348 {
349  if (_selectedRadio === aRadio)
350  return;
351 
352  [_selectedRadio setState:CPOffState];
353 
354  _selectedRadio = aRadio;
355  [_CPRadioGroupSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
356 }
357 
358 @end
359 
360 var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
361  CPRadioGroupSelectedRadioKey = @"CPRadioGroupSelectedRadioKey";
362 
363 @implementation CPRadioGroup (CPCoding)
364 
365 - (id)initWithCoder:(CPCoder)aCoder
366 {
367  self = [super init];
368 
369  if (self)
370  {
371  _radios = [aCoder decodeObjectForKey:CPRadioGroupRadiosKey];
372  _selectedRadio = [aCoder decodeObjectForKey:CPRadioGroupSelectedRadioKey];
373  }
374 
375  return self;
376 }
377 
378 - (void)encodeWithCoder:(CPCoder)aCoder
379 {
380  [aCoder encodeObject:_radios forKey:CPRadioGroupRadiosKey];
381  [aCoder encodeObject:_selectedRadio forKey:CPRadioGroupSelectedRadioKey];
382 }
383 
384 @end
385 
387 
388 + (Class)_binderClassForBinding:(CPString)aBinding
389 {
390  if (aBinding === CPSelectedValueBinding ||
391  aBinding === CPSelectedTagBinding ||
392  aBinding === CPSelectedIndexBinding)
393  {
394  var capitalizedBinding = aBinding.charAt(0).toUpperCase() + aBinding.substr(1);
395 
396  return [CPClassFromString(@"_CPRadioGroup" + capitalizedBinding + "Binder") class];
397  }
398  else if ([aBinding hasPrefix:CPEnabledBinding])
399  return [CPMultipleValueAndBinding class];
400  else if ([aBinding hasPrefix:CPHiddenBinding])
401  return [CPMultipleValueOrBinding class];
402 
403  return [super _binderClassForBinding:aBinding];
404 }
405 
406 + (BOOL)isBindingExclusive:(CPString)aBinding
407 {
408  return (aBinding == CPSelectedIndexBinding ||
409  aBinding == CPSelectedTagBinding ||
410  aBinding == CPSelectedValueBinding);
411 }
412 
413 @end
414 @implementation _CPRadioGroupSelectionBinder : CPBinder
415 {
416  id __doxygen__;
417 }
418 
419 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
420 {
421  [self setValue:aValue forBinding:aBinding];
422 }
423 
424 @end
425 @implementation _CPRadioGroupSelectedIndexBinder : _CPRadioGroupSelectionBinder
426 {
427  id __doxygen__;
428 }
429 
430 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
431 {
432  [_source selectRadioAtIndex:aValue];
433 }
434 
435 - (id)valueForBinding:(CPString)aBinding
436 {
437  return [_source selectedRadioIndex];
438 }
439 
440 @end
441 @implementation _CPRadioGroupSelectedTagBinder : _CPRadioGroupSelectionBinder
442 {
443  id __doxygen__;
444 }
445 
446 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
447 {
448  [_source selectRadioWithTag:aValue];
449 }
450 
451 - (id)valueForBinding:(CPString)aBinding
452 {
453  return [[_source selectedRadio] tag];
454 }
455 
456 @end
457 @implementation _CPRadioGroupSelectedValueBinder : _CPRadioGroupSelectionBinder
458 {
459  id __doxygen__;
460 }
461 
462 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
463 {
464  [_source _selectRadioWithTitle:aValue];
465 }
466 
467 - (id)valueForBinding:(CPString)aBinding
468 {
469  return [[_source selectedRadio] title];
470 }
471 
472 @end
473 
475 
479 - (BOOL)enabled
480 {
481  return _enabled;
482 }
483 
487 - (BOOL)hidden
488 {
489  return _hidden;
490 }
491 
495 - (id)target
496 {
497  return _target;
498 }
499 
503 - (void)setTarget:(id)aValue
504 {
505  _target = aValue;
506 }
507 
511 - (SEL)action
512 {
513  return _action;
514 }
515 
519 - (void)setAction:(SEL)aValue
520 {
521  _action = aValue;
522 }
523 
524 @end
var CPRadioGroupRadiosKey
Definition: CPRadio.j:360
id init()
Definition: CALayer.j:126
global CPApp CPRadioImageOffset
Definition: CPRadio.j:28
void setBordered:(BOOL shouldBeBordered)
Definition: CPButton.j:768
id initWithFrame:(CGRect aFrame)
Definition: CPButton.j:161
void encodeWithCoder:(CPCoder aCoder)
Definition: CPButton.j:998
void setImagePosition:(CPCellImagePosition position)
Definition: CPControl.j:917
id buttonWithTitle:theme:(CPString aTitle, [theme] CPTheme aTheme)
Definition: CPButton.j:129
BOOL startTrackingAt:(CGPoint aPoint)
Definition: CPButton.j:551
BOOL enabled
void setObjectValue:(id anObjectValue)
Definition: CPButton.j:239
var CPRadioGroupSelectedRadioKey
Definition: CPRadio.j:361
An immutable string (collection of characters).
Definition: CPString.h:2
void setHighlightsBy:(CPInteger aMask)
Definition: CPButton.j:433
Definition: CPImage.h:2
BOOL sendAction:to:(SEL anAction, [to] id anObject)
Definition: CPControl.j:319
void selectRadioAtIndex:(int index)
Definition: CPRadio.j:245
void setRadioGroup:(CPRadioGroup aRadioGroup)
Definition: CPRadio.j:128
void exposeBinding:(CPString aBinding)
void highlight:(BOOL shouldHighlight)
Definition: CPControl.j:980
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
CPNotFound
Definition: CPObjJRuntime.j:62
void setAlignment:(CPTextAlignment alignment)
Definition: CPControl.j:776
id init()
Definition: CPObject.j:145
void setShowsStateBy:(CPInteger aMask)
Definition: CPButton.j:409
Definition: CPRadio.h:2
id new()
Definition: CPObject.j:122
id initWithFrame:radioGroup:(CGRect aFrame, [radioGroup] CPRadioGroup aRadioGroup)
Definition: CPRadio.j:97
Definition: CPTheme.h:2
id initWithCoder:(CPCoder aCoder)
Definition: CPButton.j:946
id buttonWithTitle:(CPString aTitle)
Definition: CPButton.j:124
CPOnState
Definition: CPControl.j:77
var CPRadioRadioGroupKey
Definition: CPRadio.j:161
BOOL hidden()
Definition: CALayer.j:589