| Index: chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
|
| diff --git a/chrome/browser/ui/cocoa/extensions/extension_toolbar_icon_surfacing_bubble_mac.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
|
| similarity index 48%
|
| rename from chrome/browser/ui/cocoa/extensions/extension_toolbar_icon_surfacing_bubble_mac.mm
|
| rename to chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
|
| index 0151fe8e24131d162c641a4f06d14f30eed1df97..8c8147cf2e9441ebb9387b003686c855ae85363d 100644
|
| --- a/chrome/browser/ui/cocoa/extensions/extension_toolbar_icon_surfacing_bubble_mac.mm
|
| +++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
|
| @@ -2,54 +2,75 @@
|
| // 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/extensions/extension_toolbar_icon_surfacing_bubble_mac.h"
|
| +#import "chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.h"
|
|
|
| #include "base/mac/foundation_util.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| #import "chrome/browser/ui/cocoa/info_bubble_view.h"
|
| #import "chrome/browser/ui/cocoa/info_bubble_window.h"
|
| #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
|
| -#include "grit/chromium_strings.h"
|
| -#include "grit/generated_resources.h"
|
| #include "skia/ext/skia_utils_mac.h"
|
| #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
|
| #include "third_party/skia/include/core/SkColor.h"
|
| +#import "ui/base/cocoa/controls/hyperlink_button_cell.h"
|
| #import "ui/base/cocoa/hover_button.h"
|
| #import "ui/base/cocoa/window_size_constants.h"
|
| -#include "ui/base/l10n/l10n_util.h"
|
| #include "ui/native_theme/native_theme.h"
|
|
|
| -@interface ExtensionToolbarIconSurfacingBubbleMac ()
|
| +@class ExtensionMessageBubbleButton;
|
| +
|
| +@interface ToolbarActionsBarBubbleMac ()
|
|
|
| // Handles the notification that the window will close.
|
| - (void)windowWillClose:(NSNotification*)notification;
|
|
|
| // Creates and returns an NSAttributed string with the specified size and
|
| // alignment.
|
| -- (NSAttributedString*)attributedStringWithString:(int)stringId
|
| +- (NSAttributedString*)attributedStringWithString:(const base::string16&)string
|
| fontSize:(CGFloat)fontSize
|
| alignment:(NSTextAlignment)alignment;
|
|
|
| -// Creates an NSTextField with the given string, and adds it to the window.
|
| -- (NSTextField*)addTextFieldWithString:(NSAttributedString*)attributedString;
|
| +// Creates an NSTextField with the given string, size, and alignment,, and adds
|
| +// it to the window.
|
| +- (NSTextField*)addTextFieldWithString:(const base::string16&)string
|
| + fontSize:(CGFloat)fontSize
|
| + alignment:(NSTextAlignment)alignment;
|
| +
|
| +// Creates an ExtensionMessagebubbleButton the given string id, and adds it to
|
| +// the window.
|
| +- (ExtensionMessageBubbleButton*) addButtonWithString:
|
| + (const base::string16&)string
|
| + isPrimary:(BOOL)isPrimary;
|
|
|
| // Initializes the bubble's content.
|
| - (void)layout;
|
|
|
| -// Handles the "ok" button being clicked.
|
| +// Handles a button being clicked.
|
| - (void)onButtonClicked:(id)sender;
|
|
|
| @end
|
|
|
| -@interface ExtensionToolbarIconSurfacingBubbleButton : HoverButton
|
| +@interface ExtensionMessageBubbleButton : HoverButton {
|
| + BOOL isPrimary_;
|
| +}
|
| +
|
| // Draws with a blue background and white text.
|
| - (void)drawRect:(NSRect)rect;
|
| +
|
| +@property(nonatomic) BOOL isPrimary;
|
| +
|
| @end
|
|
|
| -@implementation ExtensionToolbarIconSurfacingBubbleMac
|
| +@implementation ToolbarActionsBarBubbleMac
|
| +
|
| +@synthesize actionButton = actionButton_;
|
| +@synthesize dismissButton = dismissButton_;
|
| +@synthesize learnMoreButton = learnMoreButton_;
|
|
|
| - (id)initWithParentWindow:(NSWindow*)parentWindow
|
| anchorPoint:(NSPoint)anchorPoint
|
| - delegate:(ToolbarActionsBarBubbleDelegate*)delegate {
|
| + delegate:(scoped_ptr<ToolbarActionsBarBubbleDelegate>)
|
| + delegate {
|
| base::scoped_nsobject<InfoBubbleWindow> window(
|
| [[InfoBubbleWindow alloc]
|
| initWithContentRect:ui::kWindowSizeDeterminedLater
|
| @@ -59,9 +80,9 @@
|
| if ((self = [super initWithWindow:window
|
| parentWindow:parentWindow
|
| anchoredAt:anchorPoint])) {
|
| - delegate_ = delegate;
|
| acknowledged_ = NO;
|
| [window setCanBecomeKeyWindow:NO];
|
| + delegate_ = delegate.Pass();
|
|
|
| ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
|
| [[self bubble] setAlignment:info_bubble::kAlignRightEdgeToAnchorEdge];
|
| @@ -71,27 +92,30 @@
|
| ui::NativeTheme::kColorId_DialogBackground))];
|
|
|
| [self layout];
|
| -
|
| - delegate_->OnToolbarActionsBarBubbleShown();
|
| }
|
| return self;
|
| }
|
|
|
| +- (IBAction)showWindow:(id)sender {
|
| + delegate_->OnBubbleShown();
|
| + [super showWindow:sender];
|
| +}
|
| +
|
| // Private /////////////////////////////////////////////////////////////////////
|
|
|
| - (void)windowWillClose:(NSNotification*)notification {
|
| if (!acknowledged_) {
|
| - delegate_->OnToolbarActionsBarBubbleClosed(
|
| - ToolbarActionsBarBubbleDelegate::DISMISSED);
|
| + delegate_->OnBubbleClosed(
|
| + ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS);
|
| acknowledged_ = YES;
|
| }
|
| [super windowWillClose:notification];
|
| }
|
|
|
| -- (NSAttributedString*)attributedStringWithString:(int)stringId
|
| +- (NSAttributedString*)attributedStringWithString:(const base::string16&)string
|
| fontSize:(CGFloat)fontSize
|
| alignment:(NSTextAlignment)alignment {
|
| - NSString* string = l10n_util::GetNSString(stringId);
|
| + NSString* cocoaString = base::SysUTF16ToNSString(string);
|
| base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
|
| [[NSMutableParagraphStyle alloc] init]);
|
| [paragraphStyle setAlignment:alignment];
|
| @@ -101,11 +125,18 @@
|
| [NSColor colorWithCalibratedWhite:0.2 alpha:1.0],
|
| NSParagraphStyleAttributeName : paragraphStyle.get()
|
| };
|
| - return [[[NSAttributedString alloc] initWithString:string
|
| + return [[[NSAttributedString alloc] initWithString:cocoaString
|
| attributes:attributes] autorelease];
|
| }
|
|
|
| -- (NSTextField*)addTextFieldWithString:(NSAttributedString*)attributedString {
|
| +- (NSTextField*)addTextFieldWithString:(const base::string16&)string
|
| + fontSize:(CGFloat)fontSize
|
| + alignment:(NSTextAlignment)alignment {
|
| + NSAttributedString* attributedString =
|
| + [self attributedStringWithString:string
|
| + fontSize:fontSize
|
| + alignment:alignment];
|
| +
|
| base::scoped_nsobject<NSTextField> textField(
|
| [[NSTextField alloc] initWithFrame:NSZeroRect]);
|
| [textField setEditable:NO];
|
| @@ -113,62 +144,117 @@
|
| [textField setDrawsBackground:NO];
|
| [textField setAttributedStringValue:attributedString];
|
| [[[self window] contentView] addSubview:textField];
|
| + [textField sizeToFit];
|
| return textField.autorelease();
|
| }
|
|
|
| +- (ExtensionMessageBubbleButton*)addButtonWithString:
|
| + (const base::string16&)string
|
| + isPrimary:(BOOL)isPrimary {
|
| + ExtensionMessageBubbleButton* button =
|
| + [[ExtensionMessageBubbleButton alloc] initWithFrame:NSZeroRect];
|
| + NSAttributedString* buttonString =
|
| + [self attributedStringWithString:string
|
| + fontSize:13.0
|
| + alignment:NSCenterTextAlignment];
|
| + [button setAttributedTitle:buttonString];
|
| + [button setIsPrimary:isPrimary];
|
| + [[button cell] setBordered:NO];
|
| + [button setTarget:self];
|
| + [button setAction:@selector(onButtonClicked:)];
|
| + [[[self window] contentView] addSubview:button];
|
| + [button sizeToFit];
|
| + return button;
|
| +}
|
| +
|
| - (void)layout {
|
| // We first construct the different pieces of the bubble (the heading, the
|
| // content, and the button), and size them appropriately.
|
| - NSAttributedString* headingString =
|
| - [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_HEADING
|
| - fontSize:13.0
|
| - alignment:NSLeftTextAlignment];
|
| - NSTextField* heading = [self addTextFieldWithString:headingString];
|
| - [heading sizeToFit];
|
| + NSTextField* heading =
|
| + [self addTextFieldWithString:delegate_->GetHeadingText()
|
| + fontSize:13.0
|
| + alignment:NSLeftTextAlignment];
|
| NSSize headingSize = [heading frame].size;
|
|
|
| - NSAttributedString* contentString =
|
| - [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_CONTENT
|
| - fontSize:12.0
|
| - alignment:NSLeftTextAlignment];
|
| - NSTextField* content = [self addTextFieldWithString:contentString];
|
| - [content setFrame:NSMakeRect(0, 0, headingSize.width, 0)];
|
| + NSTextField* content =
|
| + [self addTextFieldWithString:delegate_->GetBodyText()
|
| + fontSize:12.0
|
| + alignment:NSLeftTextAlignment];
|
| + CGFloat newWidth = headingSize.width + 50;
|
| + [content setFrame:NSMakeRect(0, 0, newWidth, 0)];
|
| // The content should have the same (max) width as the heading, which means
|
| // the text will most likely wrap.
|
| - NSSize contentSize = NSMakeSize(headingSize.width,
|
| + NSSize contentSize = NSMakeSize(newWidth,
|
| [GTMUILocalizerAndLayoutTweaker
|
| sizeToFitFixedWidthTextField:content]);
|
|
|
| - NSButton* button = [[ExtensionToolbarIconSurfacingBubbleButton alloc]
|
| - initWithFrame:NSZeroRect];
|
| - NSAttributedString* buttonString =
|
| - [self attributedStringWithString:IDS_EXTENSION_TOOLBAR_BUBBLE_OK
|
| - fontSize:13.0
|
| - alignment:NSCenterTextAlignment];
|
| - [button setAttributedTitle:buttonString];
|
| - [[button cell] setBordered:NO];
|
| - [button setTarget:self];
|
| - [button setAction:@selector(onButtonClicked:)];
|
| - [[[self window] contentView] addSubview:button];
|
| - [button sizeToFit];
|
| - // The button's size will only account for the text by default, so pad it a
|
| + base::string16 learnMore = delegate_->GetLearnMoreButtonText();
|
| + NSSize learnMoreSize = NSZeroSize;
|
| + if (!learnMore.empty()) { // The "learn more" link is optional.
|
| + NSAttributedString* learnMoreString =
|
| + [self attributedStringWithString:learnMore
|
| + fontSize:13.0
|
| + alignment:NSLeftTextAlignment];
|
| + learnMoreButton_ =
|
| + [[HyperlinkButtonCell buttonWithString:learnMoreString.string] retain];
|
| + [learnMoreButton_ setTarget:self];
|
| + [learnMoreButton_ setAction:@selector(onButtonClicked:)];
|
| + [[[self window] contentView] addSubview:learnMoreButton_];
|
| + [learnMoreButton_ sizeToFit];
|
| + learnMoreSize = NSMakeSize(NSWidth([learnMoreButton_ frame]),
|
| + NSHeight([learnMoreButton_ frame]));
|
| + }
|
| +
|
| + // The buttons' sizes will only account for the text by default, so pad them a
|
| // bit to make it look good.
|
| - NSSize buttonSize = NSMakeSize(NSWidth([button frame]) + 40.0,
|
| - NSHeight([button frame]) + 20.0);
|
| + const CGFloat kButtonHorizontalPadding = 40.0;
|
| + const CGFloat kButtonVerticalPadding = 20.0;
|
| +
|
| + base::string16 cancelStr = delegate_->GetDismissButtonText();
|
| + NSSize dismissButtonSize = NSZeroSize;
|
| + if (!cancelStr.empty()) { // A cancel/dismiss button is optional.
|
| + dismissButton_ = [self addButtonWithString:cancelStr
|
| + isPrimary:NO];
|
| + dismissButtonSize =
|
| + NSMakeSize(NSWidth([dismissButton_ frame]) + kButtonHorizontalPadding,
|
| + NSHeight([dismissButton_ frame]) + kButtonVerticalPadding);
|
| + }
|
| +
|
| + actionButton_ = [self addButtonWithString:delegate_->GetActionButtonText()
|
| + isPrimary:YES];
|
| + NSSize actionButtonSize =
|
| + NSMakeSize(NSWidth([actionButton_ frame]) + kButtonHorizontalPadding,
|
| + NSHeight([actionButton_ frame]) + kButtonVerticalPadding);
|
|
|
| const CGFloat kHorizontalPadding = 15.0;
|
| const CGFloat kVerticalPadding = 10.0;
|
|
|
| // Next, we set frame for all the different pieces of the bubble, from bottom
|
| // to top.
|
| - CGFloat windowWidth = headingSize.width + kHorizontalPadding * 2;
|
| + CGFloat windowWidth = newWidth + kHorizontalPadding * 2;
|
|
|
| CGFloat currentHeight = 0;
|
| - [button setFrame:NSMakeRect(windowWidth - buttonSize.width,
|
| - currentHeight,
|
| - buttonSize.width,
|
| - buttonSize.height)];
|
| - currentHeight += buttonSize.height + kVerticalPadding;
|
| + [actionButton_ setFrame:NSMakeRect(windowWidth - actionButtonSize.width,
|
| + currentHeight,
|
| + actionButtonSize.width,
|
| + actionButtonSize.height)];
|
| + if (dismissButton_) {
|
| + [dismissButton_ setFrame:NSMakeRect(
|
| + windowWidth - actionButtonSize.width - dismissButtonSize.width,
|
| + currentHeight,
|
| + dismissButtonSize.width,
|
| + dismissButtonSize.height)];
|
| + }
|
| + currentHeight += actionButtonSize.height + kVerticalPadding;
|
| +
|
| + if (learnMoreButton_) {
|
| + [learnMoreButton_ setFrame:NSMakeRect(kHorizontalPadding,
|
| + currentHeight,
|
| + learnMoreSize.width,
|
| + learnMoreSize.height)];
|
| + currentHeight += learnMoreSize.height + kVerticalPadding;
|
| + }
|
| +
|
| [content setFrame:NSMakeRect(kHorizontalPadding,
|
| currentHeight,
|
| contentSize.width,
|
| @@ -194,22 +280,41 @@
|
| }
|
|
|
| - (void)onButtonClicked:(id)sender {
|
| - if (!acknowledged_) {
|
| - delegate_->OnToolbarActionsBarBubbleClosed(
|
| - ToolbarActionsBarBubbleDelegate::ACKNOWLEDGED);
|
| - acknowledged_ = YES;
|
| - [self close];
|
| + if (acknowledged_)
|
| + return;
|
| + ToolbarActionsBarBubbleDelegate::CloseAction action =
|
| + ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE;
|
| + if (learnMoreButton_ && sender == learnMoreButton_) {
|
| + action = ToolbarActionsBarBubbleDelegate::CLOSE_LEARN_MORE;
|
| + } else if (dismissButton_ && sender == dismissButton_) {
|
| + action = ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS;
|
| + } else {
|
| + DCHECK_EQ(sender, actionButton_);
|
| + action = ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE;
|
| }
|
| + acknowledged_ = YES;
|
| + delegate_->OnBubbleClosed(action);
|
| + [self close];
|
| }
|
|
|
| @end
|
|
|
| -@implementation ExtensionToolbarIconSurfacingBubbleButton
|
| +@implementation ExtensionMessageBubbleButton
|
| +
|
| +@synthesize isPrimary = isPrimary_;
|
|
|
| - (void)drawRect:(NSRect)rect {
|
| - SkColor buttonColor = SkColorSetRGB(66, 133, 244);
|
| - SkColor textColor = [self hoverState] == kHoverStateNone ?
|
| - SkColorSetARGB(230, 255, 255, 255) : SK_ColorWHITE;
|
| + SkColor buttonColor;
|
| + SkColor textColor;
|
| + if (isPrimary_) {
|
| + buttonColor = SkColorSetRGB(66, 133, 244);
|
| + textColor = [self hoverState] == kHoverStateNone ?
|
| + SkColorSetARGB(220, 255, 255, 255) : SK_ColorWHITE;
|
| + } else {
|
| + buttonColor = SK_ColorTRANSPARENT;
|
| + textColor = [self hoverState] == kHoverStateNone ?
|
| + SkColorSetARGB(220, 0, 0, 0) : SK_ColorBLACK;
|
| + }
|
| NSRect bounds = [self bounds];
|
| NSAttributedString* title = [self attributedTitle];
|
|
|
| @@ -224,6 +329,10 @@
|
| value:selectedTitleColor
|
| range:NSMakeRange(0, [title length])];
|
|
|
| + if (!isPrimary_) {
|
| + [[NSColor darkGrayColor] setStroke];
|
| + [NSBezierPath strokeRect:bounds];
|
| + }
|
| [[self cell] drawTitle:selectedTitle.get()
|
| withFrame:bounds
|
| inView:self];
|
|
|