Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm

Issue 23674004: [rAC, OSX] Add overlay shield for interstitials/waits. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.h"
6
7 #include "base/logging.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
10 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
11 #include "skia/ext/skia_utils_mac.h"
12 #include "ui/base/animation/animation_delegate.h"
13 #include "ui/base/animation/multi_animation.h"
14
15 namespace {
16
17 // Spacing between lines of text in the overlay view.
18 const int kOverlayTextInterlineSpacing = 10;
19
20 // Spacing below image and above text messages in overlay view.
21 const int kOverlayImageBottomMargin = 50;
22
23 // TODO(groby): Unify colors with Views.
24 // Slight shading for mouse hover and legal document background.
25 SkColor kShadingColor = 0xfff2f2f2;
26
27 // A border color for the legal document view.
28 SkColor kSubtleBorderColor = 0xffdfdfdf;
29
30 // Shorten a few long types.
31 typedef ui::MultiAnimation::Part Part;
32 typedef ui::MultiAnimation::Parts Parts;
33
34 } // namespace
35
36 // Bridges Objective C and C++ delegate interfaces.
37 class AnimationDelegateBridge : public ui::AnimationDelegate {
38 public:
39 AnimationDelegateBridge(id<ChromiumAnimationDelegate>);
40
41 protected:
42 // AnimationDelegate implementation.
43 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
44 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
45
46 private:
47 id<ChromiumAnimationDelegate> delegate_; // Not owned. Owns DelegateBridge.
48 };
49
50 AnimationDelegateBridge::AnimationDelegateBridge(
51 id<ChromiumAnimationDelegate> delegate) : delegate_(delegate) {}
52
53 void AnimationDelegateBridge::AnimationProgressed(
54 const ui::Animation* animation) {
55 [delegate_ animationProgressed:animation];
56 }
57
58 void AnimationDelegateBridge::AnimationEnded(
59 const ui::Animation* animation) {
60 [delegate_ animationEnded:animation];
61 }
62
63
64 // An NSView encapsulating the message stack and its custom drawn elements.
65 @interface AutofillMessageStackView : NSView<AutofillLayout>
66 - (CGFloat)getHeightForWidth:(CGFloat)width;
67 - (void)setMessages:
68 (const std::vector<autofill::DialogOverlayString>&)messages;
69 @end
70
71
72 @implementation AutofillMessageStackView
73
74 - (void)drawRect:(NSRect)dirtyRect {
75 NSColor* shadingColor = gfx::SkColorToCalibratedNSColor(kShadingColor);
76 NSColor* borderColor = gfx::SkColorToCalibratedNSColor(kSubtleBorderColor);
77
78 CGFloat arrowHalfWidth = kArrowWidth / 2.0;
79 NSRect bounds = [self bounds];
80 CGFloat y = NSMaxY(bounds) - kArrowHeight;
81
82 NSBezierPath* arrow = [NSBezierPath bezierPath];
83 // Note that we purposely draw slightly outside of |bounds| so that the
84 // stroke is hidden on the sides.
85 [arrow moveToPoint:NSMakePoint(NSMinX(bounds) - 1.0, y)];
86 [arrow relativeLineToPoint:NSMakePoint(NSMidX(bounds) - arrowHalfWidth, 0)];
87 [arrow relativeLineToPoint:NSMakePoint(arrowHalfWidth, kArrowHeight)];
88 [arrow relativeLineToPoint:NSMakePoint(arrowHalfWidth, -kArrowHeight)];
89 [arrow lineToPoint:NSMakePoint(NSMaxX(bounds) + 1.0, y)];
90 [arrow lineToPoint:NSMakePoint(NSMaxX(bounds) + 1.0, NSMinY(bounds) - 1.0)];
91 [arrow lineToPoint:NSMakePoint(NSMinX(bounds) - 1.0, NSMinY(bounds) - 1.0)];
92 [arrow closePath];
93
94 [shadingColor setFill];
95 [arrow fill];
96 [borderColor setStroke];
97 [arrow stroke];
98
99 [super drawRect:dirtyRect];
100 }
101
102 - (CGFloat)getHeightForWidth:(CGFloat)width {
103 CGFloat height = kOverlayTextInterlineSpacing;
104 for (NSTextView* label in [self subviews]) {
105 height += NSHeight([label frame]);
106 height += kOverlayTextInterlineSpacing;
107 }
108 return height + kArrowHeight;
109 }
110
111 - (void)setMessages:
112 (const std::vector<autofill::DialogOverlayString>&) messages {
113 // We probably want to look at other multi-line messages somewhere.
114 base::scoped_nsobject<NSMutableArray> labels(
115 [[NSMutableArray alloc] initWithCapacity:messages.size()]);
116 for (size_t i = 0; i < messages.size(); ++i) {
117 base::scoped_nsobject<NSTextField> label(
118 [[NSTextField alloc] initWithFrame:NSZeroRect]);
119
120 NSFont* labelFont = messages[i].font.GetNativeFont();
121 [label setEditable:NO];
122 [label setBordered:NO];
123 [label setDrawsBackground:NO];
124 [label setFont:labelFont];
125 [label setStringValue:base::SysUTF16ToNSString(messages[i].text)];
126 [label setTextColor:gfx::SkColorToDeviceNSColor(messages[i].text_color)];
127 DCHECK(messages[i].alignment == gfx::ALIGN_CENTER);
128 [label setAlignment:NSCenterTextAlignment];
129 [label sizeToFit];
130
131 [labels addObject:label];
132 }
133 [self setSubviews:labels];
134 [self setHidden:([labels count] == 0)];
135 }
136
137 - (void)performLayout {
138 CGFloat y =
139 NSMaxY([self bounds]) - kArrowHeight - kOverlayTextInterlineSpacing;
140 for (NSTextView* label in [self subviews]) {
141 CGFloat labelHeight = NSHeight([label frame]);
142 [label setFrame:NSMakeRect(0, y - labelHeight,
143 NSWidth([self bounds]), labelHeight)];
144 y = NSMinY([label frame]) - kOverlayTextInterlineSpacing;
145 }
146 DCHECK_GT(0.0, y);
147 }
148
149 - (NSSize)preferredSize {
150 NOTREACHED();
151 return NSZeroSize;
152 }
153
154 @end
155
156
157 @implementation AutofillOverlayController
158
159 - (id)init {
sail 2013/09/04 20:04:06 rsesek pointed out that NSViewController has an de
groby-ooo-7-16 2013/09/04 20:41:45 So, all invocation sites use initWithNibName:nil b
sail 2013/09/04 21:18:51 Yea that makes sense.
groby-ooo-7-16 2013/09/04 22:19:01 Done.
160 if (self = [super init]) {
161 view_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
162 [view_ setBoxType:NSBoxCustom];
163 [view_ setBorderType:NSNoBorder];
164 [view_ setContentViewMargins:NSZeroSize];
165 [view_ setTitlePosition:NSNoTitle];
166 childView_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
167 messageStackView_.reset(
168 [[AutofillMessageStackView alloc] initWithFrame:NSZeroRect]);
169 imageView_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
170 [imageView_ setImageAlignment:NSImageAlignCenter];
171 [childView_ setSubviews:@[messageStackView_, imageView_]];
172 [view_ addSubview:childView_];
173
174 [self setView:view_];
175 }
176 return self;
177 }
178
179 - (void)setState:(const autofill::DialogOverlayState&)state {
180 // Don't update anything if we're still fading out the old state.
181 if (fadeOutAnimation_)
182 return;
183
184 if (state.image.IsEmpty()) {
185 [view_ setHidden:YES];
186 return;
187 }
188
189 [view_ setFillColor:[[view_ window] backgroundColor]];
190 [view_ setAlphaValue:1];
191 [childView_ setAlphaValue:1];
192 [imageView_ setImage:state.image.ToNSImage()];
193 [messageStackView_ setMessages:state.strings];
194 [childView_ setHidden:NO];
195 [view_ setHidden:NO];
196
197 id delegate = [[[self view] window] windowController];
198 if ([delegate respondsToSelector:@selector(requestRelayout)])
199 [delegate performSelector:@selector(requestRelayout)];
200 }
201
202 - (void)beginFadeOut {
203 // Remove first responders, since focus rings show on top of overlay view.
204 // TODO(groby): Figure out to do that less hacky. Ideally, the focus ring
205 // should be part of the controls fading in, not appear at the end.
206 [[self view] setNextResponder:[[[self view] window] firstResponder]];
207 [[[self view] window] makeFirstResponder:[self view]];
208
209 Parts parts;
210 // For this part of the animation, simply show the splash image.
211 parts.push_back(Part(autofill::kSplashDisplayDurationMs, ui::Tween::ZERO));
212 // For this part of the animation, fade out the splash image.
213 parts.push_back(
214 Part(autofill::kSplashFadeOutDurationMs, ui::Tween::EASE_IN));
215 // For this part of the animation, fade out |this| (fade in the dialog).
216 parts.push_back(
217 Part(autofill::kSplashFadeInDialogDurationMs, ui::Tween::EASE_OUT));
218 fadeOutAnimation_.reset(
219 new ui::MultiAnimation(parts,
220 ui::MultiAnimation::GetDefaultTimerInterval()));
221 animationDelegate_.reset(new AnimationDelegateBridge(self));
222 fadeOutAnimation_->set_delegate(animationDelegate_.get());
223 fadeOutAnimation_->set_continuous(false);
224 fadeOutAnimation_->Start();
225 }
226
227 - (int)getHeightForWidth:(int) width {
228 // 0 means "no preference". Image-only overlays fit the container.
229 if ([messageStackView_ isHidden])
230 return 0;
231
232 // Overlays with text messages express a size preference.
233 return kOverlayImageBottomMargin +
234 [messageStackView_ getHeightForWidth:width] +
235 NSHeight([imageView_ frame]);
236
237 return 0;
238 }
239
240 - (NSSize)preferredSize {
241 NOTREACHED(); // Only implemented as part of AutofillLayout protocol.
242 return NSZeroSize;
243 }
244
245 - (void)performLayout {
246 NSRect bounds = [view_ bounds];
247 [childView_ setFrame:bounds];
248 if ([messageStackView_ isHidden]) {
249 [imageView_ setFrame:bounds];
250 return;
251 }
252
253 int messageHeight = [messageStackView_ getHeightForWidth:NSWidth(bounds)];
254 [messageStackView_ setFrame:
255 NSMakeRect(0, 0, NSWidth(bounds), messageHeight)];
256 [messageStackView_ performLayout];
257
258 NSSize imageSize = [[imageView_ image] size];
259 [imageView_ setFrame:NSMakeRect(
260 0, NSMaxY([messageStackView_ frame]) + kOverlayImageBottomMargin,
261 NSWidth(bounds), imageSize.height)];
262 }
263
264 - (void)animationProgressed:(const ui::Animation*) animation {
265 DCHECK_EQ(animation, fadeOutAnimation_.get());
266
267 // Fade out children in stage 1.
268 if (fadeOutAnimation_->current_part_index() == 1) {
269 [childView_ setAlphaValue:(1 - fadeOutAnimation_->GetCurrentValue())];
270 }
271
272 // Fade out background in stage 2(i.e. fade in what's behind |this|).
273 if (fadeOutAnimation_->current_part_index() == 2) {
274 [view_ setAlphaValue: (1 - fadeOutAnimation_->GetCurrentValue())];
275 [childView_ setHidden:YES];
276 }
277
278 // If any fading was done, refresh display.
279 if (fadeOutAnimation_->current_part_index() != 0) {
280 [view_ setNeedsDisplay:YES];
281 }
282 }
283
284 - (void)animationEnded:(const ui::Animation*)animation {
285 DCHECK_EQ(animation, fadeOutAnimation_.get());
286 [[self view] setHidden:YES];
287 fadeOutAnimation_.reset();
288 }
289
290 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698