71 BOOL _showSuppressionButton;
73 CPAlertStyle _alertStyle;
85 _CPAlertThemeView _themeView;
87 int _defaultWindowStyle;
97 #pragma mark Creating Alerts
111 var newAlert = [[
self alloc] init];
113 [newAlert setMessageText:aMessage];
114 [newAlert addButtonWithTitle:defaultButtonTitle];
116 if (alternateButtonTitle)
117 [newAlert addButtonWithTitle:alternateButtonTitle];
119 if (otherButtonTitle)
120 [newAlert addButtonWithTitle:otherButtonTitle];
123 [newAlert setInformativeText:informativeText];
136 var newAlert = [[
self alloc] init];
138 [newAlert setMessageText:anErrorMessage];
139 [newAlert setAlertStyle:CPCriticalAlertStyle];
158 _themeView = [_CPAlertThemeView new];
165 _alertHelpButton = [[
CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
166 [_alertHelpButton setTarget:self];
167 [_alertHelpButton setAction:@selector(_showHelp:)];
173 #pragma mark Accessors
177 return [_themeView theme];
187 if (aTheme === [
self theme])
190 if (aTheme === [
CPTheme defaultHudTheme])
197 [_themeView setTheme:aTheme];
200 - (void)setValue:(
id)aValue forThemeAttribute:(
CPString)aName
202 [_themeView setValue:aValue forThemeAttribute:aName];
207 [_themeView setValue:aValue forThemeAttribute:aName inState:aState];
213 - (void)setWindowStyle:(
int)aStyle
215 CPLog.warn(
"DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
223 CPLog.warn(
"DEPRECATED: windowStyle: is deprecated. use theme instead");
224 return _defaultWindowStyle;
235 [_messageLabel setStringValue:aText];
245 return [_messageLabel stringValue];
255 [_informativeLabel setStringValue:aText];
266 return [_informativeLabel stringValue];
277 [_window setTitle:aTitle];
287 _accessoryView = aView;
296 - (void)setShowsSuppressionButton:(BOOL)shouldShowSuppressionButton
298 _showSuppressionButton = shouldShowSuppressionButton;
302 #pragma mark Accessing Buttons
318 var bounds = [[_window contentView] bounds],
319 count = [_buttons count],
323 [button setTitle:aTitle];
324 [button setTag:count];
325 [button setTarget:self];
326 [button setAction:@selector(_takeReturnCodeFrom:)];
328 [[_window contentView] addSubview:button];
331 [button setKeyEquivalent:CPCarriageReturnCharacter];
332 else if ([aTitle lowercaseString] ===
@"cancel")
333 [button setKeyEquivalent:CPEscapeFunctionKey];
335 [_buttons insertObject:button atIndex:0];
343 - (void)_layoutMessageView
345 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
346 sizeWithFontCorrection = 6.0,
348 messageLabelTextSize;
350 [_messageLabel setTextColor:[_themeView currentValueForThemeAttribute:@"message-text-color"]];
351 [_messageLabel setFont:[_themeView currentValueForThemeAttribute:@"message-text-font"]];
352 [_messageLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"message-text-shadow-color"]];
353 [_messageLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"message-text-shadow-offset"]];
354 [_messageLabel setAlignment:[_themeView currentValueForThemeAttribute:@"message-text-alignment"]];
355 [_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
357 messageLabelWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right;
358 messageLabelTextSize = [[_messageLabel stringValue] sizeWithFont:[_messageLabel font] inWidth:messageLabelWidth];
360 [_messageLabel setFrame:CGRectMake(inset.left, inset.top, messageLabelTextSize.width, messageLabelTextSize.height + sizeWithFontCorrection)];
366 - (void)_layoutInformativeView
368 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
369 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
370 sizeWithFontCorrection = 6.0,
371 informativeLabelWidth,
372 informativeLabelOriginY,
373 informativeLabelTextSize;
375 [_informativeLabel setTextColor:[_themeView currentValueForThemeAttribute:@"informative-text-color"]];
376 [_informativeLabel setFont:[_themeView currentValueForThemeAttribute:@"informative-text-font"]];
377 [_informativeLabel setTextShadowColor:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-color"]];
378 [_informativeLabel setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
379 [_informativeLabel setAlignment:[_themeView currentValueForThemeAttribute:@"informative-text-alignment"]];
380 [_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
382 informativeLabelWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right;
383 informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin;
384 informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
386 [_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
392 - (void)_layoutAccessoryView
397 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
398 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
399 accessoryViewWidth = CGRectGetWidth([[_window contentView]
frame]) - inset.left - inset.right,
400 accessoryViewOriginY = CGRectGetMaxY([_informativeLabel
frame]) + defaultElementsMargin;
402 [_accessoryView setFrameOrigin:CGPointMake(inset.left, accessoryViewOriginY)];
403 [[_window contentView] addSubview:_accessoryView];
409 - (void)_layoutSuppressionButton
411 if (!_showSuppressionButton)
414 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
415 suppressionViewXOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-x-offset"],
416 suppressionViewYOffset = [_themeView currentValueForThemeAttribute:@"suppression-button-y-offset"],
417 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
418 suppressionButtonViewOriginY = CGRectGetMaxY([(_accessoryView || _informativeLabel)
frame]) + defaultElementsMargin + suppressionViewYOffset;
420 [_suppressionButton setTextColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-color"]];
421 [_suppressionButton setFont:[_themeView currentValueForThemeAttribute:@"suppression-button-text-font"]];
422 [_suppressionButton setTextShadowColor:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
423 [_suppressionButton setTextShadowOffset:[_themeView currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
424 [_suppressionButton sizeToFit];
426 [_suppressionButton setFrameOrigin:CGPointMake(inset.left + suppressionViewXOffset, suppressionButtonViewOriginY)];
427 [[_window contentView] addSubview:_suppressionButton];
433 - (CGSize)_layoutButtonsFromView:(
CPView)lastView
435 var inset = [_themeView currentValueForThemeAttribute:@"content-inset"],
436 minimumSize = [_themeView currentValueForThemeAttribute:@"size"],
437 buttonOffset = [_themeView currentValueForThemeAttribute:@"button-offset"],
438 helpLeftOffset = [_themeView currentValueForThemeAttribute:@"help-image-left-offset"],
439 aRepresentativeButton = [_buttons objectAtIndex:0],
440 defaultElementsMargin = [_themeView currentValueForThemeAttribute:@"default-elements-margin"],
441 panelSize = [[_window contentView] frame].size,
445 [aRepresentativeButton setTheme:[
self theme]];
446 [aRepresentativeButton sizeToFit];
448 panelSize.height = CGRectGetMaxY([lastView
frame]) + defaultElementsMargin + [aRepresentativeButton frameSize].height;
449 if (panelSize.height < minimumSize.height)
450 panelSize.height = minimumSize.height;
452 buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
453 offsetX = panelSize.width - inset.right;
455 for (var i = [_buttons count] - 1; i >= 0 ; i--)
457 var button = _buttons[i];
458 [button setTheme:[
self theme]];
461 var buttonFrame = [button frame],
462 width = MAX(80.0, CGRectGetWidth(buttonFrame)),
463 height = CGRectGetHeight(buttonFrame);
466 [button setFrame:CGRectMake(offsetX, buttonsOriginY, width, height)];
472 var helpImage = [_themeView currentValueForThemeAttribute:@"help-image"],
473 helpImagePressed = [_themeView currentValueForThemeAttribute:@"help-image-pressed"],
474 helpImageSize = helpImage ? [helpImage size] : CGSizeMakeZero(),
475 helpFrame = CGRectMake(helpLeftOffset, buttonsOriginY, helpImageSize.width, helpImageSize.height);
477 [_alertHelpButton setImage:helpImage];
478 [_alertHelpButton setAlternateImage:helpImagePressed];
479 [_alertHelpButton setBordered:NO];
480 [_alertHelpButton setFrame:helpFrame];
483 panelSize.height += [aRepresentativeButton frameSize].height + inset.bottom + buttonOffset;
496 [
self _createWindowWithStyle:nil];
498 var iconOffset = [_themeView currentValueForThemeAttribute:@"image-offset"],
506 theImage = [_themeView currentValueForThemeAttribute:@"warning-image"];
509 theImage = [_themeView currentValueForThemeAttribute:@"information-image"];
512 theImage = [_themeView currentValueForThemeAttribute:@"error-image"];
516 [_alertImageView setImage:theImage];
518 var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
519 [_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
521 [
self _layoutMessageView];
522 [
self _layoutInformativeView];
523 [
self _layoutAccessoryView];
524 [
self _layoutSuppressionButton];
526 var lastView = _informativeLabel;
527 if (_showSuppressionButton)
528 lastView = _suppressionButton;
529 else if (_accessoryView)
530 lastView = _accessoryView;
532 finalSize = [
self _layoutButtonsFromView:lastView];
534 finalSize.height -= 26;
536 [_window setFrameSize:finalSize];
542 #pragma mark Displaying Alerts
551 if (!([_window styleMask] & _defaultWindowStyle))
554 [
self _createWindowWithStyle:_defaultWindowStyle];
558 [CPApp runModalForWindow:_window];
569 - (void)beginSheetModalForWindow:(
CPWindow)aWindow modalDelegate:(
id)modalDelegate didEndSelector:(
SEL)alertDidEndSelector contextInfo:(
id)contextInfo
574 [
self _createWindowWithStyle:CPDocModalWindowMask];
579 _modalDelegate = modalDelegate;
580 _didEndSelector = alertDidEndSelector;
582 [CPApp beginSheet:_window modalForWindow:aWindow modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
600 - (void)_createWindowWithStyle:(
int)forceStyle
602 var
frame = CGRectMakeZero();
603 frame.size = [_themeView currentValueForThemeAttribute:@"size"];
606 [_window setLevel:CPStatusWindowLevel];
609 [_window setTitle:_title];
611 var contentView = [_window contentView],
612 count = [_buttons count];
616 [contentView addSubview:_buttons[count]];
618 [
self addButtonWithTitle:@"OK"];
620 [contentView addSubview:_messageLabel];
621 [contentView addSubview:_alertImageView];
622 [contentView addSubview:_informativeLabel];
625 [contentView addSubview:_alertHelpButton];
631 - (@action)_showHelp:(
id)aSender
633 if ([_delegate respondsToSelector:
@selector(alertShowHelp:)])
634 [_delegate alertShowHelp:self];
640 - (@action)_takeReturnCodeFrom:(
id)aSender
642 if ([_window isSheet])
644 [_window orderOut:nil];
645 [CPApp endSheet:_window returnCode:[aSender tag]];
652 [
self _alertDidEnd:_window returnCode:[aSender tag] contextInfo:nil];
659 - (void)_alertDidEnd:(
CPWindow)aWindow returnCode:(
int)returnCode contextInfo:(
id)contextInfo
662 objj_msgSend(_modalDelegate, _didEndSelector,
self, returnCode, contextInfo);
664 _modalDelegate = nil;
665 _didEndSelector = nil;
667 if ([_delegate respondsToSelector:
@selector(alertDidEnd:returnCode:)])
668 [_delegate alertDidEnd:self returnCode:returnCode];
672 @implementation _CPAlertThemeView :
CPView
682 + (id)themeAttributes
685 CGSizeMake(400.0, 110.0),
686 CGInsetMake(15, 15, 15, 50), 6, 10,
687 CPJustifiedTextAlignment,
691 CPJustifiedTextAlignment,
713 @"informative-offset",
715 @"message-text-alignment",
716 @"message-text-color",
717 @"message-text-font",
718 @"message-text-shadow-color",
719 @"message-text-shadow-offset",
720 @"informative-text-alignment",
721 @"informative-text-color",
722 @"informative-text-font",
723 @"informative-text-shadow-color",
724 @"informative-text-shadow-offset",
726 @"information-image",
730 @"help-image-left-offset",
731 @"help-image-pressed",
732 @"suppression-button-y-offset",
733 @"suppression-button-x-offset",
734 @"default-elements-margin",
735 @"suppression-button-text-color",
736 @"suppression-button-text-font",
737 @"suppression-button-text-shadow-color",
738 @"suppression-button-text-shadow-offset"
758 - (void)setShowsHelp:(BOOL)aValue
766 - (BOOL)showsSuppressionButton
768 return _showSuppressionButton;
774 - (void)setShowsSuppressionButton:(BOOL)aValue
776 _showSuppressionButton = aValue;
782 - (CPAlertStyle)alertStyle
790 - (void)setAlertStyle:(CPAlertStyle)aValue
792 _alertStyle = aValue;
816 return _accessoryView;
824 _accessoryView = aValue;
856 return _suppressionButton;
870 - (void)setDelegate:(
id)aValue
878 - (_CPAlertThemeView)themeView