80 CPButtonDefaultHeight = 25.0;
81 CPButtonImageOffset = 3.0;
93 BOOL _allowsMixedState;
98 CPInteger _showsStateBy;
99 CPInteger _highlightsBy;
100 BOOL _imageDimsWhenDisabled;
103 CPBezelStyle _bezelStyle;
106 unsigned _keyEquivalentModifierMask;
110 float _periodicDelay;
111 float _periodicInterval;
116 + (Class)_binderClassForBinding:(
CPString)aBinding
118 if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
121 return [
super _binderClassForBinding:aBinding];
131 var button = [[
self alloc] init];
133 [button setTheme:aTheme];
134 [button setTitle:aTitle];
149 @"image-offset": 0.0,
150 @"bezel-inset": CGInsetMakeZero(),
151 @"content-inset": CGInsetMakeZero(),
161 - (id)initWithFrame:(CGRect)aFrame
184 _keyEquivalent =
@"";
185 _keyEquivalentModifierMask = 0;
188 _periodicInterval = 0.05;
189 _periodicDelay = 0.5;
191 [
self setButtonType:CPMomentaryPushInButton];
195 #pragma mark Control Size 197 - (void)setControlSize:(CPControlSize)aControlSize
201 if ([
self isBordered])
202 [
self _sizeToControlSize];
213 - (BOOL)allowsMixedState
215 return _allowsMixedState;
222 - (void)setAllowsMixedState:(BOOL)aFlag
226 if (_allowsMixedState === aFlag)
229 _allowsMixedState = aFlag;
231 if (!_allowsMixedState && [
self state] ===
CPMixedState)
239 - (void)setObjectValue:(
id)anObjectValue
241 if (!anObjectValue || anObjectValue ===
@"" || ([anObjectValue intValue] === 0))
243 else if (![anObjectValue isKindOfClass:[
CPNumber class]])
248 if ([
self allowsMixedState])
255 switch ([
self objectValue])
276 [
self unsetThemeStates:[CPThemeStateSelected, CPButtonStateMixed, CPThemeStateHighlighted]];
287 - (CPInteger)nextState
289 if ([
self allowsMixedState])
291 var value = [
self state];
293 return value - ((value === -1) ? -2 : 1);
296 return 1 - [
self state];
306 if ([
self infoForBinding:CPValueBinding])
317 - (void)setState:(CPInteger)aState
337 if (_title === aTitle)
358 if (_alternateTitle === aTitle)
361 _alternateTitle = aTitle;
369 return _alternateTitle;
379 return [
self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
396 return [
self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
399 - (void)setImageOffset:(
float)theImageOffset
406 return [
self valueForThemeAttribute:@"image-offset"];
409 - (void)setShowsStateBy:(CPInteger)aMask
414 if (_showsStateBy === aMask)
417 _showsStateBy = aMask;
428 - (CPInteger)showsStateBy
430 return _showsStateBy;
433 - (void)setHighlightsBy:(CPInteger)aMask
435 if (_highlightsBy === aMask)
438 _highlightsBy = aMask;
447 - (CPInteger)highlightsBy
449 return _highlightsBy;
452 - (void)setButtonType:(CPButtonType)aButtonType
457 [
self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
462 [
self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
472 [
self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask | CPChangeBackgroundCellMask];
473 [
self setShowsStateBy:CPChangeBackgroundCellMask | CPChangeGrayCellMask];
477 [
self setHighlightsBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
478 [
self setShowsStateBy:CPChangeGrayCellMask | CPChangeBackgroundCellMask];
488 reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
492 reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
496 reason:"Unknown button type."];
502 - (void)setImageDimsWhenDisabled:(BOOL)imageShouldDimWhenDisabled
504 imageShouldDimWhenDisabled = !!imageShouldDimWhenDisabled;
506 if (_imageDimsWhenDisabled === imageShouldDimWhenDisabled)
509 _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
518 - (BOOL)imageDimsWhenDisabled
520 return _imageDimsWhenDisabled;
523 - (void)setPeriodicDelay:(
float)aDelay interval:(
float)anInterval
525 _periodicDelay = aDelay;
526 _periodicInterval = anInterval;
531 if ([
self isContinuous])
535 if (!_continuousTimer)
547 if (_target && _action && [_target respondsToSelector:_action])
548 [_target performSelector:_action withObject:self];
551 - (BOOL)startTrackingAt:(CGPoint)aPoint
572 return startedTracking;
575 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
579 if (mouseIsUp && CGRectContainsPoint([
self bounds], aPoint))
594 - (void)invalidateTimers
596 if (_continuousTimer)
598 [_continuousTimer invalidate];
599 _continuousTimer = nil;
602 if (_continuousDelayTimer)
604 [_continuousDelayTimer invalidate];
605 _continuousDelayTimer = nil;
609 - (CGRect)contentRectForBounds:(CGRect)bounds
611 var contentInset = [
self currentValueForThemeAttribute:@"content-inset"];
613 return CGRectInsetByInset(
bounds, contentInset);
616 - (CGRect)bezelRectForBounds:(CGRect)bounds
619 if (![
self isBordered])
622 var bezelInset = [
self currentValueForThemeAttribute:@"bezel-inset"];
624 return CGRectInsetByInset(
bounds, bezelInset);
627 - (CGSize)_minimumFrameSize
629 var size = CGSizeMakeZero(),
630 contentView = [
self ephemeralSubviewNamed:@"content-view"];
634 [contentView sizeToFit];
635 size = [contentView frameSize];
638 size = [([
self title] || " ") sizeWithFont:[
self currentValueForThemeAttribute:@"font"]];
640 var contentInset = [
self currentValueForThemeAttribute:@"content-inset"],
641 minSize = [
self currentValueForThemeAttribute:@"min-size"],
642 maxSize = [
self currentValueForThemeAttribute:@"max-size"];
644 size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
645 size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
647 if (maxSize.width >= 0.0)
648 size.width = MIN(size.width, maxSize.width);
650 if (maxSize.height >= 0.0)
651 size.height = MIN(size.height, maxSize.height);
665 if ([
self ephemeralSubviewNamed:
@"content-view"])
669 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
671 if (aName ===
"bezel-view")
674 else if (aName ===
"content-view")
682 if (aName ===
"bezel-view")
684 var view = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
686 [view setHitTests:NO];
691 return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
694 - (void)layoutSubviews
700 [bezelView setBackgroundColor:[
self currentValueForThemeAttribute:@"bezel-color"]];
717 title = ([
self state] ==
CPOffState && _alternateTitle) ? _alternateTitle : _title;
728 title = ([
self state] !=
CPOffState && _alternateTitle) ? _alternateTitle : _title;
734 image = [
self image];
741 title = ([
self state] !=
CPOffState && _alternateTitle) ? _alternateTitle : _title;
747 image = [
self image];
751 [contentView setText:title];
752 [contentView setImage:image];
753 [contentView setImageOffset:[
self currentValueForThemeAttribute:@"image-offset"]];
755 [contentView setFont:[
self currentValueForThemeAttribute:@"font"]];
756 [contentView setTextColor:[
self currentValueForThemeAttribute:@"text-color"]];
757 [contentView setAlignment:[
self currentValueForThemeAttribute:@"alignment"]];
758 [contentView setVerticalAlignment:[
self currentValueForThemeAttribute:@"vertical-alignment"]];
759 [contentView setLineBreakMode:[
self currentValueForThemeAttribute:@"line-break-mode"]];
760 [contentView setTextShadowColor:[
self currentValueForThemeAttribute:@"text-shadow-color"]];
761 [contentView setTextShadowOffset:[
self currentValueForThemeAttribute:@"text-shadow-offset"]];
762 [contentView setImagePosition:[
self currentValueForThemeAttribute:@"image-position"]];
763 [contentView setImageScaling:[
self currentValueForThemeAttribute:@"image-scaling"]];
764 [contentView setDimsImage:[
self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
768 - (void)setBordered:(BOOL)shouldBeBordered
770 if (shouldBeBordered)
778 return [
self hasThemeState:CPThemeStateBordered];
789 _keyEquivalent = aString ||
@"";
801 var selfWindow = [
self window];
803 if (selfWindow === aWindow || aWindow === nil)
806 if ([selfWindow defaultButton] ===
self)
807 [selfWindow setDefaultButton:nil];
818 return _keyEquivalent;
824 - (void)setKeyEquivalentModifierMask:(
unsigned)aMask
826 _keyEquivalentModifierMask = aMask;
832 - (unsigned)keyEquivalentModifierMask
834 return _keyEquivalentModifierMask;
844 if ([[
self window] defaultButton] ===
self)
847 if (![anEvent _triggersKeyEquivalent:[
self keyEquivalent] withModifierMask:[
self keyEquivalentModifierMask]])
860 - (void)performClick:(
id)sender
864 if (![
self isEnabled])
869 var shouldHighlight = NO;
876 shouldHighlight = YES;
900 - (void)setBezelStyle:(
unsigned)aBezelStyle
902 if (aBezelStyle === _bezelStyle)
905 var currentState = [CPButtonBezelStyleStateMap objectForKey:_bezelStyle],
906 newState = [CPButtonBezelStyleStateMap objectForKey:aBezelStyle];
914 _bezelStyle = aBezelStyle;
917 - (unsigned)bezelStyle
954 _title = [aCoder decodeObjectForKey:CPButtonTitleKey];
955 _alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
956 _allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
961 _highlightsBy = [aCoder decodeIntForKey:CPButtonHighlightsByKey];
962 _showsStateBy = [aCoder decodeIntForKey:CPButtonShowsStateByKey];
977 [
self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
980 _periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
983 _periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
985 _keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
1003 [aCoder encodeObject:_title forKey:CPButtonTitleKey];
1004 [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
1006 [aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
1008 [aCoder encodeInt:_highlightsBy forKey:CPButtonHighlightsByKey];
1009 [aCoder encodeInt:_showsStateBy forKey:CPButtonShowsStateByKey];
1012 [aCoder encodeInt:[
self imagePosition] forKey:CPButtonImagePositionKey];
1015 [aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
1017 [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
1019 [aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
1020 [aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
Used to implement exception handling (creating & raising).
BOOL setThemeState:(ThemeState aState)
void setValue:forThemeAttribute:inState:(id aValue, [forThemeAttribute] CPString aName, [inState] ThemeState aState)
An object representation of nil.
BOOL startTrackingAt:(CGPoint aPoint)
CPCellImagePosition imagePosition()
void setIntValue:(int anObject)
id initWithFrame:(CGRect aFrame)
void raise:reason:(CPString aName, [reason] CPString aReason)
void setControlSize:(CPControlSize aControlSize)
CPTimer scheduledTimerWithTimeInterval:callback:repeats:(CPTimeInterval seconds, [callback] Function aFunction, [repeats] BOOL shouldRepeat)
void setValue:forThemeAttribute:(id aValue, [forThemeAttribute] CPString aName)
void setImagePosition:(CPCellImagePosition position)
A mutable key-value pair collection.
An immutable string (collection of characters).
void mouseDown:(CPEvent anEvent)
BOOL sendAction:to:(SEL anAction, [to] id anObject)
id initWithCoder:(CPCoder aCoder)
void setNeedsDisplay:(BOOL aFlag)
void setObjectValue:(id anObject)
CPTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:(CPTimeInterval seconds, [target] id aTarget, [selector] SEL aSelector, [userInfo] id userInfo, [repeats] BOOL shouldRepeat)
void setDefaultButton:(CPButton aButton)
void highlight:(BOOL shouldHighlight)
A timer object that can send a message after the given time interval.
Defines methods for use when archiving & restoring (enc/decoding).
BOOL unsetThemeState:(ThemeState aState)
CPCarriageReturnCharacter
void setFrameSize:(CGSize aSize)
A bridged object to native Javascript numbers.
void encodeWithCoder:(CPCoder aCoder)
CPView layoutEphemeralSubviewNamed:positioned:relativeToEphemeralSubviewNamed:(CPString aViewName, [positioned] CPWindowOrderingMode anOrderingMode, [relativeToEphemeralSubviewNamed] CPString relativeToViewName)
CGRect rectForEphemeralSubviewNamed:(CPString aViewName)