Chromium Code Reviews| 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 |
|
Avi (use Gerrit)
2015/04/16 19:05:54
fix ,,
Devlin
2015/04/16 22:40:59
Done.
|
| +// 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]; |
|
Avi (use Gerrit)
2015/04/16 19:05:54
align on :
Devlin
2015/04/16 22:40:59
Whoops! Must have forgot to fix indent after a var
|
| + dismissButtonSize = |
| + NSMakeSize(NSWidth([dismissButton_ frame]) + kButtonHorizontalPadding, |
| + NSHeight([dismissButton_ frame]) + kButtonVerticalPadding); |
| + } |
| + |
| + actionButton_ = [self addButtonWithString:delegate_->GetActionButtonText() |
| + isPrimary:YES]; |
|
Avi (use Gerrit)
2015/04/16 19:05:54
align on :
Devlin
2015/04/16 22:40:59
Done.
|
| + 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]; |