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.
5 #import "chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.h"
7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
11 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
12 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
13 #include "skia/ext/skia_utils_mac.h"
17 // Spacing around the message in the overlay view.
18 const CGFloat kOverlayLabelPadding = 34;
20 // Spacing below image and above text messages in overlay view.
21 const CGFloat kOverlayImageVerticalPadding = 90;
23 // TODO(groby): Unify colors with Views.
24 // Slight shading for mouse hover and legal document background.
25 SkColor kShadingColor = 0xfff2f2f2;
27 // A border color for the legal document view.
28 SkColor kSubtleBorderColor = 0xffdfdfdf;
32 // An NSView encapsulating the message stack and its custom drawn elements.
33 @interface AutofillMessageView : NSView<AutofillLayout> {
35 base::scoped_nsobject<NSTextField> label_;
38 - (id)initWithFrame:(NSRect)frame;
39 - (CGFloat)heightForWidth:(CGFloat)width;
40 - (void)setMessage:(const autofill::DialogOverlayString&)message;
44 @implementation AutofillMessageView
46 - (void)drawRect:(NSRect)dirtyRect {
47 NSColor* shadingColor = gfx::SkColorToCalibratedNSColor(kShadingColor);
48 NSColor* borderColor = gfx::SkColorToCalibratedNSColor(kSubtleBorderColor);
50 CGFloat arrowHalfWidth = autofill::kArrowWidth / 2.0;
51 NSRect bounds = [self bounds];
52 CGFloat y = NSMaxY(bounds) - autofill::kArrowHeight;
54 NSBezierPath* arrow = [NSBezierPath bezierPath];
55 // Note that we purposely draw slightly outside of |bounds| so that the
56 // stroke is hidden on the sides and bottom.
57 NSRect arrowBounds = NSInsetRect(bounds, -1, -1);
58 arrowBounds.size.height--;
59 [arrow moveToPoint:NSMakePoint(NSMinX(arrowBounds), y)];
61 NSMakePoint(NSMidX(arrowBounds) - arrowHalfWidth, y)];
62 [arrow relativeLineToPoint:
63 NSMakePoint(arrowHalfWidth,autofill::kArrowHeight)];
64 [arrow relativeLineToPoint:
65 NSMakePoint(arrowHalfWidth, -autofill::kArrowHeight)];
66 [arrow lineToPoint:NSMakePoint(NSMaxX(arrowBounds), y)];
67 [arrow lineToPoint:NSMakePoint(NSMaxX(arrowBounds), NSMinY(arrowBounds))];
68 [arrow lineToPoint:NSMakePoint(NSMinX(arrowBounds), NSMinY(arrowBounds))];
71 [shadingColor setFill];
73 [borderColor setStroke];
77 - (id)initWithFrame:(NSRect)frame {
78 if (self = [super initWithFrame:frame]) {
79 label_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]);
80 [label_ setEditable:NO];
81 [label_ setBordered:NO];
82 [label_ setDrawsBackground:NO];
83 [label_ setAlignment:NSCenterTextAlignment];
84 [self addSubview:label_];
89 - (CGFloat)heightForWidth:(CGFloat)width {
90 return NSHeight([label_ frame]) + autofill::kArrowHeight +
91 2 * kOverlayLabelPadding;
94 - (void)setMessage:(const autofill::DialogOverlayString&)message {
95 // We probably want to look at other multi-line messages somewhere.
96 [label_ setFont:message.font_list.GetPrimaryFont().GetNativeFont()];
97 [label_ setStringValue:base::SysUTF16ToNSString(message.text)];
98 [label_ setTextColor:[NSColor darkGrayColor]];
100 // Resize only height, preserve width. This guarantees text stays centered in
102 NSSize labelSize = [label_ frame].size;
103 labelSize.height = [[label_ cell] cellSize].height;
104 [label_ setFrameSize:labelSize];
106 [self setHidden:message.text.empty()];
109 - (void)performLayout {
113 CGFloat labelHeight = NSHeight([label_ frame]);
114 [label_ setFrame:NSMakeRect(0, kOverlayLabelPadding,
115 NSWidth([self bounds]), labelHeight)];
116 // TODO(groby): useful DCHECK() goes here.
119 - (NSSize)preferredSize {
127 @implementation AutofillOverlayController
129 - (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate {
130 if (self = [super initWithNibName:nil bundle:nil]) {
131 delegate_ = delegate;
133 messageView_.reset([[AutofillMessageView alloc] initWithFrame:NSZeroRect]);
134 imageView_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
135 [imageView_ setImageAlignment:NSImageAlignCenter];
137 base::scoped_nsobject<NSView> view(
138 [[NSView alloc] initWithFrame:NSZeroRect]);
139 [view setSubviews:@[messageView_, imageView_]];
145 - (void)updateState {
146 const autofill::DialogOverlayState& state = delegate_->GetDialogOverlay();
148 if (state.image.IsEmpty()) {
149 [[self view] setHidden:YES];
153 [[self view] setHidden:NO];
154 [imageView_ setImage:state.image.ToNSImage()];
155 [messageView_ setMessage:state.string];
157 NSWindowController* delegate = [[[self view] window] windowController];
158 if ([delegate respondsToSelector:@selector(requestRelayout)])
159 [delegate performSelector:@selector(requestRelayout)];
162 - (CGFloat)heightForWidth:(int)width {
163 return 2 * kOverlayImageVerticalPadding +
164 [messageView_ heightForWidth:width] +
165 [[imageView_ image] size].height;
168 - (NSSize)preferredSize {
169 NOTREACHED(); // Only implemented as part of AutofillLayout protocol.
173 - (void)performLayout {
174 NSRect bounds = [[self view] bounds];
176 int messageHeight = [messageView_ heightForWidth:NSWidth(bounds)];
177 [messageView_ setFrame:NSMakeRect(0, 0, NSWidth(bounds), messageHeight)];
178 [messageView_ performLayout];
180 NSSize imageSize = [[imageView_ image] size];
181 [imageView_ setFrame:NSMakeRect(
182 0, NSMaxY([messageView_ frame]) + kOverlayImageVerticalPadding,
183 NSWidth(bounds), imageSize.height)];