API 0.9.5
AppKit/CPButton.j
Go to the documentation of this file.
00001 /*
00002  * CPButton.j
00003  * AppKit
00004  *
00005  * Created by Francisco Tolmasky.
00006  * Copyright 2008, 280 North, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 
00024 
00025 
00026 /* @group CPBezelStyle */
00027 
00028 CPRoundedBezelStyle             = 1;
00029 CPRegularSquareBezelStyle       = 2;
00030 CPThickSquareBezelStyle         = 3;
00031 CPThickerSquareBezelStyle       = 4;
00032 CPDisclosureBezelStyle          = 5;
00033 CPShadowlessSquareBezelStyle    = 6;
00034 CPCircularBezelStyle            = 7;
00035 CPTexturedSquareBezelStyle      = 8;
00036 CPHelpButtonBezelStyle          = 9;
00037 CPSmallSquareBezelStyle         = 10;
00038 CPTexturedRoundedBezelStyle     = 11;
00039 CPRoundRectBezelStyle           = 12;
00040 CPRecessedBezelStyle            = 13;
00041 CPRoundedDisclosureBezelStyle   = 14;
00042 CPHUDBezelStyle                 = -1;
00043 
00044 
00045 /* @group CPButtonType */
00046 CPMomentaryLightButton  = 0;
00047 CPPushOnPushOffButton   = 1;
00048 CPToggleButton          = 2;
00049 CPSwitchButton          = 3; // Deprecated, use CPCheckBox instead.
00050 CPRadioButton           = 4; // Deprecated, use CPRadio instead.
00051 CPMomentaryChangeButton = 5;
00052 CPOnOffButton           = 6;
00053 CPMomentaryPushInButton = 7;
00054 CPMomentaryPushButton   = 0;
00055 CPMomentaryLight        = 7;
00056 
00057 CPNoButtonMask              = 0;
00058 CPContentsButtonMask        = 1;
00059 CPPushInButtonMask          = 2;
00060 CPGrayButtonMask            = 4;
00061 CPBackgroundButtonMask      = 8;
00062 
00063 CPNoCellMask                = CPNoButtonMask;
00064 CPContentsCellMask          = CPContentsButtonMask;
00065 CPPushInCellMask            = CPPushInButtonMask;
00066 CPChangeGrayCellMask        = CPGrayButtonMask;
00067 CPChangeBackgroundCellMask  = CPBackgroundButtonMask;
00068 
00069 CPButtonStateMixed                  = CPThemeState("mixed");
00070 CPButtonStateBezelStyleRounded      = CPThemeState("rounded");
00071 
00072 // add all future correspondance between bezel styles and theme state here.
00073 var CPButtonBezelStyleStateMap = [CPDictionary dictionaryWithObjects:[CPButtonStateBezelStyleRounded, nil]
00074                                                              forKeys:[CPRoundedBezelStyle, CPRoundRectBezelStyle]];
00075 
00076 
00077 CPButtonDefaultHeight = 24.0;
00078 CPButtonImageOffset   = 3.0;
00079 
00088 @implementation CPButton : CPControl
00089 {
00090     BOOL                _allowsMixedState;
00091 
00092     CPString            _title;
00093     CPString            _alternateTitle;
00094 
00095     CPInteger           _showsStateBy;
00096     CPInteger           _highlightsBy;
00097     BOOL                _imageDimsWhenDisabled;
00098 
00099     // NS-style Display Properties
00100     CPBezelStyle        _bezelStyle;
00101     CPControlSize       _controlSize;
00102 
00103     CPString            _keyEquivalent;
00104     unsigned            _keyEquivalentModifierMask;
00105 
00106     CPTimer             _continuousDelayTimer;
00107     CPTimer             _continuousTimer;
00108     float               _periodicDelay;
00109     float               _periodicInterval;
00110 }
00111 
00112 + (id)buttonWithTitle:(CPString)aTitle
00113 {
00114     return [self buttonWithTitle:aTitle theme:[CPTheme defaultTheme]];
00115 }
00116 
00117 + (id)buttonWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
00118 {
00119     var button = [[self alloc] init];
00120 
00121     [button setTheme:aTheme];
00122     [button setTitle:aTitle];
00123     [button sizeToFit];
00124 
00125     return button;
00126 }
00127 
00128 + (CPString)defaultThemeClass
00129 {
00130     return @"button";
00131 }
00132 
00133 + (id)themeAttributes
00134 {
00135     return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
00136                                        forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
00137 }
00138 
00144 - (id)initWithFrame:(CGRect)aFrame
00145 {
00146     self = [super initWithFrame:aFrame];
00147 
00148     if (self)
00149     {
00150         // Should we instead override the defaults?
00151         [self setValue:CPCenterTextAlignment forThemeAttribute:@"alignment"];
00152         [self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
00153         [self setValue:CPImageLeft forThemeAttribute:@"image-position"];
00154         [self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
00155 
00156         [self setBezelStyle:CPRoundRectBezelStyle];
00157         [self setBordered:YES];
00158 
00159         [self _init];
00160     }
00161 
00162     return self;
00163 }
00164 
00165 - (void)_init
00166 {
00167     _controlSize = CPRegularControlSize;
00168 
00169     _keyEquivalent = @"";
00170     _keyEquivalentModifierMask = 0;
00171 
00172     // Continuous button defaults.
00173     _periodicInterval   = 0.05;
00174     _periodicDelay      = 0.5;
00175 }
00176 
00177 // Setting the state
00182 - (BOOL)allowsMixedState
00183 {
00184     return _allowsMixedState;
00185 }
00186 
00191 - (void)setAllowsMixedState:(BOOL)aFlag
00192 {
00193     aFlag = !!aFlag;
00194 
00195     if (_allowsMixedState === aFlag)
00196         return;
00197 
00198     _allowsMixedState = aFlag;
00199 
00200     if (!_allowsMixedState && [self state] === CPMixedState)
00201         [self setState:CPOnState];
00202 }
00203 
00208 - (void)setObjectValue:(id)anObjectValue
00209 {
00210     if (!anObjectValue || anObjectValue === @"" || ([anObjectValue intValue] === 0))
00211         anObjectValue = CPOffState;
00212 
00213     else if (![anObjectValue isKindOfClass:[CPNumber class]])
00214         anObjectValue = CPOnState;
00215 
00216     else if (anObjectValue >= CPOnState)
00217         anObjectValue = CPOnState
00218 
00219     else if (anObjectValue < CPOffState)
00220         if ([self allowsMixedState])
00221             anObjectValue = CPMixedState;
00222 
00223         else
00224             anObjectValue = CPOnState;
00225 
00226     [super setObjectValue:anObjectValue];
00227 
00228     switch ([self objectValue])
00229     {
00230         case CPMixedState:  [self unsetThemeState:CPThemeStateSelected];
00231                             [self setThemeState:CPButtonStateMixed];
00232                             break;
00233 
00234         case CPOnState:     [self unsetThemeState:CPButtonStateMixed];
00235                             [self setThemeState:CPThemeStateSelected];
00236                             break;
00237 
00238         case CPOffState:    [self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed];
00239     }
00240 }
00241 
00249 - (CPInteger)nextState
00250 {
00251    if ([self allowsMixedState])
00252    {
00253       var value = [self state];
00254 
00255       return value - ((value === -1) ? -2 : 1);
00256    }
00257 
00258     return 1 - [self state];
00259 }
00260 
00266 - (void)setNextState
00267 {
00268     if ([self infoForBinding:CPValueBinding])
00269         [self setAllowsMixedState:NO];
00270 
00271     [self setState:[self nextState]];
00272 }
00273 
00279 - (void)setState:(CPInteger)aState
00280 {
00281     [self setIntValue:aState];
00282 }
00283 
00287 - (CPInteger)state
00288 {
00289     return [self intValue];
00290 }
00291 
00297 - (void)setTitle:(CPString)aTitle
00298 {
00299     if (_title === aTitle)
00300         return;
00301 
00302     _title = aTitle;
00303 
00304     [self setNeedsLayout];
00305     [self setNeedsDisplay:YES];
00306 }
00307 
00313 - (CPString)title
00314 {
00315     return _title;
00316 }
00317 
00318 - (void)setAlternateTitle:(CPString)aTitle
00319 {
00320     if (_alternateTitle === aTitle)
00321         return;
00322 
00323     _alternateTitle = aTitle;
00324 
00325     [self setNeedsLayout];
00326     [self setNeedsDisplay:YES];
00327 }
00328 
00329 - (CPString)alternateTitle
00330 {
00331     return _alternateTitle;
00332 }
00333 
00334 - (void)setImage:(CPImage)anImage
00335 {
00336     [self setValue:anImage forThemeAttribute:@"image"];
00337 }
00338 
00339 - (CPImage)image
00340 {
00341     return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
00342 }
00343 
00348 - (void)setAlternateImage:(CPImage)anImage
00349 {
00350     [self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
00351 }
00352 
00356 - (CPImage)alternateImage
00357 {
00358     return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
00359 }
00360 
00361 - (void)setImageOffset:(float)theImageOffset
00362 {
00363     [self setValue:theImageOffset forThemeAttribute:@"image-offset"];
00364 }
00365 
00366 - (float)imageOffset
00367 {
00368     return [self valueForThemeAttribute:@"image-offset"];
00369 }
00370 
00371 - (void)setShowsStateBy:(CPInteger)aMask
00372 {
00373     if (_showsStateBy === aMask)
00374         return;
00375 
00376     _showsStateBy = aMask;
00377 
00378     [self setNeedsDisplay:YES];
00379     [self setNeedsLayout];
00380 }
00381 
00382 - (CPInteger)showsStateBy
00383 {
00384     return _showsStateBy;
00385 }
00386 
00387 - (void)setHighlightsBy:(CPInteger)aMask
00388 {
00389     if (_highlightsBy === aMask)
00390         return;
00391 
00392     _highlightsBy = aMask;
00393 
00394     if ([self hasThemeState:CPThemeStateHighlighted])
00395     {
00396         [self setNeedsDisplay:YES];
00397         [self setNeedsLayout];
00398     }
00399 }
00400 
00401 - (void)setButtonType:(CPButtonType)aButtonType
00402 {
00403     switch (aButtonType)
00404     {
00405         case CPMomentaryLightButton:    [self setHighlightsBy:CPChangeBackgroundCellMask];
00406                                         [self setShowsStateBy:CPNoCellMask];
00407                                         break;
00408 
00409         case CPMomentaryPushInButton:   [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
00410                                         [self setShowsStateBy:CPNoCellMask];
00411                                         break;
00412 
00413         case CPMomentaryChangeButton:   [self setHighlightsBy:CPContentsCellMask];
00414                                         [self setShowsStateBy:CPNoCellMask];
00415                                         break;
00416 
00417         case CPPushOnPushOffButton:     [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
00418                                         [self setShowsStateBy:CPChangeBackgroundCellMask];
00419                                         break;
00420 
00421         case CPOnOffButton:             [self setHighlightsBy:CPChangeBackgroundCellMask];
00422                                         [self setShowsStateBy:CPChangeBackgroundCellMask];
00423                                         break;
00424 
00425         case CPToggleButton:            [self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
00426                                         [self setShowsStateBy:CPContentsCellMask];
00427                                         break;
00428 
00429         case CPSwitchButton:            [CPException raise:CPInvalidArgumentException
00430                                                     reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
00431 
00432         case CPRadioButton:             [CPException raise:CPInvalidArgumentException
00433                                                     reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
00434 
00435         default:                        [CPException raise:CPInvalidArgumentException
00436                                                     reason:"Unknown button type."];
00437     }
00438 
00439     [self setImageDimsWhenDisabled:YES];
00440 }
00441 
00442 - (void)setImageDimsWhenDisabled:(BOOL)imageShouldDimWhenDisabled
00443 {
00444     imageShouldDimWhenDisabled = !!imageShouldDimWhenDisabled;
00445 
00446     if (_imageDimsWhenDisabled === imageShouldDimWhenDisabled)
00447         return;
00448 
00449     _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
00450 
00451     if ([self hasThemeState:CPThemeStateDisabled])
00452     {
00453         [self setNeedsDisplay:YES];
00454         [self setNeedsLayout];
00455     }
00456 }
00457 
00458 - (BOOL)imageDimsWhenDisabled
00459 {
00460     return _imageDimsWhenDisabled;
00461 }
00462 
00463 - (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
00464 {
00465     _periodicDelay      = aDelay;
00466     _periodicInterval   = anInterval;
00467 }
00468 
00469 - (void)mouseDown:(CPEvent)anEvent
00470 {
00471     if ([self isContinuous])
00472     {
00473         _continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
00474         {
00475             if (!_continuousTimer)
00476                 _continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
00477         }
00478 
00479         repeats:NO];
00480     }
00481 
00482     [super mouseDown:anEvent];
00483 }
00484 
00485 - (void)onContinousEvent:(CPTimer)aTimer
00486 {
00487     if (_target && _action && [_target respondsToSelector:_action])
00488         [_target performSelector:_action withObject:self];
00489 }
00490 
00491 - (BOOL)startTrackingAt:(CGPoint)aPoint
00492 {
00493     [self highlight:YES];
00494 
00495     return [super startTrackingAt:aPoint];
00496 }
00497 
00498 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
00499 {
00500     [self highlight:NO];
00501     [self invalidateTimers];
00502 
00503     [super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
00504 
00505     if (mouseIsUp && CGRectContainsPoint([self bounds], aPoint))
00506         [self setNextState];
00507 }
00508 
00509 - (void)invalidateTimers
00510 {
00511     if (_continuousTimer)
00512     {
00513         [_continuousTimer invalidate];
00514         _continuousTimer = nil;
00515     }
00516 
00517     if (_continuousDelayTimer)
00518     {
00519         [_continuousDelayTimer invalidate];
00520         _continuousDelayTimer = nil;
00521     }
00522 }
00523 
00524 - (CGRect)contentRectForBounds:(CGRect)bounds
00525 {
00526     var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
00527 
00528     if (_CGInsetIsEmpty(contentInset))
00529         return bounds;
00530 
00531     bounds = _CGRectMakeCopy(bounds);
00532     bounds.origin.x += contentInset.left;
00533     bounds.origin.y += contentInset.top;
00534     bounds.size.width -= contentInset.left + contentInset.right;
00535     bounds.size.height -= contentInset.top + contentInset.bottom;
00536 
00537     return bounds;
00538 }
00539 
00540 - (CGRect)bezelRectForBounds:(CGRect)bounds
00541 {
00542     if (![self isBordered])
00543         return _CGRectMakeZero();
00544 
00545     var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
00546 
00547     if (_CGInsetIsEmpty(bezelInset))
00548         return bounds;
00549 
00550     bounds = _CGRectMakeCopy(bounds);
00551     bounds.origin.x += bezelInset.left;
00552     bounds.origin.y += bezelInset.top;
00553     bounds.size.width -= bezelInset.left + bezelInset.right;
00554     bounds.size.height -= bezelInset.top + bezelInset.bottom;
00555 
00556     return bounds;
00557 }
00558 
00559 - (CGSize)_minimumFrameSize
00560 {
00561     var size = CGSizeMakeZero(),
00562         contentView = [self ephemeralSubviewNamed:@"content-view"];
00563 
00564     if (contentView)
00565     {
00566         [contentView sizeToFit];
00567         size = [contentView frameSize];
00568     }
00569     else
00570         size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
00571 
00572     var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
00573         minSize = [self currentValueForThemeAttribute:@"min-size"],
00574         maxSize = [self currentValueForThemeAttribute:@"max-size"];
00575 
00576     size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
00577     size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
00578 
00579     if (maxSize.width >= 0.0)
00580         size.width = MIN(size.width, maxSize.width);
00581 
00582     if (maxSize.height >= 0.0)
00583         size.height = MIN(size.height, maxSize.height);
00584 
00585     return size;
00586 }
00587 
00591 - (void)sizeToFit
00592 {
00593     [self layoutSubviews];
00594 
00595     [self setFrameSize:[self _minimumFrameSize]];
00596 
00597     if ([self ephemeralSubviewNamed:@"content-view"])
00598         [self layoutSubviews];
00599 }
00600 
00601 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
00602 {
00603     if (aName === "bezel-view")
00604         return [self bezelRectForBounds:[self bounds]];
00605 
00606     else if (aName === "content-view")
00607         return [self contentRectForBounds:[self bounds]];
00608 
00609     return [super rectForEphemeralSubviewNamed:aName];
00610 }
00611 
00612 - (CPView)createEphemeralSubviewNamed:(CPString)aName
00613 {
00614     if (aName === "bezel-view")
00615     {
00616         var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
00617 
00618         [view setHitTests:NO];
00619 
00620         return view;
00621     }
00622     else
00623         return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
00624 }
00625 
00626 - (void)layoutSubviews
00627 {
00628     var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
00629                                            positioned:CPWindowBelow
00630                       relativeToEphemeralSubviewNamed:@"content-view"];
00631 
00632     [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
00633 
00634     var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
00635                                              positioned:CPWindowAbove
00636                         relativeToEphemeralSubviewNamed:@"bezel-view"];
00637 
00638     if (contentView)
00639     {
00640         [contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
00641         [contentView setImage:[self currentValueForThemeAttribute:@"image"]];
00642         [contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
00643 
00644         [contentView setFont:[self currentValueForThemeAttribute:@"font"]];
00645         [contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
00646         [contentView setAlignment:[self currentValueForThemeAttribute:@"alignment"]];
00647         [contentView setVerticalAlignment:[self currentValueForThemeAttribute:@"vertical-alignment"]];
00648         [contentView setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
00649         [contentView setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
00650         [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
00651         [contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
00652         [contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
00653         [contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
00654     }
00655 }
00656 
00657 - (void)setBordered:(BOOL)shouldBeBordered
00658 {
00659     if (shouldBeBordered)
00660         [self setThemeState:CPThemeStateBordered];
00661     else
00662         [self unsetThemeState:CPThemeStateBordered];
00663 }
00664 
00665 - (BOOL)isBordered
00666 {
00667     return [self hasThemeState:CPThemeStateBordered];
00668 }
00669 
00676 - (void)setKeyEquivalent:(CPString)aString
00677 {
00678     _keyEquivalent = aString || @"";
00679 
00680     // Check if the key equivalent is the enter key
00681     // Treat \r and \n as the same key equivalent. See issue #710.
00682     if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
00683         [self setThemeState:CPThemeStateDefault];
00684     else
00685         [self unsetThemeState:CPThemeStateDefault];
00686 }
00687 
00688 - (void)viewWillMoveToWindow:(CPWindow)aWindow
00689 {
00690     var selfWindow = [self window];
00691 
00692     if (selfWindow === aWindow || aWindow === nil)
00693         return;
00694 
00695     if ([selfWindow defaultButton] === self)
00696         [selfWindow setDefaultButton:nil];
00697 
00698     if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
00699         [aWindow setDefaultButton:self];
00700 }
00701 
00705 - (CPString)keyEquivalent
00706 {
00707     return _keyEquivalent;
00708 }
00709 
00713 - (void)setKeyEquivalentModifierMask:(unsigned)aMask
00714 {
00715     _keyEquivalentModifierMask = aMask;
00716 }
00717 
00721 - (unsigned)keyEquivalentModifierMask
00722 {
00723     return _keyEquivalentModifierMask;
00724 }
00725 
00730 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
00731 {
00732     // Don't handle the key equivalent for the default window because the window will handle it for us
00733     if ([[self window] defaultButton] === self)
00734         return NO;
00735 
00736     if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
00737         return NO;
00738 
00739     [self performClick:nil];
00740     return YES;
00741 }
00742 
00743 @end
00744 
00745 @implementation CPButton (NS)
00746 
00747 - (void)setBezelStyle:(unsigned)aBezelStyle
00748 {
00749     if (aBezelStyle === _bezelStyle)
00750         return;
00751 
00752     var currentState = [CPButtonBezelStyleStateMap objectForKey:_bezelStyle],
00753         newState = [CPButtonBezelStyleStateMap objectForKey:aBezelStyle];
00754 
00755     if (currentState)
00756         [self unsetThemeState:currentState];
00757 
00758     if (newState)
00759         [self setThemeState:newState];
00760 
00761     _bezelStyle = aBezelStyle;
00762 }
00763 
00764 - (unsigned)bezelStyle
00765 {
00766     return _bezelStyle;
00767 }
00768 
00769 @end
00770 
00771 
00772 var CPButtonImageKey                    = @"CPButtonImageKey",
00773     CPButtonAlternateImageKey           = @"CPButtonAlternateImageKey",
00774     CPButtonTitleKey                    = @"CPButtonTitleKey",
00775     CPButtonAlternateTitleKey           = @"CPButtonAlternateTitleKey",
00776     CPButtonIsBorderedKey               = @"CPButtonIsBorderedKey",
00777     CPButtonAllowsMixedStateKey         = @"CPButtonAllowsMixedStateKey",
00778     CPButtonImageDimsWhenDisabledKey    = @"CPButtonImageDimsWhenDisabledKey",
00779     CPButtonImagePositionKey            = @"CPButtonImagePositionKey",
00780     CPButtonKeyEquivalentKey            = @"CPButtonKeyEquivalentKey",
00781     CPButtonKeyEquivalentMaskKey        = @"CPButtonKeyEquivalentMaskKey",
00782     CPButtonPeriodicDelayKey            = @"CPButtonPeriodicDelayKey",
00783     CPButtonPeriodicIntervalKey         = @"CPButtonPeriodicIntervalKey";
00784 
00785 @implementation CPButton (CPCoding)
00786 
00791 - (id)initWithCoder:(CPCoder)aCoder
00792 {
00793     self = [super initWithCoder:aCoder];
00794 
00795     if (self)
00796     {
00797         [self _init];
00798 
00799         _title = [aCoder decodeObjectForKey:CPButtonTitleKey];
00800         _alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
00801 
00802         if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
00803             _allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
00804 
00805         [self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
00806 
00807         if ([aCoder containsValueForKey:CPButtonImagePositionKey])
00808             [self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
00809 
00810         if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
00811             [self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
00812 
00813         if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
00814             _periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
00815 
00816         if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
00817             _periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
00818 
00819         _keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
00820 
00821         [self setNeedsLayout];
00822         [self setNeedsDisplay:YES];
00823     }
00824 
00825     return self;
00826 }
00827 
00832 - (void)encodeWithCoder:(CPCoder)aCoder
00833 {
00834     [super encodeWithCoder:aCoder];
00835     [self invalidateTimers];
00836 
00837     [aCoder encodeObject:_title forKey:CPButtonTitleKey];
00838     [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
00839 
00840     [aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
00841 
00842     [aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
00843     [aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
00844 
00845     if (_keyEquivalent)
00846         [aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
00847 
00848     [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
00849 
00850     [aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
00851     [aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
00852 }
00853 
00854 @end
00855 
 All Classes Files Functions Variables Defines