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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm b/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..64b794e6f9e57e62f50ab9b0e7733d71daf1bae7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.mm
@@ -0,0 +1,290 @@
+// Copyright 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.
+
+#import "chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.h"
+
+#include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_types.h"
+#include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "ui/base/animation/multi_animation.h"
+
+namespace {
+
+// Spacing between lines of text in the overlay view.
+const int kOverlayTextInterlineSpacing = 10;
+
+// Spacing below image and above text messages in overlay view.
+const int kOverlayImageBottomMargin = 50;
+
+// TODO(groby): Unify colors with Views.
+// Slight shading for mouse hover and legal document background.
+SkColor kShadingColor = 0xfff2f2f2;
+
+// A border color for the legal document view.
+SkColor kSubtleBorderColor = 0xffdfdfdf;
+
+// Shorten a few long types.
+typedef ui::MultiAnimation::Part Part;
+typedef ui::MultiAnimation::Parts Parts;
+
+} // namespace
+
+// Bridges Objective C and C++ delegate interfaces.
+class AnimationDelegateBridge : public ui::AnimationDelegate {
+ public:
+ AnimationDelegateBridge(id<ChromiumAnimationDelegate>);
+
+ protected:
+ // AnimationDelegate implementation.
+ virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
+ virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
+
+ private:
+ id<ChromiumAnimationDelegate> delegate_; // Not owned. Owns DelegateBridge.
+};
+
+AnimationDelegateBridge::AnimationDelegateBridge(
+ id<ChromiumAnimationDelegate> delegate) : delegate_(delegate) {}
+
+void AnimationDelegateBridge::AnimationProgressed(
+ const ui::Animation* animation) {
+ [delegate_ animationProgressed:animation];
+}
+
+void AnimationDelegateBridge::AnimationEnded(
+ const ui::Animation* animation) {
+ [delegate_ animationEnded:animation];
+}
+
+
+// An NSView encapsulating the message stack and its custom drawn elements.
+@interface AutofillMessageStackView : NSView<AutofillLayout>
+- (CGFloat)getHeightForWidth:(CGFloat)width;
+- (void)setMessages:
+ (const std::vector<autofill::DialogOverlayString>&)messages;
+@end
+
+
+@implementation AutofillMessageStackView
+
+- (void)drawRect:(NSRect)dirtyRect {
+ NSColor* shadingColor = gfx::SkColorToCalibratedNSColor(kShadingColor);
+ NSColor* borderColor = gfx::SkColorToCalibratedNSColor(kSubtleBorderColor);
+
+ CGFloat arrowHalfWidth = kArrowWidth / 2.0;
+ NSRect bounds = [self bounds];
+ CGFloat y = NSMaxY(bounds) - kArrowHeight;
+
+ NSBezierPath* arrow = [NSBezierPath bezierPath];
+ // Note that we purposely draw slightly outside of |bounds| so that the
+ // stroke is hidden on the sides.
+ [arrow moveToPoint:NSMakePoint(NSMinX(bounds) - 1.0, y)];
+ [arrow relativeLineToPoint:NSMakePoint(NSMidX(bounds) - arrowHalfWidth, 0)];
+ [arrow relativeLineToPoint:NSMakePoint(arrowHalfWidth, kArrowHeight)];
+ [arrow relativeLineToPoint:NSMakePoint(arrowHalfWidth, -kArrowHeight)];
+ [arrow lineToPoint:NSMakePoint(NSMaxX(bounds) + 1.0, y)];
+ [arrow lineToPoint:NSMakePoint(NSMaxX(bounds) + 1.0, NSMinY(bounds) - 1.0)];
+ [arrow lineToPoint:NSMakePoint(NSMinX(bounds) - 1.0, NSMinY(bounds) - 1.0)];
+ [arrow closePath];
+
+ [shadingColor setFill];
+ [arrow fill];
+ [borderColor setStroke];
+ [arrow stroke];
+
+ [super drawRect:dirtyRect];
+}
+
+- (CGFloat)getHeightForWidth:(CGFloat)width {
+ CGFloat height = kOverlayTextInterlineSpacing;
+ for (NSTextView* label in [self subviews]) {
+ height += NSHeight([label frame]);
+ height += kOverlayTextInterlineSpacing;
+ }
+ return height + kArrowHeight;
+}
+
+- (void)setMessages:
+ (const std::vector<autofill::DialogOverlayString>&) messages {
+ // We probably want to look at other multi-line messages somewhere.
+ base::scoped_nsobject<NSMutableArray> labels(
+ [[NSMutableArray alloc] initWithCapacity:messages.size()]);
+ for (size_t i = 0; i < messages.size(); ++i) {
+ base::scoped_nsobject<NSTextField> label(
+ [[NSTextField alloc] initWithFrame:NSZeroRect]);
+
+ NSFont* labelFont = messages[i].font.GetNativeFont();
+ [label setEditable:NO];
+ [label setBordered:NO];
+ [label setDrawsBackground:NO];
+ [label setFont:labelFont];
+ [label setStringValue:base::SysUTF16ToNSString(messages[i].text)];
+ [label setTextColor:gfx::SkColorToDeviceNSColor(messages[i].text_color)];
+ DCHECK(messages[i].alignment == gfx::ALIGN_CENTER);
+ [label setAlignment:NSCenterTextAlignment];
+ [label sizeToFit];
+
+ [labels addObject:label];
+ }
+ [self setSubviews:labels];
+ [self setHidden:([labels count] == 0)];
+}
+
+- (void)performLayout {
+ CGFloat y =
+ NSMaxY([self bounds]) - kArrowHeight - kOverlayTextInterlineSpacing;
+ for (NSTextView* label in [self subviews]) {
+ CGFloat labelHeight = NSHeight([label frame]);
+ [label setFrame:NSMakeRect(0, y - labelHeight,
+ NSWidth([self bounds]), labelHeight)];
+ y = NSMinY([label frame]) - kOverlayTextInterlineSpacing;
+ }
+ DCHECK_GT(0.0, y);
+}
+
+- (NSSize)preferredSize {
+ NOTREACHED();
+ return NSZeroSize;
+}
+
+@end
+
+
+@implementation AutofillOverlayController
+
+- (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.
+ if (self = [super init]) {
+ view_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
+ [view_ setBoxType:NSBoxCustom];
+ [view_ setBorderType:NSNoBorder];
+ [view_ setContentViewMargins:NSZeroSize];
+ [view_ setTitlePosition:NSNoTitle];
+ childView_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
+ messageStackView_.reset(
+ [[AutofillMessageStackView alloc] initWithFrame:NSZeroRect]);
+ imageView_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
+ [imageView_ setImageAlignment:NSImageAlignCenter];
+ [childView_ setSubviews:@[messageStackView_, imageView_]];
+ [view_ addSubview:childView_];
+
+ [self setView:view_];
+ }
+ return self;
+}
+
+- (void)setState:(const autofill::DialogOverlayState&)state {
+ // Don't update anything if we're still fading out the old state.
+ if (fadeOutAnimation_)
+ return;
+
+ if (state.image.IsEmpty()) {
+ [view_ setHidden:YES];
+ return;
+ }
+
+ [view_ setFillColor:[[view_ window] backgroundColor]];
+ [view_ setAlphaValue:1];
+ [childView_ setAlphaValue:1];
+ [imageView_ setImage:state.image.ToNSImage()];
+ [messageStackView_ setMessages:state.strings];
+ [childView_ setHidden:NO];
+ [view_ setHidden:NO];
+
+ id delegate = [[[self view] window] windowController];
+ if ([delegate respondsToSelector:@selector(requestRelayout)])
+ [delegate performSelector:@selector(requestRelayout)];
+}
+
+- (void)beginFadeOut {
+ // Remove first responders, since focus rings show on top of overlay view.
+ // TODO(groby): Figure out to do that less hacky. Ideally, the focus ring
+ // should be part of the controls fading in, not appear at the end.
+ [[self view] setNextResponder:[[[self view] window] firstResponder]];
+ [[[self view] window] makeFirstResponder:[self view]];
+
+ Parts parts;
+ // For this part of the animation, simply show the splash image.
+ parts.push_back(Part(autofill::kSplashDisplayDurationMs, ui::Tween::ZERO));
+ // For this part of the animation, fade out the splash image.
+ parts.push_back(
+ Part(autofill::kSplashFadeOutDurationMs, ui::Tween::EASE_IN));
+ // For this part of the animation, fade out |this| (fade in the dialog).
+ parts.push_back(
+ Part(autofill::kSplashFadeInDialogDurationMs, ui::Tween::EASE_OUT));
+ fadeOutAnimation_.reset(
+ new ui::MultiAnimation(parts,
+ ui::MultiAnimation::GetDefaultTimerInterval()));
+ animationDelegate_.reset(new AnimationDelegateBridge(self));
+ fadeOutAnimation_->set_delegate(animationDelegate_.get());
+ fadeOutAnimation_->set_continuous(false);
+ fadeOutAnimation_->Start();
+}
+
+- (int)getHeightForWidth:(int) width {
+ // 0 means "no preference". Image-only overlays fit the container.
+ if ([messageStackView_ isHidden])
+ return 0;
+
+ // Overlays with text messages express a size preference.
+ return kOverlayImageBottomMargin +
+ [messageStackView_ getHeightForWidth:width] +
+ NSHeight([imageView_ frame]);
+
+ return 0;
+}
+
+- (NSSize)preferredSize {
+ NOTREACHED(); // Only implemented as part of AutofillLayout protocol.
+ return NSZeroSize;
+}
+
+- (void)performLayout {
+ NSRect bounds = [view_ bounds];
+ [childView_ setFrame:bounds];
+ if ([messageStackView_ isHidden]) {
+ [imageView_ setFrame:bounds];
+ return;
+ }
+
+ int messageHeight = [messageStackView_ getHeightForWidth:NSWidth(bounds)];
+ [messageStackView_ setFrame:
+ NSMakeRect(0, 0, NSWidth(bounds), messageHeight)];
+ [messageStackView_ performLayout];
+
+ NSSize imageSize = [[imageView_ image] size];
+ [imageView_ setFrame:NSMakeRect(
+ 0, NSMaxY([messageStackView_ frame]) + kOverlayImageBottomMargin,
+ NSWidth(bounds), imageSize.height)];
+}
+
+- (void)animationProgressed:(const ui::Animation*) animation {
+ DCHECK_EQ(animation, fadeOutAnimation_.get());
+
+ // Fade out children in stage 1.
+ if (fadeOutAnimation_->current_part_index() == 1) {
+ [childView_ setAlphaValue:(1 - fadeOutAnimation_->GetCurrentValue())];
+ }
+
+ // Fade out background in stage 2(i.e. fade in what's behind |this|).
+ if (fadeOutAnimation_->current_part_index() == 2) {
+ [view_ setAlphaValue: (1 - fadeOutAnimation_->GetCurrentValue())];
+ [childView_ setHidden:YES];
+ }
+
+ // If any fading was done, refresh display.
+ if (fadeOutAnimation_->current_part_index() != 0) {
+ [view_ setNeedsDisplay:YES];
+ }
+}
+
+- (void)animationEnded:(const ui::Animation*)animation {
+ DCHECK_EQ(animation, fadeOutAnimation_.get());
+ [[self view] setHidden:YES];
+ fadeOutAnimation_.reset();
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698