OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.h" | 5 #include "chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.h" |
6 | 6 |
7 #import "base/mac/foundation_util.h" | 7 #import "base/mac/foundation_util.h" |
8 #include "components/grit/components_scaled_resources.h" | 8 #include "components/grit/components_scaled_resources.h" |
9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" | 9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" |
10 #import "ui/base/cocoa/controls/blue_label_button.h" | 10 #import "ui/base/cocoa/controls/blue_label_button.h" |
| 11 #import "ui/base/cocoa/controls/hyperlink_text_view.h" |
11 #import "ui/base/cocoa/nscolor_additions.h" | 12 #import "ui/base/cocoa/nscolor_additions.h" |
12 #include "ui/base/l10n/l10n_util_mac.h" | 13 #include "ui/base/l10n/l10n_util_mac.h" |
13 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 // Maximum width used by page contents. | 18 // Maximum width used by page contents. |
18 const CGFloat kMaxContainerWidth = 600; | 19 const CGFloat kMaxContainerWidth = 600; |
19 // Padding between icon and title. | 20 // Padding between icon and title. |
20 const CGFloat kIconTitleSpacing = 40; | 21 const CGFloat kIconTitleSpacing = 40; |
21 // Padding between title and message. | 22 // Padding between title and message. |
22 const CGFloat kTitleMessageSpacing = 18; | 23 const CGFloat kTitleMessageSpacing = 18; |
23 // Padding between message and link. | 24 // Padding between message and link. |
24 const CGFloat kMessageLinkSpacing = 50; | 25 const CGFloat kMessageLinkSpacing = 50; |
25 // Padding between message and button. | 26 // Padding between message and button. |
26 const CGFloat kMessageButtonSpacing = 44; | 27 const CGFloat kMessageButtonSpacing = 44; |
27 // Minimum margins on all sides. | 28 // Minimum margins on all sides. |
28 const CGFloat kTabMargin = 13; | 29 const CGFloat kTabMargin = 13; |
29 // Maximum margin on top. | 30 // Maximum margin on top. |
30 const CGFloat kMaxTopMargin = 130; | 31 const CGFloat kMaxTopMargin = 130; |
31 | 32 |
32 NSTextField* MakeLabelTextField(NSRect frame) { | 33 NSTextField* MakeLabelTextField(NSRect frame) { |
| 34 // Not a scoped_nsobject for easy property access. |
33 NSTextField* ret = [[[NSTextField alloc] initWithFrame:frame] autorelease]; | 35 NSTextField* ret = [[[NSTextField alloc] initWithFrame:frame] autorelease]; |
34 ret.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin; | 36 ret.autoresizingMask = NSViewWidthSizable; |
35 ret.editable = NO; | 37 ret.editable = NO; |
36 ret.drawsBackground = NO; | 38 ret.drawsBackground = NO; |
37 ret.bezeled = NO; | 39 ret.bezeled = NO; |
38 return ret; | 40 return ret; |
39 } | 41 } |
40 | 42 |
41 } // namespace | 43 } // namespace |
42 | 44 |
43 @interface SadTabContainerView : NSView | 45 @interface SadTabContainerView : NSView |
44 @end | 46 @end |
45 | 47 |
46 @implementation SadTabContainerView | 48 @implementation SadTabContainerView |
47 - (BOOL)isFlipped { | 49 - (BOOL)isFlipped { |
48 return YES; | 50 return YES; |
49 } | 51 } |
50 @end | 52 @end |
51 | 53 |
52 @interface SadTabView ()<NSTextViewDelegate> | 54 @interface SadTabView ()<NSTextViewDelegate> |
53 @end | 55 @end |
54 | 56 |
55 @implementation SadTabView { | 57 @implementation SadTabView { |
56 NSView* container_; | 58 NSView* container_; |
57 NSImageView* icon_; | |
58 NSTextField* title_; | |
59 NSTextField* message_; | 59 NSTextField* message_; |
60 HyperlinkTextView* help_; | 60 HyperlinkTextView* help_; |
61 NSButton* button_; | 61 NSButton* button_; |
| 62 chrome::SadTab* sadTab_; |
62 } | 63 } |
63 | 64 |
64 @synthesize delegate = delegate_; | 65 - (instancetype)initWithFrame:(NSRect)frame sadTab:(chrome::SadTab*)sadTab { |
| 66 if ((self = [super initWithFrame:frame])) { |
| 67 sadTab_ = sadTab; |
65 | 68 |
66 - (instancetype)initWithFrame:(NSRect)frame { | |
67 if ((self = [super initWithFrame:frame])) { | |
68 self.wantsLayer = YES; | 69 self.wantsLayer = YES; |
69 self.layer.backgroundColor = | 70 self.layer.backgroundColor = |
70 [NSColor colorWithCalibratedWhite:245.0f / 255.0f alpha:1.0].cr_CGColor; | 71 [NSColor colorWithCalibratedWhite:245.0f / 255.0f alpha:1.0].cr_CGColor; |
71 container_ = [[SadTabContainerView new] autorelease]; | 72 container_ = [[SadTabContainerView new] autorelease]; |
72 | 73 |
73 NSImage* iconImage = ResourceBundle::GetSharedInstance() | 74 NSImage* iconImage = ResourceBundle::GetSharedInstance() |
74 .GetNativeImageNamed(IDR_CRASH_SAD_TAB) | 75 .GetNativeImageNamed(IDR_CRASH_SAD_TAB) |
75 .ToNSImage(); | 76 .ToNSImage(); |
76 icon_ = [[NSImageView new] autorelease]; | 77 NSImageView* icon = [[NSImageView new] autorelease]; |
77 icon_.image = iconImage; | 78 icon.image = iconImage; |
78 icon_.frameSize = iconImage.size; | 79 icon.frameSize = iconImage.size; |
79 icon_.autoresizingMask = NSViewMaxXMargin | NSViewMaxYMargin; | 80 [container_ addSubview:icon]; |
80 [container_ addSubview:icon_]; | |
81 | 81 |
82 CGFloat width = self.bounds.size.width; | 82 NSTextField* title = MakeLabelTextField( |
83 title_ = MakeLabelTextField( | 83 NSMakeRect(0, NSMaxY(icon.frame) + kIconTitleSpacing, 0, 0)); |
84 NSMakeRect(0, NSMaxY(icon_.frame) + kIconTitleSpacing, width, 0)); | 84 title.font = [NSFont systemFontOfSize:24]; |
85 title_.font = [NSFont systemFontOfSize:24]; | 85 title.textColor = |
86 title_.textColor = | |
87 [NSColor colorWithCalibratedWhite:38.0f / 255.0f alpha:1.0]; | 86 [NSColor colorWithCalibratedWhite:38.0f / 255.0f alpha:1.0]; |
88 [title_ sizeToFit]; | |
89 [container_ addSubview:title_]; | |
90 | 87 |
91 message_ = | 88 NSMutableParagraphStyle* titleStyle = |
92 MakeLabelTextField(NSMakeRect(0, NSMaxY(title_.frame), width, 0)); | 89 [[NSMutableParagraphStyle new] autorelease]; |
| 90 titleStyle.lineSpacing = 6; |
| 91 title.attributedStringValue = [[[NSAttributedString alloc] |
| 92 initWithString:l10n_util::GetNSString(sadTab->GetTitle()) |
| 93 attributes:@{NSParagraphStyleAttributeName : titleStyle}] |
| 94 autorelease]; |
| 95 |
| 96 [title sizeToFit]; |
| 97 [container_ addSubview:title]; |
| 98 |
| 99 NSFont* messageFont = [NSFont systemFontOfSize:14]; |
| 100 NSColor* messageColor = |
| 101 [NSColor colorWithCalibratedWhite:81.0f / 255.0f alpha:1.0]; |
| 102 |
| 103 message_ = MakeLabelTextField(NSMakeRect(0, NSMaxY(title.frame), 0, 0)); |
| 104 message_.frameOrigin = |
| 105 NSMakePoint(0, NSMaxY(title.frame) + kTitleMessageSpacing); |
93 base::mac::ObjCCast<NSCell>(message_.cell).wraps = YES; | 106 base::mac::ObjCCast<NSCell>(message_.cell).wraps = YES; |
94 message_.font = [NSFont systemFontOfSize:14]; | 107 message_.font = messageFont; |
95 message_.textColor = | 108 message_.textColor = messageColor; |
96 [NSColor colorWithCalibratedWhite:81.0f / 255.0f alpha:1.0]; | 109 message_.stringValue = l10n_util::GetNSString(sadTab->GetMessage()); |
97 [container_ addSubview:message_]; | 110 [container_ addSubview:message_]; |
98 | 111 |
| 112 NSString* helpLinkTitle = |
| 113 l10n_util::GetNSString(sadTab->GetHelpLinkTitle()); |
99 help_ = [[[HyperlinkTextView alloc] | 114 help_ = [[[HyperlinkTextView alloc] |
100 initWithFrame:NSMakeRect(0, 0, 1, message_.font.pointSize + 4)] | 115 initWithFrame:NSMakeRect(0, 0, 1, message_.font.pointSize + 4)] |
101 autorelease]; | 116 autorelease]; |
102 help_.delegate = self; | 117 help_.delegate = self; |
103 help_.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin; | 118 help_.autoresizingMask = NSViewWidthSizable; |
104 help_.textContainer.lineFragmentPadding = 2; // To align with message_. | 119 help_.textContainer.lineFragmentPadding = 2; // To align with message_. |
| 120 [help_ setMessage:helpLinkTitle |
| 121 withFont:messageFont |
| 122 messageColor:messageColor]; |
| 123 [help_ addLinkRange:NSMakeRange(0, helpLinkTitle.length) |
| 124 withURL:@(sadTab->GetHelpLinkURL()) |
| 125 linkColor:messageColor]; |
| 126 [help_ sizeToFit]; |
105 [container_ addSubview:help_]; | 127 [container_ addSubview:help_]; |
106 | 128 |
107 button_ = [[BlueLabelButton new] autorelease]; | 129 button_ = [[BlueLabelButton new] autorelease]; |
108 button_.target = self; | 130 button_.target = self; |
109 button_.action = @selector(buttonClicked); | 131 button_.action = @selector(buttonClicked); |
| 132 button_.title = l10n_util::GetNSString(sadTab->GetButtonTitle()); |
| 133 [button_ sizeToFit]; |
110 [container_ addSubview:button_]; | 134 [container_ addSubview:button_]; |
111 | 135 |
112 [self addSubview:container_]; | 136 [self addSubview:container_]; |
| 137 [self resizeSubviewsWithOldSize:self.bounds.size]; |
113 } | 138 } |
114 return self; | 139 return self; |
115 } | 140 } |
116 | 141 |
| 142 - (BOOL)isOpaque { |
| 143 return YES; |
| 144 } |
| 145 |
117 - (BOOL)isFlipped { | 146 - (BOOL)isFlipped { |
118 return YES; | 147 return YES; |
119 } | 148 } |
120 | 149 |
| 150 - (void)updateLayer { |
| 151 // Currently, updateLayer is only called once. If that changes, a DCHECK in |
| 152 // SadTab::RecordFirstPaint will pipe up and we should add a guard here. |
| 153 sadTab_->RecordFirstPaint(); |
| 154 } |
| 155 |
121 - (void)resizeSubviewsWithOldSize:(NSSize)oldSize { | 156 - (void)resizeSubviewsWithOldSize:(NSSize)oldSize { |
122 [super resizeSubviewsWithOldSize:oldSize]; | 157 [super resizeSubviewsWithOldSize:oldSize]; |
123 | 158 |
124 NSSize size = self.bounds.size; | 159 NSSize size = self.bounds.size; |
125 NSSize containerSize = NSMakeSize( | 160 NSSize containerSize = NSMakeSize( |
126 std::min(size.width - 2 * kTabMargin, kMaxContainerWidth), size.height); | 161 std::min(size.width - 2 * kTabMargin, kMaxContainerWidth), size.height); |
127 | 162 |
128 // Set the container's size first because text wrapping depends on its width. | 163 // Set the container's size first because text wrapping depends on its width. |
129 container_.frameSize = containerSize; | 164 container_.frameSize = containerSize; |
130 | 165 |
131 // |message_| can wrap to variable number of lines. | 166 // |message_| can wrap to variable number of lines. |
132 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_]; | 167 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_]; |
133 | 168 |
134 message_.frameOrigin = | |
135 NSMakePoint(0, NSMaxY(title_.frame) + kTitleMessageSpacing); | |
136 help_.frameOrigin = | 169 help_.frameOrigin = |
137 NSMakePoint(0, NSMaxY(message_.frame) + kMessageLinkSpacing); | 170 NSMakePoint(0, NSMaxY(message_.frame) + kMessageLinkSpacing); |
138 | 171 |
139 button_.frameOrigin = | 172 button_.frameOrigin = |
140 NSMakePoint(containerSize.width - NSWidth(button_.bounds), | 173 NSMakePoint(containerSize.width - NSWidth(button_.bounds), |
141 NSMaxY(message_.frame) + kMessageButtonSpacing); | 174 NSMaxY(message_.frame) + kMessageButtonSpacing); |
142 | 175 |
143 containerSize.height = NSMaxY(button_.frame); | 176 containerSize.height = NSMaxY(button_.frame); |
144 container_.frameSize = containerSize; | 177 container_.frameSize = containerSize; |
145 | 178 |
146 // Center. Top margin is must be between kTabMargin and kMaxTopMargin. | 179 // Center. Top margin is must be between kTabMargin and kMaxTopMargin. |
147 container_.frameOrigin = NSMakePoint( | 180 container_.frameOrigin = NSMakePoint( |
148 floor((size.width - containerSize.width) / 2), | 181 floor((size.width - containerSize.width) / 2), |
149 std::min(kMaxTopMargin, | 182 std::min(kMaxTopMargin, |
150 std::max(kTabMargin, | 183 std::max(kTabMargin, |
151 size.height - containerSize.height - kTabMargin))); | 184 size.height - containerSize.height - kTabMargin))); |
152 } | 185 } |
153 | 186 |
154 - (void)setTitle:(int)title { | |
155 NSMutableParagraphStyle* style = [[NSMutableParagraphStyle new] autorelease]; | |
156 style.lineSpacing = 6; | |
157 | |
158 title_.attributedStringValue = [[[NSAttributedString alloc] | |
159 initWithString:l10n_util::GetNSString(title) | |
160 attributes:@{NSParagraphStyleAttributeName : style}] autorelease]; | |
161 } | |
162 | |
163 - (void)setMessage:(int)message { | |
164 message_.stringValue = l10n_util::GetNSString(message); | |
165 } | |
166 | |
167 - (void)setButtonTitle:(int)buttonTitle { | |
168 button_.title = l10n_util::GetNSString(buttonTitle); | |
169 [button_ sizeToFit]; | |
170 } | |
171 | |
172 - (void)setHelpLinkTitle:(int)helpLinkTitle URL:(NSString*)url { | |
173 NSString* title = l10n_util::GetNSString(helpLinkTitle); | |
174 [help_ setMessage:title | |
175 withFont:message_.font | |
176 messageColor:message_.textColor]; | |
177 [help_ addLinkRange:NSMakeRange(0, title.length) | |
178 withURL:url | |
179 linkColor:message_.textColor]; | |
180 [help_ sizeToFit]; | |
181 } | |
182 | |
183 - (void)buttonClicked { | 187 - (void)buttonClicked { |
184 [delegate_ sadTabViewButtonClicked:self]; | 188 sadTab_->PerformAction(chrome::SadTab::Action::BUTTON); |
185 } | 189 } |
186 | 190 |
187 // Called when someone clicks on the embedded link. | 191 // Called when someone clicks on the embedded link. |
188 - (BOOL)textView:(NSTextView*)textView | 192 - (BOOL)textView:(NSTextView*)textView |
189 clickedOnLink:(id)link | 193 clickedOnLink:(id)link |
190 atIndex:(NSUInteger)charIndex { | 194 atIndex:(NSUInteger)charIndex { |
191 [delegate_ sadTabView:self helpLinkClickedWithURL:(NSString*)link]; | 195 sadTab_->PerformAction(chrome::SadTab::Action::HELP_LINK); |
192 return YES; | 196 return YES; |
193 } | 197 } |
194 | 198 |
| 199 - (NSRange)textView:(NSTextView*)textView |
| 200 willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange |
| 201 toCharacterRange:(NSRange)newSelectedCharRange { |
| 202 return NSMakeRange(0, 0); |
| 203 } |
| 204 |
195 @end | 205 @end |
OLD | NEW |