1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
// 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 "chrome/browser/ui/cocoa/validation_message_bubble_cocoa.h"
#include "base/mac/foundation_util.h"
#include "base/memory/scoped_ptr.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"
#import "chrome/browser/ui/cocoa/validation_message_bubble_controller.h"
#include "chrome/browser/ui/validation_message_bubble.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "grit/theme_resources.h"
#import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
#import "ui/base/cocoa/base_view.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
#import "ui/base/cocoa/flipped_view.h"
#include "ui/base/resource/resource_bundle.h"
const CGFloat kWindowInitialWidth = 200;
const CGFloat kWindowInitialHeight = 100;
const CGFloat kWindowMinWidth = 64;
const CGFloat kWindowMaxWidth = 256;
const CGFloat kWindowPadding = 8;
const CGFloat kIconTextMargin = 4;
const CGFloat kTextVerticalMargin = 4;
@implementation ValidationMessageBubbleController
- (id)init:(NSWindow*)parentWindow
anchoredAt:(NSPoint)anchorPoint
mainText:(const base::string16&)mainText
subText:(const base::string16&)subText {
base::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:parentWindow
anchoredAt:anchorPoint])) {
[[self bubble] setArrowLocation:info_bubble::kTopLeft];
self.shouldOpenAsKeyWindow = NO;
NSView* contentView = [ValidationMessageBubbleController
constructContentView:mainText subText:subText];
[[window contentView] addSubview:contentView];
NSRect contentFrame = [contentView frame];
NSRect windowFrame = [window frame];
windowFrame.size.width = NSWidth(contentFrame) + kWindowPadding * 2;
windowFrame.size.height = NSHeight(contentFrame) + kWindowPadding * 2
+ info_bubble::kBubbleArrowHeight;
[window setFrame:windowFrame display:NO];
[self showWindow:nil];
}
return self;
}
+ (NSView*)constructContentView:(const base::string16&)mainText
subText:(const base::string16&)subText {
NSRect contentFrame = NSMakeRect(kWindowPadding, kWindowPadding, 0, 0);
FlippedView* contentView = [[FlippedView alloc] initWithFrame:contentFrame];
NSImage* image = ResourceBundle::GetSharedInstance()
.GetNativeImageNamed(IDR_INPUT_ALERT).ToNSImage();
base::scoped_nsobject<NSImageView> imageView([[NSImageView alloc]
initWithFrame:NSMakeRect(0, 0, image.size.width, image.size.height)]);
[imageView setImageFrameStyle:NSImageFrameNone];
[imageView setImage:image];
[contentView addSubview:imageView];
contentFrame.size.height = image.size.height;
const CGFloat textX = NSWidth([imageView frame]) + kIconTextMargin;
NSRect textFrame = NSMakeRect(textX, 0, NSWidth(contentFrame) - textX, 0);
base::scoped_nsobject<NSTextField> text(
[[NSTextField alloc] initWithFrame:textFrame]);
[text setStringValue:base::SysUTF16ToNSString(mainText)];
[text setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
[text setEditable:NO];
[text setBezeled:NO];
const CGFloat minTextWidth = kWindowMinWidth - kWindowPadding * 2 - textX;
const CGFloat maxTextWidth = kWindowMaxWidth - kWindowPadding * 2 - textX;
[text sizeToFit];
[contentView addSubview:text];
textFrame = [text frame];
if (NSWidth(textFrame) < minTextWidth) {
textFrame.size.width = minTextWidth;
[text setFrame:textFrame];
} else if (NSWidth(textFrame) > maxTextWidth) {
textFrame.size.width = maxTextWidth;
textFrame.size.height = 0;
[text setFrame:textFrame];
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:text];
textFrame = [text frame];
}
contentFrame.size.width = NSMaxX(textFrame);
contentFrame.size.height =
std::max(NSHeight(contentFrame), NSHeight(textFrame));
if (!subText.empty()) {
NSRect subTextFrame = NSMakeRect(
textX, NSMaxY(textFrame) + kTextVerticalMargin,
NSWidth(textFrame), 0);
base::scoped_nsobject<NSTextField> text2(
[[NSTextField alloc] initWithFrame:subTextFrame]);
[text2 setStringValue:base::SysUTF16ToNSString(subText)];
[text2 setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
[text2 setEditable:NO];
[text2 setBezeled:NO];
[text2 sizeToFit];
subTextFrame = [text2 frame];
if (NSWidth(subTextFrame) > maxTextWidth) {
subTextFrame.size.width = maxTextWidth;
[text2 setFrame:subTextFrame];
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:text2];
subTextFrame = [text2 frame];
}
[contentView addSubview:text2];
contentFrame.size.width =
std::max(NSWidth(contentFrame), NSMaxX(subTextFrame));
contentFrame.size.height =
std::max(NSHeight(contentFrame), NSMaxY(subTextFrame));
}
[contentView setFrame:contentFrame];
return contentView;
}
@end // implementation ValidationMessageBubbleCocoa
// ----------------------------------------------------------------
// Converts |anchor_in_root_view| in rwhv coordinates to cocoa screen
// coordinates, and returns an NSPoint at the center of the bottom side of the
// converted rectangle.
NSPoint GetAnchorPoint(content::RenderWidgetHost* widget_host,
const gfx::Rect& anchor_in_root_view) {
BaseView* view = base::mac::ObjCCastStrict<BaseView>(
widget_host->GetView()->GetNativeView());
NSRect cocoaRect = [view flipRectToNSRect:anchor_in_root_view];
NSRect windowRect = [view convertRect:cocoaRect toView:nil];
NSPoint point = NSMakePoint(NSMidX(windowRect), NSMinY(windowRect));
return ui::ConvertPointFromWindowToScreen([view window], point);
}
ValidationMessageBubbleCocoa::ValidationMessageBubbleCocoa(
content::WebContents* web_contents,
const gfx::Rect& anchor_in_root_view,
const base::string16& main_text,
const base::string16& sub_text) {
content::RenderWidgetHost* widget_host =
web_contents->GetRenderViewHost()->GetWidget();
controller_.reset([[[ValidationMessageBubbleController alloc]
init:[widget_host->GetView()->GetNativeView() window]
anchoredAt:GetAnchorPoint(widget_host, anchor_in_root_view)
mainText:main_text
subText:sub_text] retain]);
}
ValidationMessageBubbleCocoa::~ValidationMessageBubbleCocoa() {
[controller_ close];
}
void ValidationMessageBubbleCocoa::SetPositionRelativeToAnchor(
content::RenderWidgetHost* widget_host,
const gfx::Rect& anchor_in_root_view) {
[controller_ setAnchorPoint:GetAnchorPoint(widget_host, anchor_in_root_view)];
}
|