58 - (BOOL)alertShowHelp:(
CPAlert)alert;
59 - (void)alertDidEnd:(
CPAlert)theAlert returnCode:(
int)returnCode;
62 @implementation _CPAlertThemeView :
CPView 75 @"size": CGSizeMake(400.0, 110.0),
76 @"content-inset": CGInsetMake(15, 15, 15, 50),
77 @"informative-offset": 6,
83 @"message-text-shadow-offset": CGSizeMakeZero(),
87 @"informative-text-shadow-color": [
CPNull null],
88 @"informative-text-shadow-offset": CGSizeMakeZero(),
89 @"image-offset": CGPointMake(15, 12),
94 @"help-image-left-offset": 15,
96 @"suppression-button-y-offset": 0.0,
97 @"suppression-button-x-offset": 0.0,
98 @"default-elements-margin": 3.0,
101 @"suppression-button-text-shadow-color": [
CPNull null],
102 @"suppression-button-text-shadow-offset": 0.0,
103 @"modal-window-button-margin-y": 0.0,
104 @"modal-window-button-margin-x": 0.0,
105 @"standard-window-button-margin-y": 0.0,
106 @"standard-window-button-margin-x": 0.0,
137 BOOL _showSuppressionButton;
139 CPAlertStyle _alertStyle;
150 Function _didEndBlock;
151 unsigned _implementedDelegateMethods;
153 _CPAlertThemeView _themeView;
155 int _defaultWindowStyle;
165 #pragma mark Creating Alerts 179 var newAlert = [[
self alloc] init];
181 [newAlert setMessageText:aMessage];
182 [newAlert addButtonWithTitle:defaultButtonTitle];
184 if (alternateButtonTitle)
185 [newAlert addButtonWithTitle:alternateButtonTitle];
187 if (otherButtonTitle)
188 [newAlert addButtonWithTitle:otherButtonTitle];
191 [newAlert setInformativeText:informativeText];
204 var newAlert = [[
self alloc] init];
206 [newAlert setMessageText:anErrorMessage];
207 [newAlert setAlertStyle:CPCriticalAlertStyle];
225 _defaultWindowStyle = _CPModalWindowMask;
226 _themeView = [_CPAlertThemeView new];
233 _alertHelpButton = [[
CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
234 [_alertHelpButton setTarget:self];
235 [_alertHelpButton setAction:@selector(_showHelp:)];
243 #pragma mark Delegate 249 - (void)setDelegate:(
id <CPAlertDelegate>)aDelegate
251 if (_delegate === aDelegate)
254 _delegate = aDelegate;
255 _implementedDelegateMethods = 0;
257 if ([_delegate respondsToSelector:
@selector(alertShowHelp:)])
260 if ([_delegate respondsToSelector:
@selector(alertDidEnd:returnCode:)])
265 #pragma mark Accessors 269 return [_themeView theme];
279 if (aTheme === [
self theme])
282 if (aTheme === [
CPTheme defaultHudTheme])
289 [_themeView setTheme:aTheme];
292 - (void)setValue:(
id)aValue forThemeAttribute:(
CPString)aName
294 [_themeView setValue:aValue forThemeAttribute:aName];
299 [_themeView setValue:aValue forThemeAttribute:aName inState:aState];
304 - (void)setWindowStyle:(
int)style
306 CPLog.warn(
"DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
314 CPLog.warn(
"DEPRECATED: windowStyle: is deprecated. use theme instead");
315 return _defaultWindowStyle;
326 [_messageLabel setStringValue:text];
337 return [_messageLabel stringValue];
347 [_informativeLabel setStringValue:text];
358 return [_informativeLabel stringValue];
370 [_window setTitle:aTitle];
380 _accessoryView = aView;
389 - (void)setShowsSuppressionButton:(BOOL)shouldShowSuppressionButton
391 _showSuppressionButton = shouldShowSuppressionButton;
395 #pragma mark Accessing Buttons 411 var
bounds = [[_window contentView] bounds],
412 count = [_buttons count],
414 button = [[
CPButton alloc] initWithFrame:CGRectMakeZero()];
416 [button setTitle:aTitle];
417 [button setTag:count];
418 [button setTarget:self];
419 [button setAction:@selector(_takeReturnCodeFrom:)];
421 [[_window contentView] addSubview:button];
424 [button setKeyEquivalent:CPCarriageReturnCharacter];
425 else if ([aTitle lowercaseString] ===
@"cancel")
426 [button setKeyEquivalent:CPEscapeFunctionKey];
428 [_buttons insertObject:button atIndex:0];
436 - (void)_layoutMessageView
438 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
439 sizeWithFontCorrection = 6.0,
441 messageLabelTextSize;
443 [_messageLabel setTextColor:[_themeView currentValueForThemeAttribute:@"message-text-color"]];
444 [_messageLabel setFont:[_themeView currentValueForThemeAttribute:@"message-text-font"]];
445 [_messageLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"message-text-shadow-color"]];
446 [_messageLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"message-text-shadow-offset"]];
447 [_messageLabel setAlignment:[_themeView currentValueForThemeAttribute:@"message-text-alignment"]];
448 [_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
450 messageLabelWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right;
451 messageLabelTextSize = [[_messageLabel stringValue] sizeWithFont:[_messageLabel font] inWidth:messageLabelWidth];
453 [_messageLabel setFrame:CGRectMake(inset.left, inset.top, messageLabelTextSize.width, messageLabelTextSize.height + sizeWithFontCorrection)];
459 - (void)_layoutInformativeView
461 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
462 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
463 sizeWithFontCorrection = 6.0,
464 informativeLabelWidth,
465 informativeLabelOriginY,
466 informativeLabelTextSize;
468 [_informativeLabel setTextColor:[_themeView currentValueForThemeAttribute:@"informative-text-color"]];
469 [_informativeLabel setFont:[_themeView currentValueForThemeAttribute:@"informative-text-font"]];
470 [_informativeLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-color"]];
471 [_informativeLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
472 [_informativeLabel setAlignment:[_themeView currentValueForThemeAttribute:@"informative-text-alignment"]];
473 [_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
475 informativeLabelWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right;
476 informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin;
477 informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
479 [_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
485 - (void)_layoutAccessoryView
490 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
491 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
492 accessoryViewWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right,
493 accessoryViewOriginY = CGRectGetMaxY([_informativeLabel
frame]) + defaultElementsMargin;
495 [_accessoryView setFrameOrigin:CGPointMake(inset.left, accessoryViewOriginY)];
496 [[_window contentView] addSubview:_accessoryView];
502 - (void)_layoutSuppressionButton
504 if (!_showSuppressionButton)
507 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
508 suppressionViewXOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-x-offset"],
509 suppressionViewYOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-y-offset"],
510 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
511 suppressionButtonViewOriginY = CGRectGetMaxY([(_accessoryView || _informativeLabel)
frame]) + defaultElementsMargin + suppressionViewYOffset;
513 [_suppressionButton setTextColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-color"]];
514 [_suppressionButton setFont:[_themeView currentValueForThemeAttribute:@"suppression-button-text-font"]];
515 [_suppressionButton setTextShadowColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
516 [_suppressionButton setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
517 [_suppressionButton sizeToFit];
519 [_suppressionButton setFrameOrigin:CGPointMake(inset.left + suppressionViewXOffset, suppressionButtonViewOriginY)];
520 [[_window contentView] addSubview:_suppressionButton];
526 - (CGSize)_layoutButtonsFromView:(
CPView)lastView
528 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
529 minimumSize = [_themeView currentValueForThemeAttribute:@"size"],
530 buttonOffset = [_themeView currentValueForThemeAttribute:@"button-offset"],
531 helpLeftOffset = [_themeView currentValueForThemeAttribute:@"help-image-left-offset"],
532 aRepresentativeButton = [_buttons objectAtIndex:0],
533 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
534 panelSize = [[_window contentView] frame].size,
538 theme = [
self theme],
541 [aRepresentativeButton setTheme:[
self theme]];
542 [aRepresentativeButton sizeToFit];
544 panelSize.height = CGRectGetMaxY([lastView
frame]) + defaultElementsMargin + [aRepresentativeButton frameSize].height;
545 if (panelSize.height < minimumSize.height)
546 panelSize.height = minimumSize.height;
548 buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
549 offsetX = panelSize.width - inset.right;
551 switch ([_window styleMask])
553 case _CPModalWindowMask:
554 buttonMarginY = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-y"];
555 buttonMarginX = [_themeView currentValueForThemeAttribute:@"modal-window-button-margin-x"];
559 buttonMarginY = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-y"];
560 buttonMarginX = [_themeView currentValueForThemeAttribute:@"standard-window-button-margin-x"];
564 for (var i = [_buttons count] - 1; i >= 0 ; i--)
566 var button = _buttons[i];
567 [button setTheme:[
self theme]];
570 var buttonFrame = [button frame],
571 width = MAX(80.0, CGRectGetWidth(buttonFrame)),
572 height = CGRectGetHeight(buttonFrame);
575 [button setFrame:CGRectMake(offsetX + buttonMarginX, buttonsOriginY + buttonMarginY, width, height)];
581 var helpImage = [_themeView currentValueForThemeAttribute:@"help-image"],
582 helpImagePressed = [_themeView currentValueForThemeAttribute:@"help-image-pressed"],
583 helpImageSize = helpImage ? [helpImage size] : CGSizeMakeZero(),
584 helpFrame = CGRectMake(helpLeftOffset, buttonsOriginY, helpImageSize.width, helpImageSize.height);
586 [_alertHelpButton setImage:helpImage];
587 [_alertHelpButton setAlternateImage:helpImagePressed];
588 [_alertHelpButton setBordered:NO];
589 [_alertHelpButton setFrame:helpFrame];
592 panelSize.height += [aRepresentativeButton frameSize].height + inset.bottom + buttonOffset;
605 [
self _createWindowWithStyle:nil];
607 var iconOffset = [_themeView currentValueForThemeAttribute:@"image-offset"],
615 theImage = [_themeView currentValueForThemeAttribute:@"warning-image"];
618 theImage = [_themeView currentValueForThemeAttribute:@"information-image"];
621 theImage = [_themeView currentValueForThemeAttribute:@"error-image"];
625 [_alertImageView setImage:theImage];
627 var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
628 [_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
630 [
self _layoutMessageView];
631 [
self _layoutInformativeView];
632 [
self _layoutAccessoryView];
633 [
self _layoutSuppressionButton];
635 var lastView = _informativeLabel;
636 if (_showSuppressionButton)
637 lastView = _suppressionButton;
638 else if (_accessoryView)
639 lastView = _accessoryView;
641 finalSize = [
self _layoutButtonsFromView:lastView];
643 finalSize.height -= 26;
645 [_window setFrameSize:finalSize];
650 [_window setMovable:YES];
651 [_window setMovableByWindowBackground:YES];
657 #pragma mark Displaying Alerts 666 if (!([_window styleMask] & _defaultWindowStyle))
669 [
self _createWindowWithStyle:_defaultWindowStyle];
673 [CPApp runModalForWindow:_window];
680 - (void)runModalWithDidEndBlock:(Function )block
682 _didEndBlock = block;
695 - (void)beginSheetModalForWindow:(
CPWindow)aWindow modalDelegate:(
id)modalDelegate didEndSelector:(
SEL)alertDidEndSelector contextInfo:(
id)contextInfo
700 [
self _createWindowWithStyle:CPDocModalWindowMask];
705 _modalDelegate = modalDelegate;
706 _didEndSelector = alertDidEndSelector;
708 [CPApp beginSheet:_window modalForWindow:aWindow modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
728 - (void)beginSheetModalForWindow:(
CPWindow)aWindow didEndBlock:(Function )block
730 _didEndBlock = block;
740 - (void)_createWindowWithStyle:(
int)forceStyle
742 var
frame = CGRectMakeZero();
743 frame.size = [_themeView currentValueForThemeAttribute:@"size"];
746 [_window setLevel:CPStatusWindowLevel];
747 [_window setPlatformWindow:[[CPApp keyWindow] platformWindow]];
750 [_window setTitle:_title];
752 var contentView = [_window contentView],
753 count = [_buttons count];
757 [contentView addSubview:_buttons[count]];
759 [
self addButtonWithTitle:@"OK"];
761 [contentView addSubview:_messageLabel];
762 [contentView addSubview:_alertImageView];
763 [contentView addSubview:_informativeLabel];
766 [contentView addSubview:_alertHelpButton];
772 - (@action)_showHelp:(
id)aSender
774 [
self _sendDelegateAlertShowHelp];
780 - (@action)_takeReturnCodeFrom:(
id)aSender
782 if ([_window isSheet])
784 [_window orderOut:nil];
785 [CPApp endSheet:_window returnCode:[aSender tag]];
792 [
self _alertDidEnd:_window returnCode:[aSender tag] contextInfo:nil];
799 - (void)_alertDidEnd:(
CPWindow)aWindow returnCode:(
int)returnCode contextInfo:(
id)contextInfo
803 if (typeof(_didEndBlock) ===
"function")
804 _didEndBlock(
self, returnCode);
806 CPLog.warn(
"%s: didEnd block is not a function", [
self description]);
811 else if (_modalDelegate)
814 _modalDelegate.isa.objj_msgSend3(_modalDelegate, _didEndSelector,
self, returnCode, contextInfo);
819 _delegate.isa.objj_msgSend2(_delegate, _didEndSelector,
self, returnCode);
821 [
self _sendDelegateAlertDidEndReturnCode:returnCode];
834 - (void)_sendDelegateAlertDidEndReturnCode:(
int)returnCode
839 [_delegate alertDidEnd:self returnCode:returnCode];
846 - (BOOL)_sendDelegateAlertShowHelp
851 return [_delegate alertShowHelp:self];
869 - (void)setShowsHelp:(BOOL)aValue
877 - (BOOL)showsSuppressionButton
879 return _showSuppressionButton;
885 - (void)setShowsSuppressionButton:(BOOL)aValue
887 _showSuppressionButton = aValue;
893 - (CPAlertStyle)alertStyle
901 - (void)setAlertStyle:(CPAlertStyle)aValue
903 _alertStyle = aValue;
927 return _accessoryView;
935 _accessoryView = aValue;
967 return _suppressionButton;
973 - (SEL)didEndSelector
975 return _didEndSelector;
981 - (void)setDidEndSelector:(
SEL)aValue
983 _didEndSelector = aValue;
989 - (_CPAlertThemeView)themeView
CPTheme defaultHudTheme()
An object representation of nil.
CPFont systemFontOfSize:(CGSize aSize)
id< CPAlertDelegate > _delegate accessors(property=delegate)
void beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:(CPWindow aWindow, [modalDelegate] id modalDelegate, [didEndSelector] SEL alertDidEndSelector, [contextInfo] id contextInfo)
void setTheme:(CPTheme aTheme)
A mutable key-value pair collection.
function ThemeState(stateNames)
CPInformationalAlertStyle
id initWithContentRect:styleMask:(CGRect aContentRect, [styleMask] unsigned aStyleMask)
An immutable string (collection of characters).
CPFont boldSystemFontOfSize:(CGSize aSize)
id checkBoxWithTitle:(CPString aTitle)
CPTextField labelWithTitle:(CPString aTitle)
global CPApp var CPAlertDelegate_alertDidEnd_returnCode_
global CPApp var CPAlertDelegate_alertShowHelp_
CPAlertStyle CPWarningAlertStyle
CPHUDBackgroundWindowMask
FrameUpdater prototype description