blob: 7d48561e03193cfaa14aaf37aad1b5b23a47ab04 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h"
#import "base/logging.h"
#import "chrome/browser/ui/chrome_style.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
#import "chrome/browser/ui/cocoa/hover_close_button.h"
#include "skia/ext/skia_utils_mac.h"
#include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
#include "ui/base/cocoa/controls/hyperlink_button_cell.h"
#include "ui/base/cocoa/window_size_constants.h"
namespace {
const CGFloat kWindowMinWidth = 500;
const CGFloat kButtonGap = 6;
} // namespace
@interface ConstrainedWindowAlert ()
// Position the alert buttons within the given window width.
- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth;
// Resize the given text field to fit within the window and position it starting
// at |yPos|. Returns the new value of yPos.
- (CGFloat)layoutTextField:(NSTextField*)textField
yPos:(CGFloat)yPos
windowWidth:(CGFloat)windowWidth;
// If a link has been set, resizes the link to fit within the window and
// position it starting at |yPos|. Returns the new value of yPos.
- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos
windowWidth:(CGFloat)windowWidth;
// Positions the accessory view starting at yPos. Returns the new value of yPos.
- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos;
// Update the position of the close button.
- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth
windowHeight:(CGFloat)windowHeight;
@end
@implementation ConstrainedWindowAlert
- (id)init {
if ((self = [super init])) {
window_.reset([[ConstrainedWindowCustomWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater]);
NSView* contentView = [window_ contentView];
informativeTextField_.reset([constrained_window::CreateLabel() retain]);
[contentView addSubview:informativeTextField_];
messageTextField_.reset([constrained_window::CreateLabel() retain]);
[contentView addSubview:messageTextField_];
closeButton_.reset(
[[WebUIHoverCloseButton alloc] initWithFrame:NSZeroRect]);
[contentView addSubview:closeButton_];
}
return self;
}
- (NSString*)informativeText {
return [informativeTextField_ stringValue];
}
- (void)setInformativeText:(NSString*)string {
[informativeTextField_ setAttributedStringValue:
constrained_window::GetAttributedLabelString(
string,
chrome_style::kTextFontStyle,
NSNaturalTextAlignment,
NSLineBreakByWordWrapping)];
}
- (NSString*)messageText {
return [messageTextField_ stringValue];
}
- (void)setMessageText:(NSString*)string {
[messageTextField_ setAttributedStringValue:
constrained_window::GetAttributedLabelString(
string,
chrome_style::kTitleFontStyle,
NSNaturalTextAlignment,
NSLineBreakByWordWrapping)];
}
- (void)setLinkText:(NSString*)text target:(id)target action:(SEL)action {
if (![text length]) {
[linkView_ removeFromSuperview];
linkView_.reset(nil);
return;
}
if (!linkView_.get()) {
linkView_.reset(
[[HyperlinkButtonCell buttonWithString:[NSString string]] retain]);
[[window_ contentView] addSubview:linkView_];
}
[linkView_ setTitle:text];
[linkView_ setTarget:target];
[linkView_ setAction:action];
}
- (NSView*)accessoryView {
return accessoryView_;
}
- (void)setAccessoryView:(NSView*)accessoryView {
[accessoryView_ removeFromSuperview];
accessoryView_.reset([accessoryView retain]);
[[window_ contentView] addSubview:accessoryView_];
}
- (NSArray*)buttons {
return buttons_;
}
- (NSButton*)closeButton {
return closeButton_;
}
- (NSWindow*)window {
return window_;
}
- (void)addButtonWithTitle:(NSString*)title
keyEquivalent:(NSString*)keyEquivalent
target:(id)target
action:(SEL)action {
if (!buttons_.get())
buttons_.reset([[NSMutableArray alloc] init]);
base::scoped_nsobject<NSButton> button(
[[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
[button setTitle:title];
[button setKeyEquivalent:keyEquivalent];
[button setTarget:target];
[button setAction:action];
[buttons_ addObject:button];
[[window_ contentView] addSubview:button];
}
- (void)layout {
// Button width.
CGFloat buttonWidth = 0;
for (NSButton* button in buttons_.get()) {
[button sizeToFit];
NSSize size = [button frame].size;
buttonWidth += size.width;
}
if ([buttons_ count])
buttonWidth += ([buttons_ count] - 1) * kButtonGap;
// Window width.
CGFloat windowWidth = buttonWidth;
if (accessoryView_.get())
windowWidth = std::max(windowWidth, NSWidth([accessoryView_ frame]));
windowWidth += chrome_style::kHorizontalPadding * 2;
windowWidth = std::max(windowWidth, kWindowMinWidth);
// Layout controls.
[self layoutButtonsWithWindowWidth:windowWidth];
CGFloat curY = [buttons_ count] ? NSMaxY([[buttons_ lastObject] frame])
: chrome_style::kClientBottomPadding;
CGFloat availableMessageWidth =
windowWidth - chrome_style::GetCloseButtonSize() - kButtonGap;
curY = [self layoutLinkAtYPos:curY
windowWidth:availableMessageWidth];
curY = [self layoutAccessoryViewAtYPos:curY];
curY = [self layoutTextField:informativeTextField_
yPos:curY
windowWidth:windowWidth];
curY = [self layoutTextField:messageTextField_
yPos:curY
windowWidth:availableMessageWidth];
CGFloat windowHeight = curY + chrome_style::kTitleTopPadding;
[self layoutCloseButtonWithWindowWidth:windowWidth
windowHeight:windowHeight];
// Update window frame.
NSRect windowFrame = NSMakeRect(0, 0, windowWidth, windowHeight);
windowFrame = [window_ frameRectForContentRect:windowFrame];
[window_ setFrame:windowFrame display:NO];
}
- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth {
// Layout first 2 button right to left.
CGFloat curX = windowWidth - chrome_style::kHorizontalPadding;
const int buttonCount = [buttons_ count];
for (int i = 0; i < std::min(2, buttonCount); ++i) {
NSButton* button = [buttons_ objectAtIndex:i];
NSRect rect = [button frame];
rect.origin.x = curX - NSWidth(rect);
rect.origin.y = chrome_style::kClientBottomPadding;
[button setFrameOrigin:rect.origin];
curX = NSMinX(rect) - kButtonGap;
}
// Layout remaining buttons left to right.
curX = chrome_style::kHorizontalPadding;
for (int i = buttonCount - 1; i >= 2; --i) {
NSButton* button = [buttons_ objectAtIndex:i];
[button setFrameOrigin:
NSMakePoint(curX, chrome_style::kClientBottomPadding)];
curX += NSMaxX([button frame]) + kButtonGap;
}
}
- (CGFloat)layoutTextField:(NSTextField*)textField
yPos:(CGFloat)yPos
windowWidth:(CGFloat)windowWidth {
if (![[textField stringValue] length]) {
[textField setHidden:YES];
return yPos;
}
[textField setHidden:NO];
NSRect rect;
rect.origin.y = yPos + chrome_style::kRowPadding;
rect.origin.x = chrome_style::kHorizontalPadding;
rect.size.width = windowWidth -
chrome_style::kHorizontalPadding * 2;
rect.size.height = 1;
[textField setFrame:rect];
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
return NSMaxY([textField frame]);
}
- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos
windowWidth:(CGFloat)windowWidth {
if (!linkView_.get())
return yPos;
NSRect availableBounds = NSMakeRect(
0,
0,
windowWidth - chrome_style::kHorizontalPadding * 2,
CGFLOAT_MAX);
NSSize size = [[linkView_ cell] cellSizeForBounds:availableBounds];
NSRect rect;
rect.origin.y = yPos + chrome_style::kRowPadding;
rect.origin.x = chrome_style::kHorizontalPadding;
rect.size = size;
[linkView_ setFrame:rect];
return NSMaxY([linkView_ frame]);
}
- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos {
if (!accessoryView_.get())
return yPos;
NSRect frame = [accessoryView_ frame];
frame.origin.y = yPos + chrome_style::kRowPadding;
frame.origin.x = chrome_style::kHorizontalPadding;
[accessoryView_ setFrameOrigin:frame.origin];
return NSMaxY(frame);
}
- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth
windowHeight:(CGFloat)windowHeight {
NSRect frame;
frame.size.width = chrome_style::GetCloseButtonSize();
frame.size.height = chrome_style::GetCloseButtonSize();
frame.origin.x = windowWidth -
chrome_style::kCloseButtonPadding - NSWidth(frame);
frame.origin.y = windowHeight -
chrome_style::kCloseButtonPadding - NSHeight(frame);
[closeButton_ setFrame:frame];
}
- (NSButton*)linkView {
return linkView_;
}
@end