1 // Copyright (c) 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_textfield.h" 6 7 #include <algorithm> 8 9 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 10 11 namespace { 12 13 const CGFloat kGap = 6.0; // gap between icon and text. 14 15 } // namespace 16 17 @interface AutofillTextFieldCell (Internal) 18 19 - (NSRect)iconFrameForFrame:(NSRect)frame; 20 - (NSRect)textFrameForFrame:(NSRect)frame; 21 22 @end 23 24 @implementation AutofillTextField 25 26 @synthesize delegate = delegate_; 27 28 + (Class)cellClass { 29 return [AutofillTextFieldCell class]; 30 } 31 32 - (id)initWithFrame:(NSRect)frame { 33 if (self = [super initWithFrame:frame]) 34 [super setDelegate:self]; 35 return self; 36 } 37 38 - (BOOL)becomeFirstResponder { 39 BOOL result = [super becomeFirstResponder]; 40 if (result && delegate_) 41 [delegate_ fieldBecameFirstResponder:self]; 42 return result; 43 } 44 45 - (void)controlTextDidEndEditing:(NSNotification*)notification { 46 if (delegate_) 47 [delegate_ didEndEditing:self]; 48 } 49 50 - (void)controlTextDidChange:(NSNotification*)aNotification { 51 if (delegate_) 52 [delegate_ didChange:self]; 53 } 54 55 - (NSString*)fieldValue { 56 return [[self cell] fieldValue]; 57 } 58 59 - (void)setFieldValue:(NSString*)fieldValue { 60 [[self cell] setFieldValue:fieldValue]; 61 } 62 63 - (NSString*)validityMessage { 64 return validityMessage_; 65 } 66 67 - (void)setValidityMessage:(NSString*)validityMessage { 68 validityMessage_.reset([validityMessage copy]); 69 [[self cell] setInvalid:[self invalid]]; 70 [self setNeedsDisplay:YES]; 71 } 72 73 - (BOOL)invalid { 74 return [validityMessage_ length] != 0; 75 } 76 77 @end 78 79 @implementation AutofillTextFieldCell 80 81 @synthesize invalid = invalid_; 82 83 - (NSImage*) icon{ 84 return icon_; 85 } 86 87 - (void)setIcon:(NSImage*) icon { 88 icon_.reset([icon retain]); 89 } 90 91 - (NSString*)fieldValue { 92 return [self stringValue]; 93 } 94 95 - (void)setFieldValue:(NSString*)fieldValue { 96 [self setStringValue:fieldValue]; 97 } 98 99 - (NSRect)textFrameForFrame:(NSRect)frame { 100 if (icon_) { 101 NSRect textFrame, iconFrame; 102 NSDivideRect(frame, &iconFrame, &textFrame, 103 kGap + [icon_ size].width, NSMaxXEdge); 104 return textFrame; 105 } 106 return frame; 107 } 108 109 - (NSRect)iconFrameForFrame:(NSRect)frame { 110 NSRect iconFrame; 111 if (icon_) { 112 NSRect textFrame; 113 NSDivideRect(frame, &iconFrame, &textFrame, 114 kGap + [icon_ size].width, NSMaxXEdge); 115 } 116 return iconFrame; 117 } 118 119 - (NSSize)cellSize { 120 NSSize cellSize = [super cellSize]; 121 122 if (icon_) { 123 NSSize iconSize = [icon_ size]; 124 cellSize.width += kGap + iconSize.width; 125 cellSize.height = std::max(cellSize.height, iconSize.height); 126 } 127 128 return cellSize; 129 } 130 131 - (void)editWithFrame:(NSRect)cellFrame 132 inView:(NSView *)controlView 133 editor:(NSText *)editor 134 delegate:(id)delegate 135 event:(NSEvent *)event { 136 [super editWithFrame:[self textFrameForFrame:cellFrame] 137 inView:controlView 138 editor:editor 139 delegate:delegate 140 event:event]; 141 } 142 143 - (void)selectWithFrame:(NSRect)cellFrame 144 inView:(NSView *)controlView 145 editor:(NSText *)editor 146 delegate:(id)delegate 147 start:(NSInteger)start 148 length:(NSInteger)length { 149 [super selectWithFrame:[self textFrameForFrame:cellFrame] 150 inView:controlView 151 editor:editor 152 delegate:delegate 153 start:start 154 length:length]; 155 } 156 157 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { 158 [super drawWithFrame:cellFrame inView:controlView]; 159 160 if (icon_) { 161 NSRect iconFrame = [self iconFrameForFrame:cellFrame]; 162 iconFrame.size = [icon_ size]; 163 iconFrame.origin.y += 164 roundf((NSHeight(cellFrame) - NSHeight(iconFrame)) / 2.0); 165 [icon_ drawInRect:iconFrame 166 fromRect:NSZeroRect 167 operation:NSCompositeSourceOver 168 fraction:1.0 169 respectFlipped:YES 170 hints:nil]; 171 } 172 173 if (invalid_) { 174 gfx::ScopedNSGraphicsContextSaveGState state; 175 176 // Render red border for invalid fields. 177 [[NSColor colorWithDeviceRed:1.0 green:0.0 blue:0.0 alpha:1.0] setStroke]; 178 [[NSBezierPath bezierPathWithRect:NSInsetRect(cellFrame, 0.5, 0.5)] stroke]; 179 180 // Render a dog ear to flag invalid fields. 181 const CGFloat kDogEarSize = 10.0f; 182 183 // TODO(groby): This is a temporary placeholder and will be replaced 184 // with an image. (Pending UI/UX work). 185 [[NSColor colorWithDeviceRed:1.0 green:0.0 blue:0.0 alpha:1.0] setFill]; 186 NSBezierPath* dog_ear = [NSBezierPath bezierPath]; 187 NSPoint corner = NSMakePoint(NSMaxX(cellFrame), NSMinY(cellFrame)); 188 [dog_ear moveToPoint:NSMakePoint(corner.x - kDogEarSize, corner.y)]; 189 [dog_ear lineToPoint:corner]; 190 [dog_ear lineToPoint:NSMakePoint(corner.x, corner.y + kDogEarSize)]; 191 [dog_ear closePath]; 192 [dog_ear fill]; 193 } 194 } 195 196 @end 197