00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 @import "CPControl.j"
00025 @import "CPStringDrawing.j"
00026 @import "CPCompatibility.j"
00027
00028 #include "CoreGraphics/CGGeometry.h"
00029 #include "Platform/Platform.h"
00030 #include "Platform/DOM/CPDOMDisplayServer.h"
00031
00032
00033
00034
00035
00036
00037 CPLineBreakByWordWrapping = 0;
00038
00039
00040
00041
00042 CPLineBreakByCharWrapping = 1;
00043
00044
00045
00046
00047 CPLineBreakByClipping = 2;
00048
00049
00050
00051
00052 CPLineBreakByTruncatingHead = 3;
00053
00054
00055
00056
00057 CPLineBreakByTruncatingTail = 4;
00058
00059
00060
00061
00062 CPLineBreakByTruncatingMiddle = 5;
00063
00064
00065
00066
00067
00068
00069 CPTextFieldSquareBezel = 0;
00070
00071
00072
00073
00074
00075 CPTextFieldRoundedBezel = 1;
00076
00077
00078 #if PLATFORM(DOM)
00079
00080 var CPTextFieldDOMInputElement = nil,
00081 CPTextFieldDOMPasswordInputElement = nil,
00082 CPTextFieldDOMStandardInputElement = nil,
00083 CPTextFieldInputOwner = nil,
00084 CPTextFieldTextDidChangeValue = nil,
00085 CPTextFieldInputResigning = NO,
00086 CPTextFieldInputDidBlur = NO,
00087 CPTextFieldInputIsActive = NO,
00088 CPTextFieldCachedSelectStartFunction = nil,
00089 CPTextFieldCachedDragFunction = nil,
00090
00091 CPTextFieldBlurFunction = nil,
00092 CPTextFieldKeyUpFunction = nil,
00093 CPTextFieldKeyPressFunction = nil,
00094 CPTextFieldKeyDownFunction = nil;
00095
00096 #endif
00097
00098 var CPSecureTextFieldCharacter = "\u2022";
00099
00100 @implementation CPString (CPTextFieldAdditions)
00101
00105 - (CPString)string
00106 {
00107 return self;
00108 }
00109
00110 @end
00111
00112 CPTextFieldStateRounded = CPThemeState("rounded");
00113 CPTextFieldStatePlaceholder = CPThemeState("placeholder");
00114
00119 @implementation CPTextField : CPControl
00120 {
00121 BOOL _isEditable;
00122 BOOL _isSelectable;
00123 BOOL _isSecure;
00124
00125 BOOL _drawsBackground;
00126
00127 CPColor _textFieldBackgroundColor;
00128
00129 id _placeholderString;
00130
00131 id _delegate;
00132
00133 CPString _textDidChangeValue;
00134
00135
00136 CPTextFieldBezelStyle _bezelStyle;
00137 BOOL _isBordered;
00138 CPControlSize _controlSize;
00139 }
00140
00141 + (CPTextField)textFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth
00142 {
00143 return [self textFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[CPTheme defaultTheme]];
00144 }
00145
00146 + (CPTextField)textFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth theme:(CPTheme)aTheme
00147 {
00148 var textField = [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
00149
00150 [textField setTheme:aTheme];
00151 [textField setStringValue:aStringValue];
00152 [textField setPlaceholderString:aPlaceholder];
00153 [textField setBordered:YES];
00154 [textField setBezeled:YES];
00155 [textField setEditable:YES];
00156
00157 [textField sizeToFit];
00158
00159 return textField;
00160 }
00161
00162 + (CPTextField)roundedTextFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth
00163 {
00164 return [self roundedTextFieldWithStringValue:aStringValue placeholder:aPlaceholder width:aWidth theme:[CPTheme defaultTheme]];
00165 }
00166
00167 + (CPTextField)roundedTextFieldWithStringValue:(CPString)aStringValue placeholder:(CPString)aPlaceholder width:(float)aWidth theme:(CPTheme)aTheme
00168 {
00169 var textField = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, aWidth, 29.0)];
00170
00171 [textField setTheme:aTheme];
00172 [textField setStringValue:aStringValue];
00173 [textField setPlaceholderString:aPlaceholder];
00174 [textField setBezelStyle:CPTextFieldRoundedBezel];
00175 [textField setBordered:YES];
00176 [textField setBezeled:YES];
00177 [textField setEditable:YES];
00178
00179 [textField sizeToFit];
00180
00181 return textField;
00182 }
00183
00184 + (CPTextField)labelWithTitle:(CPString)aTitle
00185 {
00186 return [self labelWithTitle:aTitle theme:[CPTheme defaultTheme]];
00187 }
00188
00189 + (CPTextField)labelWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
00190 {
00191 var textField = [[self alloc] init];
00192
00193 [textField setStringValue:aTitle];
00194 [textField sizeToFit];
00195
00196 return textField;
00197 }
00198
00199 + (CPString)themeClass
00200 {
00201 return "textfield";
00202 }
00203
00204 + (id)themeAttributes
00205 {
00206 return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), nil]
00207 forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
00208 }
00209
00210
00211 #if PLATFORM(DOM)
00212 - (DOMElement)_inputElement
00213 {
00214 if (!CPTextFieldDOMInputElement)
00215 {
00216 CPTextFieldDOMInputElement = document.createElement("input");
00217 CPTextFieldDOMInputElement.style.position = "absolute";
00218 CPTextFieldDOMInputElement.style.border = "0px";
00219 CPTextFieldDOMInputElement.style.padding = "0px";
00220 CPTextFieldDOMInputElement.style.margin = "0px";
00221 CPTextFieldDOMInputElement.style.whiteSpace = "pre";
00222 CPTextFieldDOMInputElement.style.background = "transparent";
00223 CPTextFieldDOMInputElement.style.outline = "none";
00224
00225 CPTextFieldBlurFunction = function(anEvent)
00226 {
00227 if (CPTextFieldInputOwner && CPTextFieldInputOwner._DOMElement != CPTextFieldDOMInputElement.parentNode)
00228 return;
00229
00230 if (!CPTextFieldInputResigning)
00231 {
00232 [[CPTextFieldInputOwner window] makeFirstResponder:nil];
00233 return;
00234 }
00235
00236 CPTextFieldHandleBlur(anEvent, CPTextFieldDOMInputElement);
00237 CPTextFieldInputDidBlur = YES;
00238
00239 return true;
00240 }
00241
00242 CPTextFieldKeyDownFunction = function(anEvent)
00243 {
00244 CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
00245
00246 CPTextFieldKeyPressFunction(anEvent);
00247
00248 return true;
00249 }
00250
00251 CPTextFieldKeyPressFunction = function(aDOMEvent)
00252 {
00253 aDOMEvent = aDOMEvent || window.event;
00254
00255 if (aDOMEvent.keyCode == CPReturnKeyCode || aDOMEvent.keyCode == CPTabKeyCode)
00256 {
00257 if (aDOMEvent.preventDefault)
00258 aDOMEvent.preventDefault();
00259 if (aDOMEvent.stopPropagation)
00260 aDOMEvent.stopPropagation();
00261 aDOMEvent.cancelBubble = true;
00262
00263 var owner = CPTextFieldInputOwner;
00264
00265 if (aDOMEvent && aDOMEvent.keyCode == CPReturnKeyCode)
00266 {
00267 [owner sendAction:[owner action] to:[owner target]];
00268 [[owner window] makeFirstResponder:nil];
00269 }
00270 else if (aDOMEvent && aDOMEvent.keyCode == CPTabKeyCode)
00271 {
00272 if (!aDOMEvent.shiftKey)
00273 [[owner window] selectNextKeyView:owner];
00274 else
00275 [[owner window] selectPreviousKeyView:owner];
00276 }
00277 }
00278
00279 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00280 }
00281
00282 CPTextFieldKeyUpFunction = function()
00283 {
00284 [CPTextFieldInputOwner setStringValue:CPTextFieldDOMInputElement.value];
00285
00286 if ([CPTextFieldInputOwner stringValue] !== CPTextFieldTextDidChangeValue)
00287 {
00288 CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
00289 [CPTextFieldInputOwner textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:CPTextFieldInputOwner userInfo:nil]];
00290 }
00291
00292 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00293 }
00294
00295 CPTextFieldHandleBlur = function(anEvent)
00296 {
00297 var owner = CPTextFieldInputOwner;
00298 CPTextFieldInputOwner = nil;
00299
00300 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00301 }
00302
00303 if (document.attachEvent)
00304 {
00305 CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
00306 CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
00307 CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
00308 }
00309 else
00310 {
00311 CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyUp, CPTextFieldKeyUpFunction, NO);
00312 CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyDown, CPTextFieldKeyDownFunction, NO);
00313 CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyPress, CPTextFieldKeyPressFunction, NO);
00314 }
00315
00316
00317 CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
00318
00319 CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
00320 }
00321
00322 if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
00323 {
00324 if ([self isSecure])
00325 CPTextFieldDOMInputElement.type = "password";
00326 else
00327 CPTextFieldDOMInputElement.type = "text";
00328
00329 return CPTextFieldDOMInputElement;
00330 }
00331
00332 if ([self isSecure])
00333 {
00334 if (!CPTextFieldDOMPasswordInputElement)
00335 {
00336 CPTextFieldDOMPasswordInputElement = document.createElement("input");
00337 CPTextFieldDOMPasswordInputElement.style.position = "absolute";
00338 CPTextFieldDOMPasswordInputElement.style.border = "0px";
00339 CPTextFieldDOMPasswordInputElement.style.padding = "0px";
00340 CPTextFieldDOMPasswordInputElement.style.margin = "0px";
00341 CPTextFieldDOMPasswordInputElement.style.whiteSpace = "pre";
00342 CPTextFieldDOMPasswordInputElement.style.background = "transparent";
00343 CPTextFieldDOMPasswordInputElement.style.outline = "none";
00344 CPTextFieldDOMPasswordInputElement.type = "password";
00345
00346 CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
00347 CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
00348 CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
00349
00350 CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
00351 }
00352
00353 CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
00354 }
00355 else
00356 {
00357 CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
00358 }
00359
00360 return CPTextFieldDOMInputElement;
00361 }
00362 #endif
00363
00364 - (id)initWithFrame:(CGRect)aFrame
00365 {
00366 self = [super initWithFrame:aFrame];
00367
00368 if (self)
00369 {
00370 [self setStringValue:@""];
00371 [self setPlaceholderString:@""];
00372
00373 _sendActionOn = CPKeyUpMask | CPKeyDownMask;
00374
00375 [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
00376 }
00377
00378 return self;
00379 }
00380
00381 #pragma mark Controlling Editability and Selectability
00382
00386 - (void)setEditable:(BOOL)shouldBeEditable
00387 {
00388 _isEditable = shouldBeEditable;
00389 }
00390
00394 - (BOOL)isEditable
00395 {
00396 return _isEditable;
00397 }
00398
00403 - (void)setSelectable:(BOOL)aFlag
00404 {
00405 _isSelectable = aFlag;
00406 }
00407
00411 - (BOOL)isSelectable
00412 {
00413 return _isSelectable;
00414 }
00415
00420 - (void)setSecure:(BOOL)aFlag
00421 {
00422 _isSecure = aFlag;
00423 }
00424
00428 - (BOOL)isSecure
00429 {
00430 return _isSecure;
00431 }
00432
00433
00438 - (void)setBezeled:(BOOL)shouldBeBezeled
00439 {
00440 if (shouldBeBezeled)
00441 [self setThemeState:CPThemeStateBezeled];
00442 else
00443 [self unsetThemeState:CPThemeStateBezeled];
00444 }
00445
00449 - (BOOL)isBezeled
00450 {
00451 return [self hasThemeState:CPThemeStateBezeled];
00452 }
00453
00458 - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
00459 {
00460 var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
00461
00462 if (shouldBeRounded)
00463 [self setThemeState:CPTextFieldStateRounded];
00464 else
00465 [self unsetThemeState:CPTextFieldStateRounded];
00466 }
00467
00471 - (CPTextFieldBezelStyle)bezelStyle
00472 {
00473 if ([self hasThemeState:CPTextFieldStateRounded])
00474 return CPTextFieldRoundedBezel;
00475
00476 return CPTextFieldSquareBezel;
00477 }
00478
00483 - (void)setBordered:(BOOL)shouldBeBordered
00484 {
00485 if (shouldBeBordered)
00486 [self setThemeState:CPThemeStateBordered];
00487 else
00488 [self unsetThemeState:CPThemeStateBordered];
00489 }
00490
00494 - (BOOL)isBordered
00495 {
00496 return [self hasThemeState:CPThemeStateBordered];
00497 }
00498
00503 - (void)setDrawsBackground:(BOOL)shouldDrawBackground
00504 {
00505 if (_drawsBackground == shouldDrawBackground)
00506 return;
00507
00508 _drawsBackground = shouldDrawBackground;
00509
00510 [self setNeedsLayout];
00511 [self setNeedsDisplay:YES];
00512 }
00513
00517 - (BOOL)drawsBackground
00518 {
00519 return _drawsBackground;
00520 }
00521
00526 - (void)setTextFieldBackgroundColor:(CPColor)aColor
00527 {
00528 if (_textFieldBackgroundColor == aColor)
00529 return;
00530
00531 _textFieldBackgroundColor = aColor;
00532
00533 [self setNeedsLayout];
00534 [self setNeedsDisplay:YES];
00535 }
00536
00540 - (CPColor)textFieldBackgroundColor
00541 {
00542 return _textFieldBackgroundColor;
00543 }
00544
00545
00546 - (BOOL)acceptsFirstResponder
00547 {
00548 return [self isEditable] && [self isEnabled];
00549 }
00550
00551
00552 - (BOOL)becomeFirstResponder
00553 {
00554 if (CPTextFieldInputOwner && [CPTextFieldInputOwner window] !== [self window])
00555 [[CPTextFieldInputOwner window] makeFirstResponder:nil];
00556
00557 [self setThemeState:CPThemeStateEditing];
00558
00559 [self _updatePlaceholderState];
00560
00561 [self setNeedsLayout];
00562
00563 #if PLATFORM(DOM)
00564
00565 var string = [self stringValue],
00566 element = [self _inputElement];
00567
00568 element.value = string;
00569 element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
00570 element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
00571 element.style.zIndex = 1000;
00572
00573 var contentRect = [self contentRectForBounds:[self bounds]];
00574
00575 element.style.top = _CGRectGetMinY(contentRect) + "px";
00576 element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px";
00577 element.style.width = _CGRectGetWidth(contentRect) + "px";
00578 element.style.height = _CGRectGetHeight(contentRect) + "px";
00579
00580 _DOMElement.appendChild(element);
00581
00582 window.setTimeout(function()
00583 {
00584 element.focus();
00585 CPTextFieldInputOwner = self;
00586 }, 0.0);
00587
00588
00589 [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
00590
00591 [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
00592
00593 CPTextFieldInputIsActive = YES;
00594
00595 if (document.attachEvent)
00596 {
00597 CPTextFieldCachedSelectStartFunction = document.body.onselectstart;
00598 CPTextFieldCachedDragFunction = document.body.ondrag;
00599
00600 document.body.ondrag = function () {};
00601 document.body.onselectstart = function () {};
00602 }
00603
00604 #endif
00605
00606 return YES;
00607 }
00608
00609
00610 - (BOOL)resignFirstResponder
00611 {
00612 [self unsetThemeState:CPThemeStateEditing];
00613
00614 [self _updatePlaceholderState];
00615
00616 [self setNeedsLayout];
00617
00618 #if PLATFORM(DOM)
00619
00620 var element = [self _inputElement];
00621
00622 [self setObjectValue:element.value];
00623
00624 CPTextFieldInputResigning = YES;
00625 element.blur();
00626
00627 if (!CPTextFieldInputDidBlur)
00628 CPTextFieldBlurFunction();
00629
00630 CPTextFieldInputDidBlur = NO;
00631 CPTextFieldInputResigning = NO;
00632
00633 if (element.parentNode == _DOMElement)
00634 element.parentNode.removeChild(element);
00635
00636 CPTextFieldInputIsActive = NO;
00637
00638 if (document.attachEvent)
00639 {
00640 CPTextFieldCachedSelectStartFunction = nil;
00641 CPTextFieldCachedDragFunction = nil;
00642
00643 document.body.ondrag = CPTextFieldCachedDragFunction
00644 document.body.onselectstart = CPTextFieldCachedSelectStartFunction
00645 }
00646
00647 #endif
00648
00649
00650 [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
00651
00652 return YES;
00653 }
00654
00655 - (void)mouseDown:(CPEvent)anEvent
00656 {
00657
00658 if ([self isEditable] && [self isEnabled])
00659 return [[self window] makeFirstResponder:self];
00660 else
00661 return [[self nextResponder] mouseDown:anEvent];
00662 }
00663
00667 - (id)objectValue
00668 {
00669 return [super objectValue];
00670 }
00671
00672
00673
00674
00675 - (void)setObjectValue:(id)aValue
00676 {
00677 [super setObjectValue:aValue];
00678
00679 [self _updatePlaceholderState];
00680 }
00681
00682 - (void)_updatePlaceholderState
00683 {
00684 var string = [self stringValue];
00685
00686 if ((!string || [string length] === 0) && ![self hasThemeState:CPThemeStateEditing])
00687 [self setThemeState:CPTextFieldStatePlaceholder];
00688 else
00689 [self unsetThemeState:CPTextFieldStatePlaceholder];
00690 }
00691
00696 -(void)setPlaceholderString:(CPString)aStringValue
00697 {
00698 if (_placeholderString === aStringValue)
00699 return;
00700
00701 _placeholderString = aStringValue;
00702
00703
00704 if ([self hasThemeState:CPTextFieldStatePlaceholder])
00705 {
00706 [self setNeedsLayout];
00707 [self setNeedsDisplay:YES];
00708 }
00709 }
00710
00714 - (CPString)placeholderString
00715 {
00716 return _placeholderString;
00717 }
00718
00736 - (void)sizeToFit
00737 {
00738 var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
00739 contentInset = [self currentValueForThemeAttribute:@"content-inset"],
00740 minSize = [self currentValueForThemeAttribute:@"min-size"],
00741 maxSize = [self currentValueForThemeAttribute:@"max-size"];
00742
00743 size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
00744 size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
00745
00746 if (maxSize.width >= 0.0)
00747 size.width = MIN(size.width, maxSize.width);
00748
00749 if (maxSize.height >= 0.0)
00750 size.height = MIN(size.height, maxSize.height);
00751
00752 if ([self isEditable])
00753 size.width = CGRectGetWidth([self frame]);
00754
00755 [self setFrameSize:size];
00756 }
00757
00761 - (void)selectText:(id)sender
00762 {
00763 #if PLATFORM(DOM)
00764 var element = [self _inputElement];
00765
00766 if (element.parentNode == _DOMElement && ([self isEditable] || [self isSelectable]))
00767 element.select();
00768 #endif
00769 }
00770
00771 #pragma mark Setting the Delegate
00772
00773 - (void)setDelegate:(id)aDelegate
00774 {
00775 var defaultCenter = [CPNotificationCenter defaultCenter];
00776
00777
00778 if (_delegate)
00779 {
00780 [defaultCenter removeObserver:_delegate name:CPControlTextDidBeginEditingNotification object:self];
00781 [defaultCenter removeObserver:_delegate name:CPControlTextDidChangeNotification object:self];
00782 [defaultCenter removeObserver:_delegate name:CPControlTextDidEndEditingNotification object:self];
00783 }
00784
00785 _delegate = aDelegate;
00786
00787 if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
00788 [defaultCenter
00789 addObserver:_delegate
00790 selector:@selector(controlTextDidBeginEditing:)
00791 name:CPControlTextDidBeginEditingNotification
00792 object:self];
00793
00794 if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
00795 [defaultCenter
00796 addObserver:_delegate
00797 selector:@selector(controlTextDidChange:)
00798 name:CPControlTextDidChangeNotification
00799 object:self];
00800
00801
00802 if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
00803 [defaultCenter
00804 addObserver:_delegate
00805 selector:@selector(controlTextDidEndEditing:)
00806 name:CPControlTextDidEndEditingNotification
00807 object:self];
00808
00809 }
00810
00811 - (id)delegate
00812 {
00813 return _delegate;
00814 }
00815
00816 - (CGRect)contentRectForBounds:(CGRect)bounds
00817 {
00818 var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
00819
00820 if (!contentInset)
00821 return bounds;
00822
00823 bounds.origin.x += contentInset.left;
00824 bounds.origin.y += contentInset.top;
00825 bounds.size.width -= contentInset.left + contentInset.right;
00826 bounds.size.height -= contentInset.top + contentInset.bottom;
00827
00828 return bounds;
00829 }
00830
00831 - (CGRect)bezelRectForBounds:(CFRect)bounds
00832 {
00833 var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
00834
00835 if (_CGInsetIsEmpty(bezelInset))
00836 return bounds;
00837
00838 bounds.origin.x += bezelInset.left;
00839 bounds.origin.y += bezelInset.top;
00840 bounds.size.width -= bezelInset.left + bezelInset.right;
00841 bounds.size.height -= bezelInset.top + bezelInset.bottom;
00842
00843 return bounds;
00844 }
00845
00846 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
00847 {
00848 if (aName === "bezel-view")
00849 return [self bezelRectForBounds:[self bounds]];
00850
00851 else if (aName === "content-view")
00852 return [self contentRectForBounds:[self bounds]];
00853
00854 return [super rectForEphemeralSubviewNamed:aName];
00855 }
00856
00857 - (CPView)createEphemeralSubviewNamed:(CPString)aName
00858 {
00859 if (aName === "bezel-view")
00860 {
00861 var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
00862
00863 [view setHitTests:NO];
00864
00865 return view;
00866 }
00867 else
00868 {
00869 var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
00870
00871
00872 return view;
00873 }
00874
00875 return [super createEphemeralSubviewNamed:aName];
00876 }
00877
00878 - (void)layoutSubviews
00879 {
00880 var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
00881 positioned:CPWindowBelow
00882 relativeToEphemeralSubviewNamed:@"content-view"];
00883
00884 if (bezelView)
00885 [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
00886
00887 var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
00888 positioned:CPWindowAbove
00889 relativeToEphemeralSubviewNamed:@"bezel-view"];
00890
00891 if (contentView)
00892 {
00893 [contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
00894
00895 var string = "";
00896
00897 if ([self hasThemeState:CPTextFieldStatePlaceholder])
00898 string = [self placeholderString];
00899 else
00900 {
00901 string = [self stringValue];
00902
00903 if ([self isSecure])
00904 string = secureStringForString(string);
00905 }
00906
00907 [contentView setText:string];
00908
00909 [contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
00910 [contentView setFont:[self currentValueForThemeAttribute:@"font"]];
00911 [contentView setAlignment:[self currentValueForThemeAttribute:@"alignment"]];
00912 [contentView setVerticalAlignment:[self currentValueForThemeAttribute:@"vertical-alignment"]];
00913 [contentView setLineBreakMode:[self currentValueForThemeAttribute:@"line-break-mode"]];
00914 [contentView setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
00915 [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
00916 }
00917 }
00918
00919 @end
00920
00921 var secureStringForString = function(aString)
00922 {
00923
00924 if (!aString)
00925 return "";
00926
00927 var secureString = "",
00928 length = aString.length;
00929
00930 while (length--)
00931 secureString += CPSecureTextFieldCharacter;
00932
00933 return secureString;
00934 }
00935
00936
00937 var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
00938 CPTextFieldIsSelectableKey = "CPTextFieldIsSelectableKey",
00939 CPTextFieldIsBorderedKey = "CPTextFieldIsBorderedKey",
00940 CPTextFieldIsBezeledKey = "CPTextFieldIsBezeledKey",
00941 CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
00942 CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
00943 CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
00944 CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
00945 CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
00946
00947 @implementation CPTextField (CPCoding)
00948
00954 - (id)initWithCoder:(CPCoder)aCoder
00955 {
00956 self = [super initWithCoder:aCoder];
00957
00958 if (self)
00959 {
00960 [self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
00961 [self setSelectable:[aCoder decodeBoolForKey:CPTextFieldIsSelectableKey]];
00962
00963 [self setDrawsBackground:[aCoder decodeBoolForKey:CPTextFieldDrawsBackgroundKey]];
00964
00965 [self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
00966
00967 [self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
00968 }
00969
00970 return self;
00971 }
00972
00977 - (void)encodeWithCoder:(CPCoder)aCoder
00978 {
00979 [super encodeWithCoder:aCoder];
00980
00981 [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
00982 [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
00983
00984 [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
00985
00986 [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
00987
00988 [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
00989 }
00990
00991 @end
00992