91 BOOL _allowsMixedState;
96 CPInteger _showsStateBy;
97 CPInteger _highlightsBy;
98 BOOL _imageDimsWhenDisabled;
101 CPBezelStyle _bezelStyle;
102 CPControlSize _controlSize;
105 unsigned _keyEquivalentModifierMask;
109 float _periodicDelay;
110 float _periodicInterval;
122 var button = [[
self alloc] init];
124 [button setTheme:aTheme];
125 [button setTitle:aTitle];
136 + (id)themeAttributes
139 forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
147 - (id)initWithFrame:(CGRect)aFrame
172 _keyEquivalent =
@"";
173 _keyEquivalentModifierMask = 0;
176 _periodicInterval = 0.05;
177 _periodicDelay = 0.5;
179 [
self setButtonType:CPMomentaryPushInButton];
187 - (BOOL)allowsMixedState
189 return _allowsMixedState;
196 - (void)setAllowsMixedState:(BOOL)aFlag
200 if (_allowsMixedState === aFlag)
203 _allowsMixedState = aFlag;
205 if (!_allowsMixedState && [
self state] ===
CPMixedState)
213 - (void)setObjectValue:(
id)anObjectValue
215 if (!anObjectValue || anObjectValue ===
@"" || ([anObjectValue intValue] === 0))
217 else if (![anObjectValue isKindOfClass:[
CPNumber class]])
222 if ([
self allowsMixedState])
229 switch ([
self objectValue])
250 [
self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed | CPThemeStateHighlighted];
261 - (CPInteger)nextState
263 if ([
self allowsMixedState])
265 var value = [
self state];
267 return value - ((value === -1) ? -2 : 1);
270 return 1 - [
self state];
291 - (void)setState:(CPInteger)aState
311 if (_title === aTitle)
332 if (_alternateTitle === aTitle)
335 _alternateTitle = aTitle;
343 return _alternateTitle;
373 - (void)setImageOffset:(
float)theImageOffset
383 - (void)setShowsStateBy:(CPInteger)aMask
388 if (_showsStateBy === aMask)
391 _showsStateBy = aMask;
402 - (CPInteger)showsStateBy
404 return _showsStateBy;
407 - (void)setHighlightsBy:(CPInteger)aMask
409 if (_highlightsBy === aMask)
412 _highlightsBy = aMask;
421 - (CPInteger)highlightsBy
423 return _highlightsBy;
426 - (void)setButtonType:(CPButtonType)aButtonType
443 [
self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
447 [
self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
455 reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
458 reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
461 reason:"Unknown button type."];
467 - (void)setImageDimsWhenDisabled:(BOOL)imageShouldDimWhenDisabled
469 imageShouldDimWhenDisabled = !!imageShouldDimWhenDisabled;
471 if (_imageDimsWhenDisabled === imageShouldDimWhenDisabled)
474 _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
483 - (BOOL)imageDimsWhenDisabled
485 return _imageDimsWhenDisabled;
488 - (void)setPeriodicDelay:(
float)aDelay interval:(
float)anInterval
490 _periodicDelay = aDelay;
491 _periodicInterval = anInterval;
496 if ([
self isContinuous])
500 if (!_continuousTimer)
512 if (_target && _action && [_target respondsToSelector:_action])
513 [_target performSelector:_action withObject:self];
516 - (BOOL)startTrackingAt:(CGPoint)aPoint
535 return startedTracking;
538 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
542 if (mouseIsUp && CGRectContainsPoint([
self bounds], aPoint))
557 - (void)invalidateTimers
559 if (_continuousTimer)
561 [_continuousTimer invalidate];
562 _continuousTimer = nil;
565 if (_continuousDelayTimer)
567 [_continuousDelayTimer invalidate];
568 _continuousDelayTimer = nil;
572 - (CGRect)contentRectForBounds:(CGRect)bounds
576 return _CGRectInsetByInset(bounds, contentInset);
579 - (CGRect)bezelRectForBounds:(CGRect)bounds
582 if (![
self isBordered])
587 return _CGRectInsetByInset(bounds, bezelInset);
590 - (CGSize)_minimumFrameSize
592 var size = CGSizeMakeZero(),
593 contentView = [
self ephemeralSubviewNamed:@"content-view"];
597 [contentView sizeToFit];
598 size = [contentView frameSize];
601 size = [([
self title] || " ") sizeWithFont:[
self currentValueForThemeAttribute:@"font"]];
603 var contentInset = [
self currentValueForThemeAttribute:@"content-inset"],
604 minSize = [
self currentValueForThemeAttribute:@"min-size"],
605 maxSize = [
self currentValueForThemeAttribute:@"max-size"];
607 size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
608 size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
610 if (maxSize.width >= 0.0)
611 size.width = MIN(size.width, maxSize.width);
613 if (maxSize.height >= 0.0)
614 size.height = MIN(size.height, maxSize.height);
628 if ([
self ephemeralSubviewNamed:
@"content-view"])
632 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
634 if (aName ===
"bezel-view")
637 else if (aName ===
"content-view")
645 if (aName ===
"bezel-view")
647 var view = [[
CPView alloc] initWithFrame:_CGRectMakeZero()];
649 [view setHitTests:NO];
654 return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
657 - (void)layoutSubviews
678 if (_showsStateBy & CPContentsCellMask)
680 title = ([
self state] ==
CPOffState && _alternateTitle) ? _alternateTitle : _title;
689 else if (_showsStateBy & CPContentsCellMask)
691 title = ([
self state] !=
CPOffState && _alternateTitle) ? _alternateTitle : _title;
697 image = [
self image];
704 title = ([
self state] !=
CPOffState && _alternateTitle) ? _alternateTitle : _title;
710 image = [
self image];
714 [contentView setText:title];
715 [contentView setImage:image];
727 [contentView setDimsImage:[
self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
731 - (void)setBordered:(BOOL)shouldBeBordered
733 if (shouldBeBordered)
752 _keyEquivalent = aString ||
@"";
764 var selfWindow = [
self window];
766 if (selfWindow === aWindow || aWindow === nil)
769 if ([selfWindow defaultButton] ===
self)
770 [selfWindow setDefaultButton:nil];
781 return _keyEquivalent;
787 - (void)setKeyEquivalentModifierMask:(
unsigned)aMask
789 _keyEquivalentModifierMask = aMask;
795 - (unsigned)keyEquivalentModifierMask
797 return _keyEquivalentModifierMask;
807 if ([[
self window] defaultButton] ===
self)
810 if (![anEvent _triggersKeyEquivalent:[
self keyEquivalent] withModifierMask:[
self keyEquivalentModifierMask]])
823 - (void)performClick:(
id)sender
827 if (![
self isEnabled])
832 var shouldHighlight = NO;
839 shouldHighlight = YES;
863 - (void)setBezelStyle:(
unsigned)aBezelStyle
865 if (aBezelStyle === _bezelStyle)
868 var currentState = [CPButtonBezelStyleStateMap objectForKey:_bezelStyle],
869 newState = [CPButtonBezelStyleStateMap objectForKey:aBezelStyle];
877 _bezelStyle = aBezelStyle;
880 - (unsigned)bezelStyle
917 _title = [aCoder decodeObjectForKey:CPButtonTitleKey];
918 _alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
919 _allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
924 _highlightsBy = [aCoder decodeIntForKey:CPButtonHighlightsByKey];
925 _showsStateBy = [aCoder decodeIntForKey:CPButtonShowsStateByKey];
940 [
self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
943 _periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
946 _periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
948 _keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
966 [aCoder encodeObject:_title forKey:CPButtonTitleKey];
967 [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
969 [aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
971 [aCoder encodeInt:_highlightsBy forKey:CPButtonHighlightsByKey];
972 [aCoder encodeInt:_showsStateBy forKey:CPButtonShowsStateByKey];
975 [aCoder encodeInt:[
self imagePosition] forKey:CPButtonImagePositionKey];
978 [aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
980 [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
982 [aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
983 [aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];