Chromium Code Reviews| Index: chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm |
| diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b2b3f1182193c499c04639c0312a1ce93259a625 |
| --- /dev/null |
| +++ b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm |
| @@ -0,0 +1,193 @@ |
| +// Copyright (c) 2013 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. |
| + |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/strings/sys_string_conversions.h" |
| +#include "chrome/browser/ui/validation_message_bubble.h" |
| +#include "content/public/browser/render_widget_host.h" |
| +#include "content/public/browser/render_widget_host_view.h" |
| +#include "grit/theme_resources.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#import "chrome/browser/ui/cocoa/flipped_view.h" |
| +#import "chrome/browser/ui/cocoa/info_bubble_view.h" |
| +#import "chrome/browser/ui/cocoa/info_bubble_window.h" |
| +#import "chrome/browser/ui/cocoa/base_bubble_controller.h" |
| +#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| + |
| +const CGFloat kWindowInitialWidth = 200; |
| +const CGFloat kWindowInitialHeight = 100; |
| +const CGFloat kWindowMinWidth = 64; |
| +const CGFloat kWindowMaxWidth = 256; |
| +const CGFloat kWindowPadding = 8; |
| +const CGFloat kWindowPadding2x = 16; |
|
Nico
2013/04/25 22:57:49
Not used, remove
tkent
2013/04/29 22:24:19
Done.
|
| +const CGFloat kIconTextMargin = 4; |
| +const CGFloat kTextVerticalMargin = 4; |
| + |
| +@interface ValidationMessageBubbleController : BaseBubbleController { |
| +} |
| + |
| +- (id)init:(NSWindow*)parent_window |
| +anchoredAt:(NSPoint)anchor_point |
| + mainText:(const string16&)main_text |
| + subText:(const string16&)sub_text; |
| + |
| +@end // interface ValidationMessageBubbleController |
| + |
| + |
| +@implementation ValidationMessageBubbleController |
| + |
| +- (id)init:(NSWindow*)parent_window |
| +anchoredAt:(NSPoint)anchor_point |
| + mainText:(const string16&)main_text |
| + subText:(const string16&)sub_text { |
| + |
| + scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] |
| + initWithContentRect: |
| + NSMakeRect(0, 0, kWindowInitialWidth, kWindowInitialHeight) |
| + styleMask:NSBorderlessWindowMask |
| + backing:NSBackingStoreBuffered |
| + defer:NO]); |
| + if ((self = [super initWithWindow:window.get() |
| + parentWindow:parent_window |
| + anchoredAt:anchor_point])) { |
| + [[self bubble] setArrowLocation:info_bubble::kTopLeft]; |
| + self.shouldOpenKeyWindow = false; |
| + |
| + NSRect content_frame = NSMakeRect( |
| + kWindowPadding, |
| + kWindowPadding, |
| + kWindowInitialWidth - kWindowPadding * 2, |
| + kWindowInitialHeight - (info_bubble::kBubbleArrowHeight |
| + + kWindowPadding * 2)); |
| + scoped_nsobject<FlippedView> content_view( |
| + [[FlippedView alloc] initWithFrame:content_frame]); |
| + [[window contentView] addSubview:content_view]; |
| + |
| + NSImage* image = ResourceBundle::GetSharedInstance() |
| + .GetNativeImageNamed(IDR_UPDATE_AVAILABLE).ToNSImage(); |
| + scoped_nsobject<NSImageView> image_view([[NSImageView alloc] initWithFrame: |
|
Nico
2013/04/25 22:57:49
ObjC functions use camelCaseVariableNames
(throug
tkent
2013/04/29 22:24:19
Renamed all of variables.
|
| + NSMakeRect(0, 0, image.size.width, image.size.height)]); |
| + [image_view setImageFrameStyle:NSImageFrameNone]; |
| + [image_view setImage:image]; |
| + [content_view addSubview:image_view]; |
| + content_frame.size.height = image.size.height; |
| + |
| + const CGFloat text_x = [image_view frame].size.width + kIconTextMargin; |
|
Nico
2013/04/25 22:57:49
NSWidth([image_view frame])
tkent
2013/04/29 22:24:19
Replaced all of .size.width and .size.height with
|
| + NSRect text_frame = |
| + NSMakeRect(text_x, 0, content_frame.size.width - text_x, 0); |
| + scoped_nsobject<NSTextField> text( |
| + [[NSTextField alloc] initWithFrame:text_frame]); |
| + [text setStringValue:base::SysUTF16ToNSString(main_text)]; |
| + [text setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; |
| + [text setEditable:NO]; |
| + [text setBezeled:NO]; |
| + const CGFloat min_text_width |
| + = kWindowMinWidth - kWindowPadding * 2 - text_x; |
| + const CGFloat max_text_width |
| + = kWindowMaxWidth - kWindowPadding * 2 - text_x; |
| + [text sizeToFit]; |
| + [content_view addSubview:text]; |
| + text_frame = [text frame]; |
| + if (text_frame.size.width < min_text_width) { |
| + text_frame.size.width = min_text_width; |
| + [text setFrame:text_frame]; |
| + } else if (text_frame.size.width > max_text_width) { |
| + text_frame.size.width = max_text_width; |
| + text_frame.size.height = 0; |
| + [text setFrame:text_frame]; |
| + text_frame.size.height = |
| + [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:text]; |
| + [text setFrame:text_frame]; |
| + } |
| + content_frame.size.width = NSMaxX(text_frame); |
| + content_frame.size.height = std::max(content_frame.size.height, |
| + text_frame.size.height); |
| + |
| + if (!sub_text.empty()) { |
| + NSRect sub_text_frame = NSMakeRect( |
| + text_x, NSMaxY(text_frame) + kTextVerticalMargin, |
| + text_frame.size.width, 0); |
| + scoped_nsobject<NSTextField> text2( |
| + [[NSTextField alloc] initWithFrame:sub_text_frame]); |
| + [text2 setStringValue:base::SysUTF16ToNSString(sub_text)]; |
| + [text2 setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; |
| + [text2 setEditable:NO]; |
| + [text2 setBezeled:NO]; |
| + [text2 sizeToFit]; |
| + sub_text_frame = [text2 frame]; |
| + if (sub_text_frame.size.width > max_text_width) { |
| + sub_text_frame.size.width = max_text_width; |
| + [text2 setFrame:sub_text_frame]; |
| + sub_text_frame.size.height = |
| + [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:text2]; |
| + [text2 setFrame:sub_text_frame]; |
| + } |
| + [content_view addSubview:text2]; |
| + content_frame.size.width = |
| + std::max(content_frame.size.width, NSMaxX(sub_text_frame)); |
| + content_frame.size.height = |
| + std::max(content_frame.size.height, NSMaxY(sub_text_frame)); |
| + } |
| + |
| + // Adjust the content and window size. |
| + [content_view setFrame:content_frame]; |
| + NSRect window_frame = [window frame]; |
| + window_frame.size.width = content_frame.size.width + kWindowPadding * 2; |
| + window_frame.size.height = content_frame.size.height + kWindowPadding * 2 |
| + + info_bubble::kBubbleArrowHeight; |
| + [window setFrame:window_frame display:nil]; |
| + |
| + [self showWindow:nil]; |
| + } |
| + return self; |
| +} |
| + |
| +@end // implementation ValidationMessageBubbleCocoa |
| + |
| +// ---------------------------------------------------------------- |
| + |
| +namespace { |
| + |
| +class ValidationMessageBubbleCocoa : public chrome::ValidationMessageBubble { |
| + public: |
| + ValidationMessageBubbleCocoa(content::RenderWidgetHost* widget_host, |
| + const gfx::Rect& anchor_in_screen, |
| + const string16& main_text, |
| + const string16& sub_text) { |
| + NSWindow* parent_window = [widget_host->GetView()->GetNativeView() window]; |
| + NSPoint anchor_point = NSMakePoint( |
| + anchor_in_screen.x() + anchor_in_screen.width() / 2, |
| + [[parent_window screen] frame].size.height |
| + - (anchor_in_screen.y() + anchor_in_screen.height())); |
| + controller_.reset([[[ValidationMessageBubbleController alloc] |
| + init:parent_window |
| + anchoredAt:anchor_point |
| + mainText:main_text |
| + subText:sub_text] retain]); |
| + } |
| + |
| + virtual ~ValidationMessageBubbleCocoa() { |
| + [controller_.get() close]; |
| + } |
| + |
| +private: |
| + scoped_nsobject<ValidationMessageBubbleController> controller_; |
| +}; |
| + |
| +} |
| + |
| +// ---------------------------------------------------------------- |
| + |
| +namespace chrome { |
| + |
| +scoped_ptr<ValidationMessageBubble> ValidationMessageBubble::CreateAndShow( |
| + content::RenderWidgetHost* widget_host, |
| + const gfx::Rect& anchor_in_screen, |
| + const string16& main_text, |
| + const string16& sub_text) { |
| + return scoped_ptr<ValidationMessageBubble>(new ValidationMessageBubbleCocoa( |
| + widget_host, anchor_in_screen, main_text, sub_text)).Pass(); |
| +} |
| + |
| +} |