![]() |
API 0.9.5
|
00001 /* 00002 * CPView.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00025 00026 00027 /* 00028 @global 00029 @group CPViewAutoresizingMasks 00030 The default resizingMask, the view will not resize or reposition itself. 00031 */ 00032 CPViewNotSizable = 0; 00033 /* 00034 @global 00035 @group CPViewAutoresizingMasks 00036 Allow for flexible space on the left hand side of the view. 00037 */ 00038 CPViewMinXMargin = 1; 00039 /* 00040 @global 00041 @group CPViewAutoresizingMasks 00042 The view should grow and shrink horizontally with its parent view. 00043 */ 00044 CPViewWidthSizable = 2; 00045 /* 00046 @global 00047 @group CPViewAutoresizingMasks 00048 Allow for flexible space to the right hand side of the view. 00049 */ 00050 CPViewMaxXMargin = 4; 00051 /* 00052 @global 00053 @group CPViewAutoresizingMasks 00054 Allow for flexible space above the view. 00055 */ 00056 CPViewMinYMargin = 8; 00057 /* 00058 @global 00059 @group CPViewAutoresizingMasks 00060 The view should grow and shrink vertically with its parent view. 00061 */ 00062 CPViewHeightSizable = 16; 00063 /* 00064 @global 00065 @group CPViewAutoresizingMasks 00066 Allow for flexible space below the view. 00067 */ 00068 CPViewMaxYMargin = 32; 00069 00070 CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification"; 00071 CPViewFrameDidChangeNotification = @"CPViewFrameDidChangeNotification"; 00072 00073 var CachedNotificationCenter = nil, 00074 CachedThemeAttributes = nil; 00075 00076 #if PLATFORM(DOM) 00077 var DOMElementPrototype = nil, 00078 00079 BackgroundTrivialColor = 0, 00080 BackgroundVerticalThreePartImage = 1, 00081 BackgroundHorizontalThreePartImage = 2, 00082 BackgroundNinePartImage = 3, 00083 BackgroundTransparentColor = 4; 00084 #endif 00085 00086 var CPViewFlags = { }, 00087 CPViewHasCustomDrawRect = 1 << 0, 00088 CPViewHasCustomLayoutSubviews = 1 << 1; 00089 00107 @implementation CPView : CPResponder 00108 { 00109 CPWindow _window; 00110 00111 CPView _superview; 00112 CPArray _subviews; 00113 00114 CPGraphicsContext _graphicsContext; 00115 00116 int _tag; 00117 00118 CGRect _frame; 00119 CGRect _bounds; 00120 CGAffineTransform _boundsTransform; 00121 CGAffineTransform _inverseBoundsTransform; 00122 00123 CPSet _registeredDraggedTypes; 00124 CPArray _registeredDraggedTypesArray; 00125 00126 BOOL _isHidden; 00127 BOOL _hitTests; 00128 BOOL _clipsToBounds; 00129 00130 BOOL _postsFrameChangedNotifications; 00131 BOOL _postsBoundsChangedNotifications; 00132 BOOL _inhibitFrameAndBoundsChangedNotifications; 00133 00134 #if PLATFORM(DOM) 00135 DOMElement _DOMElement; 00136 DOMElement _DOMContentsElement; 00137 00138 CPArray _DOMImageParts; 00139 CPArray _DOMImageSizes; 00140 00141 unsigned _backgroundType; 00142 #endif 00143 00144 CGRect _dirtyRect; 00145 00146 float _opacity; 00147 CPColor _backgroundColor; 00148 00149 BOOL _autoresizesSubviews; 00150 unsigned _autoresizingMask; 00151 00152 CALayer _layer; 00153 BOOL _wantsLayer; 00154 00155 // Full Screen State 00156 BOOL _isInFullScreenMode; 00157 00158 _CPViewFullScreenModeState _fullScreenModeState; 00159 00160 // Layout Support 00161 BOOL _needsLayout; 00162 JSObject _ephemeralSubviews; 00163 00164 // Theming Support 00165 CPTheme _theme; 00166 CPString _themeClass; 00167 JSObject _themeAttributes; 00168 unsigned _themeState; 00169 00170 JSObject _ephemeralSubviewsForNames; 00171 CPSet _ephereralSubviews; 00172 00173 // Key View Support 00174 CPView _nextKeyView; 00175 CPView _previousKeyView; 00176 00177 unsigned _viewClassFlags; 00178 00179 // ToolTips 00180 CPString _toolTip; 00181 } 00182 00183 /* 00184 Private method for Objective-J. 00185 @ignore 00186 */ 00187 + (void)initialize 00188 { 00189 if (self !== [CPView class]) 00190 return; 00191 00192 #if PLATFORM(DOM) 00193 DOMElementPrototype = document.createElement("div"); 00194 00195 var style = DOMElementPrototype.style; 00196 00197 style.overflow = "hidden"; 00198 style.position = "absolute"; 00199 style.visibility = "visible"; 00200 style.zIndex = 0; 00201 #endif 00202 00203 CachedNotificationCenter = [CPNotificationCenter defaultCenter]; 00204 } 00205 00206 - (void)setupViewFlags 00207 { 00208 var theClass = [self class], 00209 classUID = [theClass UID]; 00210 00211 if (CPViewFlags[classUID] === undefined) 00212 { 00213 var flags = 0; 00214 00215 if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)]) 00216 flags |= CPViewHasCustomDrawRect; 00217 00218 if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)]) 00219 flags |= CPViewHasCustomLayoutSubviews; 00220 00221 CPViewFlags[classUID] = flags; 00222 } 00223 00224 _viewClassFlags = CPViewFlags[classUID]; 00225 } 00226 00227 + (CPSet)keyPathsForValuesAffectingFrame 00228 { 00229 return [CPSet setWithObjects:@"frameOrigin", @"frameSize"]; 00230 } 00231 00232 + (CPSet)keyPathsForValuesAffectingBounds 00233 { 00234 return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"]; 00235 } 00236 00237 + (CPMenu)defaultMenu 00238 { 00239 return nil; 00240 } 00241 00242 - (id)init 00243 { 00244 return [self initWithFrame:CGRectMakeZero()]; 00245 } 00246 00251 - (id)initWithFrame:(CGRect)aFrame 00252 { 00253 self = [super init]; 00254 00255 if (self) 00256 { 00257 var width = _CGRectGetWidth(aFrame), 00258 height = _CGRectGetHeight(aFrame); 00259 00260 _subviews = []; 00261 _registeredDraggedTypes = [CPSet set]; 00262 _registeredDraggedTypesArray = []; 00263 00264 _tag = -1; 00265 00266 _frame = _CGRectMakeCopy(aFrame); 00267 _bounds = _CGRectMake(0.0, 0.0, width, height); 00268 00269 _autoresizingMask = CPViewNotSizable; 00270 _autoresizesSubviews = YES; 00271 _clipsToBounds = YES; 00272 00273 _opacity = 1.0; 00274 _isHidden = NO; 00275 _hitTests = YES; 00276 00277 #if PLATFORM(DOM) 00278 _DOMElement = DOMElementPrototype.cloneNode(false); 00279 00280 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame)); 00281 CPDOMDisplayServerSetStyleSize(_DOMElement, width, height); 00282 00283 _DOMImageParts = []; 00284 _DOMImageSizes = []; 00285 #endif 00286 00287 _theme = [CPTheme defaultTheme]; 00288 _themeState = CPThemeStateNormal; 00289 00290 [self setupViewFlags]; 00291 00292 [self _loadThemeAttributes]; 00293 } 00294 00295 return self; 00296 } 00297 00302 - (CPView)superview 00303 { 00304 return _superview; 00305 } 00306 00311 - (CPArray)subviews 00312 { 00313 return [_subviews copy]; 00314 } 00315 00319 - (CPWindow)window 00320 { 00321 return _window; 00322 } 00323 00328 - (void)addSubview:(CPView)aSubview 00329 { 00330 [self _insertSubview:aSubview atIndex:CPNotFound]; 00331 } 00332 00339 - (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView 00340 { 00341 var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound; 00342 00343 // In other words, if no view, then either all the way at the bottom or all the way at the top. 00344 if (index === CPNotFound) 00345 index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0; 00346 00347 // else, if we have a view, above if above. 00348 else if (anOrderingMode === CPWindowAbove) 00349 ++index; 00350 00351 [self _insertSubview:aSubview atIndex:index]; 00352 } 00353 00354 /* @ignore */ 00355 - (void)_insertSubview:(CPView)aSubview atIndex:(int)anIndex 00356 { 00357 // We will have to adjust the z-index of all views starting at this index. 00358 var count = _subviews.length; 00359 00360 // dirty the key view loop, in case the window wants to auto recalculate it 00361 [[self window] _dirtyKeyViewLoop]; 00362 00363 // If this is already one of our subviews, remove it. 00364 if (aSubview._superview == self) 00365 { 00366 var index = [_subviews indexOfObjectIdenticalTo:aSubview]; 00367 00368 // FIXME: should this be anIndex >= count? (last one) 00369 if (index === anIndex || index === count - 1 && anIndex === count) 00370 return; 00371 00372 [_subviews removeObjectAtIndex:index]; 00373 00374 #if PLATFORM(DOM) 00375 CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement); 00376 #endif 00377 00378 if (anIndex > index) 00379 --anIndex; 00380 00381 //We've effectively made the subviews array shorter, so represent that. 00382 --count; 00383 } 00384 else 00385 { 00386 // Remove the view from its previous superview. 00387 [aSubview removeFromSuperview]; 00388 00389 // Set the subview's window to our own. 00390 [aSubview _setWindow:_window]; 00391 00392 // Notify the subview that it will be moving. 00393 [aSubview viewWillMoveToSuperview:self]; 00394 00395 // Set ourselves as the superview. 00396 aSubview._superview = self; 00397 } 00398 00399 if (anIndex === CPNotFound || anIndex >= count) 00400 { 00401 _subviews.push(aSubview); 00402 00403 #if PLATFORM(DOM) 00404 // Attach the actual node. 00405 CPDOMDisplayServerAppendChild(_DOMElement, aSubview._DOMElement); 00406 #endif 00407 } 00408 else 00409 { 00410 _subviews.splice(anIndex, 0, aSubview); 00411 00412 #if PLATFORM(DOM) 00413 // Attach the actual node. 00414 CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement); 00415 #endif 00416 } 00417 00418 [aSubview setNextResponder:self]; 00419 [aSubview viewDidMoveToSuperview]; 00420 00421 [self didAddSubview:aSubview]; 00422 } 00423 00428 - (void)didAddSubview:(CPView)aSubview 00429 { 00430 } 00431 00436 - (void)removeFromSuperview 00437 { 00438 if (!_superview) 00439 return; 00440 00441 // dirty the key view loop, in case the window wants to auto recalculate it 00442 [[self window] _dirtyKeyViewLoop]; 00443 00444 [_superview willRemoveSubview:self]; 00445 00446 [_superview._subviews removeObject:self]; 00447 00448 #if PLATFORM(DOM) 00449 CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement); 00450 #endif 00451 _superview = nil; 00452 00453 [self _setWindow:nil]; 00454 } 00455 00461 - (void)replaceSubview:(CPView)aSubview with:(CPView)aView 00462 { 00463 if (aSubview._superview != self) 00464 return; 00465 00466 var index = [_subviews indexOfObjectIdenticalTo:aSubview]; 00467 00468 [aSubview removeFromSuperview]; 00469 00470 [self _insertSubview:aView atIndex:index]; 00471 } 00472 00473 - (void)setSubviews:(CPArray)newSubviews 00474 { 00475 if (!newSubviews) 00476 [CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"]; 00477 00478 // Trivial Case 0: Same array somehow 00479 if ([_subviews isEqual:newSubviews]) 00480 return; 00481 00482 // Trivial Case 1: No current subviews, simply add all new subviews. 00483 if ([_subviews count] === 0) 00484 { 00485 var index = 0, 00486 count = [newSubviews count]; 00487 00488 for (; index < count; ++index) 00489 [self addSubview:newSubviews[index]]; 00490 00491 return; 00492 } 00493 00494 // Trivial Case 2: No new subviews, simply remove all current subviews. 00495 if ([newSubviews count] === 0) 00496 { 00497 var count = [_subviews count]; 00498 00499 while (count--) 00500 [_subviews[count] removeFromSuperview]; 00501 00502 return; 00503 } 00504 00505 // Find out the views that were removed. 00506 var removedSubviews = [CPMutableSet setWithArray:_subviews]; 00507 00508 [removedSubviews removeObjectsInArray:newSubviews]; 00509 [removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 00510 00511 // Find out which views need to be added. 00512 var addedSubviews = [CPMutableSet setWithArray:newSubviews]; 00513 00514 [addedSubviews removeObjectsInArray:_subviews]; 00515 00516 var addedSubview = nil, 00517 addedSubviewEnumerator = [addedSubviews objectEnumerator]; 00518 00519 while (addedSubview = [addedSubviewEnumerator nextObject]) 00520 [self addSubview:addedSubview]; 00521 00522 // If the order is fine, no need to reorder. 00523 if ([_subviews isEqual:newSubviews]) 00524 return; 00525 00526 _subviews = [newSubviews copy]; 00527 00528 #if PLATFORM(DOM) 00529 var index = 0, 00530 count = [_subviews count]; 00531 00532 for (; index < count; ++index) 00533 { 00534 var subview = _subviews[index]; 00535 00536 CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement); 00537 CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement); 00538 } 00539 #endif 00540 } 00541 00542 /* @ignore */ 00543 - (void)_setWindow:(CPWindow)aWindow 00544 { 00545 if (_window === aWindow) 00546 return; 00547 00548 [[self window] _dirtyKeyViewLoop]; 00549 00550 // Clear out first responder if we're the first responder and leaving. 00551 if ([_window firstResponder] === self) 00552 [_window makeFirstResponder:nil]; 00553 00554 // Notify the view and its subviews 00555 [self viewWillMoveToWindow:aWindow]; 00556 00557 // Unregister the drag events from the current window and register 00558 // them in the new window. 00559 if (_registeredDraggedTypes) 00560 { 00561 [_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; 00562 [aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes]; 00563 } 00564 00565 _window = aWindow; 00566 00567 var count = [_subviews count]; 00568 00569 while (count--) 00570 [_subviews[count] _setWindow:aWindow]; 00571 00572 [self viewDidMoveToWindow]; 00573 00574 [[self window] _dirtyKeyViewLoop]; 00575 } 00576 00581 - (BOOL)isDescendantOf:(CPView)aView 00582 { 00583 var view = self; 00584 00585 do 00586 { 00587 if (view == aView) 00588 return YES; 00589 } while(view = [view superview]) 00590 00591 return NO; 00592 } 00593 00597 - (void)viewDidMoveToSuperview 00598 { 00599 // if (_graphicsContext) 00600 [self setNeedsDisplay:YES]; 00601 } 00602 00606 - (void)viewDidMoveToWindow 00607 { 00608 } 00609 00614 - (void)viewWillMoveToSuperview:(CPView)aView 00615 { 00616 } 00617 00622 - (void)viewWillMoveToWindow:(CPWindow)aWindow 00623 { 00624 } 00625 00630 - (void)willRemoveSubview:(CPView)aView 00631 { 00632 } 00633 00638 - (CPMenuItem)enclosingMenuItem 00639 { 00640 var view = self; 00641 00642 while (view && ![view isKindOfClass:[_CPMenuItemView class]]) 00643 view = [view superview]; 00644 00645 if (view) 00646 return view._menuItem; 00647 00648 return nil; 00649 /* var view = self, 00650 enclosingMenuItem = _enclosingMenuItem; 00651 00652 while (!enclosingMenuItem && (view = view._enclosingMenuItem)) 00653 view = [view superview]; 00654 00655 return enclosingMenuItem;*/ 00656 } 00657 00658 - (void)setTag:(CPInteger)aTag 00659 { 00660 _tag = aTag; 00661 } 00662 00663 - (CPInteger)tag 00664 { 00665 return _tag; 00666 } 00667 00668 - (CPView)viewWithTag:(CPInteger)aTag 00669 { 00670 if ([self tag] == aTag) 00671 return self; 00672 00673 var index = 0, 00674 count = _subviews.length; 00675 00676 for (; index < count; ++index) 00677 { 00678 var view = [_subviews[index] viewWithTag:aTag]; 00679 00680 if (view) 00681 return view; 00682 } 00683 00684 return nil; 00685 } 00686 00691 - (BOOL)isFlipped 00692 { 00693 return YES; 00694 } 00695 00703 - (void)setFrame:(CGRect)aFrame 00704 { 00705 if (_CGRectEqualToRect(_frame, aFrame)) 00706 return; 00707 00708 _inhibitFrameAndBoundsChangedNotifications = YES; 00709 00710 [self setFrameOrigin:aFrame.origin]; 00711 [self setFrameSize:aFrame.size]; 00712 00713 _inhibitFrameAndBoundsChangedNotifications = NO; 00714 00715 if (_postsFrameChangedNotifications) 00716 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self]; 00717 } 00718 00723 - (CGRect)frame 00724 { 00725 return _CGRectMakeCopy(_frame); 00726 } 00727 00728 - (CGPoint)frameOrigin 00729 { 00730 return _CGPointMakeCopy(_frame.origin); 00731 } 00732 00733 - (CGSize)frameSize 00734 { 00735 return _CGSizeMakeCopy(_frame.size); 00736 } 00737 00745 - (void)setCenter:(CGPoint)aPoint 00746 { 00747 [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)]; 00748 } 00749 00754 - (CGPoint)center 00755 { 00756 return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y); 00757 } 00758 00766 - (void)setFrameOrigin:(CGPoint)aPoint 00767 { 00768 var origin = _frame.origin; 00769 00770 if (!aPoint || _CGPointEqualToPoint(origin, aPoint)) 00771 return; 00772 00773 origin.x = aPoint.x; 00774 origin.y = aPoint.y; 00775 00776 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) 00777 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self]; 00778 00779 #if PLATFORM(DOM) 00780 var transform = _superview ? _superview._boundsTransform : NULL; 00781 00782 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y); 00783 #endif 00784 } 00785 00792 - (void)setFrameSize:(CGSize)aSize 00793 { 00794 var size = _frame.size; 00795 00796 if (!aSize || _CGSizeEqualToSize(size, aSize)) 00797 return; 00798 00799 var oldSize = _CGSizeMakeCopy(size); 00800 00801 size.width = aSize.width; 00802 size.height = aSize.height; 00803 00804 if (YES) 00805 { 00806 _bounds.size.width = aSize.width; 00807 _bounds.size.height = aSize.height; 00808 } 00809 00810 if (_layer) 00811 [_layer _owningViewBoundsChanged]; 00812 00813 if (_autoresizesSubviews) 00814 [self resizeSubviewsWithOldSize:oldSize]; 00815 00816 [self setNeedsLayout]; 00817 [self setNeedsDisplay:YES]; 00818 00819 #if PLATFORM(DOM) 00820 CPDOMDisplayServerSetStyleSize(_DOMElement, size.width, size.height); 00821 00822 if (_DOMContentsElement) 00823 { 00824 CPDOMDisplayServerSetSize(_DOMContentsElement, size.width, size.height); 00825 CPDOMDisplayServerSetStyleSize(_DOMContentsElement, size.width, size.height); 00826 } 00827 00828 if (_backgroundType !== BackgroundTrivialColor) 00829 { 00830 if (_backgroundType === BackgroundTransparentColor) 00831 { 00832 CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height); 00833 } 00834 else 00835 { 00836 var images = [[_backgroundColor patternImage] imageSlices]; 00837 00838 if (_backgroundType === BackgroundVerticalThreePartImage) 00839 { 00840 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height); 00841 } 00842 else if (_backgroundType === BackgroundHorizontalThreePartImage) 00843 { 00844 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height); 00845 } 00846 else if (_backgroundType === BackgroundNinePartImage) 00847 { 00848 var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, 00849 height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height; 00850 00851 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height); 00852 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height); 00853 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height); 00854 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height); 00855 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height); 00856 } 00857 } 00858 } 00859 #endif 00860 00861 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) 00862 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self]; 00863 } 00864 00870 - (void)setBounds:(CGRect)bounds 00871 { 00872 if (_CGRectEqualToRect(_bounds, bounds)) 00873 return; 00874 00875 _inhibitFrameAndBoundsChangedNotifications = YES; 00876 00877 [self setBoundsOrigin:bounds.origin]; 00878 [self setBoundsSize:bounds.size]; 00879 00880 _inhibitFrameAndBoundsChangedNotifications = NO; 00881 00882 if (_postsBoundsChangedNotifications) 00883 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; 00884 } 00885 00890 - (CGRect)bounds 00891 { 00892 return _CGRectMakeCopy(_bounds); 00893 } 00894 00895 - (CGPoint)boundsOrigin 00896 { 00897 return _CGPointMakeCopy(_bounds.origin); 00898 } 00899 00900 - (CGSize)boundsSize 00901 { 00902 return _CGSizeMakeCopy(_bounds.size); 00903 } 00904 00911 - (void)setBoundsOrigin:(CGPoint)aPoint 00912 { 00913 var origin = _bounds.origin; 00914 00915 if (_CGPointEqualToPoint(origin, aPoint)) 00916 return; 00917 00918 origin.x = aPoint.x; 00919 origin.y = aPoint.y; 00920 00921 if (origin.x != 0 || origin.y != 0) 00922 { 00923 _boundsTransform = _CGAffineTransformMakeTranslation(-origin.x, -origin.y); 00924 _inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform); 00925 } 00926 else 00927 { 00928 _boundsTransform = nil; 00929 _inverseBoundsTransform = nil; 00930 } 00931 00932 #if PLATFORM(DOM) 00933 var index = _subviews.length; 00934 00935 while (index--) 00936 { 00937 var view = _subviews[index], 00938 origin = view._frame.origin; 00939 00940 CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y); 00941 } 00942 #endif 00943 00944 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) 00945 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; 00946 } 00947 00954 - (void)setBoundsSize:(CGSize)aSize 00955 { 00956 var size = _bounds.size; 00957 00958 if (_CGSizeEqualToSize(size, aSize)) 00959 return; 00960 00961 var frameSize = _frame.size; 00962 00963 if (!_CGSizeEqualToSize(size, frameSize)) 00964 { 00965 var origin = _bounds.origin; 00966 00967 origin.x /= size.width / frameSize.width; 00968 origin.y /= size.height / frameSize.height; 00969 } 00970 00971 size.width = aSize.width; 00972 size.height = aSize.height; 00973 00974 if (!_CGSizeEqualToSize(size, frameSize)) 00975 { 00976 var origin = _bounds.origin; 00977 00978 origin.x *= size.width / frameSize.width; 00979 origin.y *= size.height / frameSize.height; 00980 } 00981 00982 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) 00983 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; 00984 } 00985 00986 00991 - (void)resizeWithOldSuperviewSize:(CGSize)aSize 00992 { 00993 var mask = [self autoresizingMask]; 00994 00995 if (mask == CPViewNotSizable) 00996 return; 00997 00998 var frame = _superview._frame, 00999 newFrame = _CGRectMakeCopy(_frame), 01000 dX = (_CGRectGetWidth(frame) - aSize.width) / 01001 (((mask & CPViewMinXMargin) ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)), 01002 dY = (_CGRectGetHeight(frame) - aSize.height) / 01003 ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0)); 01004 01005 if (mask & CPViewMinXMargin) 01006 newFrame.origin.x += dX; 01007 if (mask & CPViewWidthSizable) 01008 newFrame.size.width += dX; 01009 01010 if (mask & CPViewMinYMargin) 01011 newFrame.origin.y += dY; 01012 if (mask & CPViewHeightSizable) 01013 newFrame.size.height += dY; 01014 01015 [self setFrame:newFrame]; 01016 } 01017 01022 - (void)resizeSubviewsWithOldSize:(CGSize)aSize 01023 { 01024 var count = _subviews.length; 01025 01026 while (count--) 01027 [_subviews[count] resizeWithOldSuperviewSize:aSize]; 01028 } 01029 01037 - (void)setAutoresizesSubviews:(BOOL)aFlag 01038 { 01039 _autoresizesSubviews = !!aFlag; 01040 } 01041 01046 - (BOOL)autoresizesSubviews 01047 { 01048 return _autoresizesSubviews; 01049 } 01050 01055 - (void)setAutoresizingMask:(unsigned)aMask 01056 { 01057 _autoresizingMask = aMask; 01058 } 01059 01063 - (unsigned)autoresizingMask 01064 { 01065 return _autoresizingMask; 01066 } 01067 01068 // Fullscreen Mode 01069 01073 - (BOOL)enterFullScreenMode 01074 { 01075 return [self enterFullScreenMode:nil withOptions:nil]; 01076 } 01077 01083 - (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options 01084 { 01085 _fullScreenModeState = _CPViewFullScreenModeStateMake(self); 01086 01087 var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask]; 01088 01089 [fullScreenWindow setLevel:CPScreenSaverWindowLevel]; 01090 [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 01091 01092 var contentView = [fullScreenWindow contentView]; 01093 01094 [contentView setBackgroundColor:[CPColor blackColor]]; 01095 [contentView addSubview:self]; 01096 01097 [self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 01098 [self setFrame:CGRectMakeCopy([contentView bounds])]; 01099 01100 [fullScreenWindow makeKeyAndOrderFront:self]; 01101 01102 [fullScreenWindow makeFirstResponder:self]; 01103 01104 _isInFullScreenMode = YES; 01105 01106 return YES; 01107 } 01108 01112 - (void)exitFullScreenMode 01113 { 01114 [self exitFullScreenModeWithOptions:nil]; 01115 } 01116 01121 - (void)exitFullScreenModeWithOptions:(CPDictionary)options 01122 { 01123 if (!_isInFullScreenMode) 01124 return; 01125 01126 _isInFullScreenMode = NO; 01127 01128 [self setFrame:_fullScreenModeState.frame]; 01129 [self setAutoresizingMask:_fullScreenModeState.autoresizingMask]; 01130 [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index]; 01131 01132 [[self window] orderOut:self]; 01133 } 01134 01138 - (BOOL)isInFullScreenMode 01139 { 01140 return _isInFullScreenMode; 01141 } 01142 01147 - (void)setHidden:(BOOL)aFlag 01148 { 01149 aFlag = !!aFlag; 01150 01151 if (_isHidden === aFlag) 01152 return; 01153 01154 // FIXME: Should we return to visibility? This breaks in FireFox, Opera, and IE. 01155 // _DOMElement.style.visibility = (_isHidden = aFlag) ? "hidden" : "visible"; 01156 _isHidden = aFlag; 01157 #if PLATFORM(DOM) 01158 _DOMElement.style.display = _isHidden ? "none" : "block"; 01159 #endif 01160 01161 if (aFlag) 01162 { 01163 var view = [_window firstResponder]; 01164 01165 if ([view isKindOfClass:[CPView class]]) 01166 { 01167 do 01168 { 01169 if (self == view) 01170 { 01171 [_window makeFirstResponder:[self nextValidKeyView]]; 01172 break; 01173 } 01174 } 01175 while (view = [view superview]); 01176 } 01177 01178 [self _notifyViewDidHide]; 01179 } 01180 else 01181 { 01182 [self _notifyViewDidUnhide]; 01183 } 01184 } 01185 01186 - (void)_notifyViewDidHide 01187 { 01188 [self viewDidHide]; 01189 01190 var count = [_subviews count]; 01191 while (count--) 01192 [_subviews[count] _notifyViewDidHide]; 01193 } 01194 01195 - (void)_notifyViewDidUnhide 01196 { 01197 [self viewDidUnhide]; 01198 01199 var count = [_subviews count]; 01200 while (count--) 01201 [_subviews[count] _notifyViewDidUnhide]; 01202 } 01203 01207 - (BOOL)isHidden 01208 { 01209 return _isHidden; 01210 } 01211 01212 - (void)setClipsToBounds:(BOOL)shouldClip 01213 { 01214 if (_clipsToBounds === shouldClip) 01215 return; 01216 01217 _clipsToBounds = shouldClip; 01218 01219 #if PLATFORM(DOM) 01220 _DOMElement.style.overflow = _clipsToBounds ? "hidden" : "visible"; 01221 #endif 01222 } 01223 01224 - (BOOL)clipsToBounds 01225 { 01226 return _clipsToBounds; 01227 } 01228 01234 - (void)setAlphaValue:(float)anAlphaValue 01235 { 01236 if (_opacity == anAlphaValue) 01237 return; 01238 01239 _opacity = anAlphaValue; 01240 01241 #if PLATFORM(DOM) 01242 01243 if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature)) 01244 { 01245 if (anAlphaValue === 1.0) 01246 try { _DOMElement.style.removeAttribute("filter") } catch (anException) { } 01247 else 01248 _DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")"; 01249 } 01250 else 01251 _DOMElement.style.opacity = anAlphaValue; 01252 01253 #endif 01254 } 01255 01260 - (float)alphaValue 01261 { 01262 return _opacity; 01263 } 01264 01269 - (BOOL)isHiddenOrHasHiddenAncestor 01270 { 01271 var view = self; 01272 01273 while (view && ![view isHidden]) 01274 view = [view superview]; 01275 01276 return view !== nil; 01277 } 01278 01282 - (BOOL)_isVisible 01283 { 01284 return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible]; 01285 } 01286 01296 - (void)viewDidHide 01297 { 01298 01299 } 01300 01310 - (void)viewDidUnhide 01311 { 01312 01313 } 01314 01320 //FIXME: should be NO by default? 01321 - (BOOL)acceptsFirstMouse:(CPEvent)anEvent 01322 { 01323 return YES; 01324 } 01325 01330 - (BOOL)hitTests 01331 { 01332 return _hitTests; 01333 } 01334 01339 - (void)setHitTests:(BOOL)shouldHitTest 01340 { 01341 _hitTests = !!shouldHitTest; 01342 } 01343 01349 - (CPView)hitTest:(CPPoint)aPoint 01350 { 01351 if (_isHidden || !_hitTests || !CPRectContainsPoint(_frame, aPoint)) 01352 return nil; 01353 01354 var view = nil, 01355 i = _subviews.length, 01356 adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame)); 01357 01358 if (_inverseBoundsTransform) 01359 adjustedPoint = _CGPointApplyAffineTransform(adjustedPoint, _inverseBoundsTransform); 01360 01361 while (i--) 01362 if (view = [_subviews[i] hitTest:adjustedPoint]) 01363 return view; 01364 01365 return self; 01366 } 01367 01371 - (BOOL)needsPanelToBecomeKey 01372 { 01373 return NO; 01374 } 01375 01380 - (BOOL)mouseDownCanMoveWindow 01381 { 01382 return ![self isOpaque]; 01383 } 01384 01385 - (void)mouseDown:(CPEvent)anEvent 01386 { 01387 if ([self mouseDownCanMoveWindow]) 01388 [super mouseDown:anEvent]; 01389 } 01390 01391 - (void)rightMouseDown:(CPEvent)anEvent 01392 { 01393 var menu = [self menuForEvent:anEvent]; 01394 if (menu) 01395 [CPMenu popUpContextMenu:menu withEvent:anEvent forView:self]; 01396 else if ([[self nextResponder] isKindOfClass:CPView]) 01397 [super rightMouseDown:anEvent]; 01398 else 01399 [[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES]; 01400 } 01401 01402 - (CPMenu)menuForEvent:(CPEvent)anEvent 01403 { 01404 return [self menu] || [[self class] defaultMenu]; 01405 } 01406 01411 - (void)setBackgroundColor:(CPColor)aColor 01412 { 01413 if (_backgroundColor == aColor) 01414 return; 01415 01416 if (aColor == [CPNull null]) 01417 aColor = nil; 01418 01419 _backgroundColor = aColor; 01420 01421 #if PLATFORM(DOM) 01422 var patternImage = [_backgroundColor patternImage], 01423 colorExists = _backgroundColor && ([_backgroundColor patternImage] || [_backgroundColor alphaComponent] > 0.0), 01424 colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0, 01425 supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature), 01426 colorNeedsDOMElement = colorHasAlpha && !supportsRGBA, 01427 amount = 0; 01428 01429 if ([patternImage isThreePartImage]) 01430 { 01431 _backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage; 01432 amount = 3 - _DOMImageParts.length; 01433 } 01434 else if ([patternImage isNinePartImage]) 01435 { 01436 _backgroundType = BackgroundNinePartImage; 01437 amount = 9 - _DOMImageParts.length; 01438 } 01439 else 01440 { 01441 _backgroundType = colorNeedsDOMElement ? BackgroundTransparentColor : BackgroundTrivialColor; 01442 amount = (colorNeedsDOMElement ? 1 : 0) - _DOMImageParts.length; 01443 } 01444 01445 if (amount > 0) 01446 { 01447 while (amount--) 01448 { 01449 var DOMElement = DOMElementPrototype.cloneNode(false); 01450 01451 DOMElement.style.zIndex = -1000; 01452 01453 _DOMImageParts.push(DOMElement); 01454 _DOMElement.appendChild(DOMElement); 01455 } 01456 } 01457 else 01458 { 01459 amount = -amount; 01460 while (amount--) 01461 _DOMElement.removeChild(_DOMImageParts.pop()); 01462 } 01463 01464 if (_backgroundType === BackgroundTrivialColor || _backgroundType === BackgroundTransparentColor) 01465 { 01466 var colorCSS = colorExists ? [_backgroundColor cssString] : ""; 01467 01468 if (colorNeedsDOMElement) 01469 { 01470 _DOMElement.style.background = ""; 01471 _DOMImageParts[0].style.background = [_backgroundColor cssString]; 01472 01473 if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature)) 01474 _DOMImageParts[0].style.filter = "alpha(opacity=" + [_backgroundColor alphaComponent] * 100 + ")"; 01475 else 01476 _DOMImageParts[0].style.opacity = [_backgroundColor alphaComponent]; 01477 01478 var size = [self bounds].size; 01479 CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height); 01480 } 01481 else 01482 _DOMElement.style.background = colorCSS; 01483 } 01484 else 01485 { 01486 var slices = [patternImage imageSlices], 01487 count = MIN(_DOMImageParts.length, slices.length), 01488 frameSize = _frame.size; 01489 01490 while (count--) 01491 { 01492 var image = slices[count], 01493 size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero(); 01494 01495 CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height); 01496 01497 _DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : ""; 01498 01499 if (!supportsRGBA) 01500 { 01501 if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature)) 01502 try { _DOMImageParts[count].style.removeAttribute("filter") } catch (anException) { } 01503 else 01504 _DOMImageParts[count].style.opacity = 1.0; 01505 } 01506 } 01507 01508 if (_backgroundType == BackgroundNinePartImage) 01509 { 01510 var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, 01511 height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height; 01512 01513 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height); 01514 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height); 01515 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height); 01516 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height); 01517 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height); 01518 01519 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); 01520 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); 01521 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); 01522 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[3], NULL, 0.0, _DOMImageSizes[1].height); 01523 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[4], NULL, _DOMImageSizes[0].width, _DOMImageSizes[0].height); 01524 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[5], NULL, 0.0, _DOMImageSizes[1].height); 01525 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[6], NULL, 0.0, 0.0); 01526 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[7], NULL, _DOMImageSizes[6].width, 0.0); 01527 CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0); 01528 } 01529 else if (_backgroundType == BackgroundVerticalThreePartImage) 01530 { 01531 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height); 01532 01533 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); 01534 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height); 01535 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0); 01536 } 01537 else if (_backgroundType == BackgroundHorizontalThreePartImage) 01538 { 01539 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height); 01540 01541 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); 01542 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); 01543 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); 01544 } 01545 } 01546 #endif 01547 } 01548 01552 - (CPColor)backgroundColor 01553 { 01554 return _backgroundColor; 01555 } 01556 01557 // Converting Coordinates 01564 - (CGPoint)convertPoint:(CGPoint)aPoint fromView:(CPView)aView 01565 { 01566 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(aView, self)); 01567 } 01568 01574 - (CGPoint)convertPointFromBase:(CGPoint)aPoint 01575 { 01576 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(nil, self)); 01577 } 01578 01585 - (CGPoint)convertPoint:(CGPoint)aPoint toView:(CPView)aView 01586 { 01587 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, aView)); 01588 } 01589 01595 - (CGPoint)convertPointToBase:(CGPoint)aPoint 01596 { 01597 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, nil)); 01598 } 01599 01606 - (CGSize)convertSize:(CGSize)aSize fromView:(CPView)aView 01607 { 01608 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(aView, self)); 01609 } 01610 01617 - (CGSize)convertSize:(CGSize)aSize toView:(CPView)aView 01618 { 01619 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(self, aView)); 01620 } 01621 01628 - (CGRect)convertRect:(CGRect)aRect fromView:(CPView)aView 01629 { 01630 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(aView, self)); 01631 } 01632 01638 - (CGRect)convertRectFromBase:(CGRect)aRect 01639 { 01640 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(nil, self)); 01641 } 01642 01649 - (CGRect)convertRect:(CGRect)aRect toView:(CPView)aView 01650 { 01651 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, aView)); 01652 } 01653 01659 - (CGRect)convertRectToBase:(CGRect)aRect 01660 { 01661 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, nil)); 01662 } 01663 01676 - (void)setPostsFrameChangedNotifications:(BOOL)shouldPostFrameChangedNotifications 01677 { 01678 shouldPostFrameChangedNotifications = !!shouldPostFrameChangedNotifications; 01679 01680 if (_postsFrameChangedNotifications === shouldPostFrameChangedNotifications) 01681 return; 01682 01683 _postsFrameChangedNotifications = shouldPostFrameChangedNotifications; 01684 01685 if (_postsFrameChangedNotifications) 01686 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self]; 01687 } 01688 01692 - (BOOL)postsFrameChangedNotifications 01693 { 01694 return _postsFrameChangedNotifications; 01695 } 01696 01709 - (void)setPostsBoundsChangedNotifications:(BOOL)shouldPostBoundsChangedNotifications 01710 { 01711 shouldPostBoundsChangedNotifications = !!shouldPostBoundsChangedNotifications; 01712 01713 if (_postsBoundsChangedNotifications === shouldPostBoundsChangedNotifications) 01714 return; 01715 01716 _postsBoundsChangedNotifications = shouldPostBoundsChangedNotifications; 01717 01718 if (_postsBoundsChangedNotifications) 01719 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; 01720 } 01721 01727 - (BOOL)postsBoundsChangedNotifications 01728 { 01729 return _postsBoundsChangedNotifications; 01730 } 01731 01742 - (void)dragImage:(CPImage)anImage at:(CGPoint)aLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack 01743 { 01744 [_window dragImage:anImage at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack]; 01745 } 01746 01757 - (void)dragView:(CPView)aView at:(CPPoint)aLocation offset:(CPSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack 01758 { 01759 [_window dragView:aView at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack]; 01760 } 01761 01766 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes 01767 { 01768 if (!pasteboardTypes || ![pasteboardTypes count]) 01769 return; 01770 01771 var theWindow = [self window]; 01772 01773 [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; 01774 [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; 01775 [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes]; 01776 01777 _registeredDraggedTypesArray = nil; 01778 } 01779 01784 - (CPArray)registeredDraggedTypes 01785 { 01786 if (!_registeredDraggedTypesArray) 01787 _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; 01788 01789 return _registeredDraggedTypesArray; 01790 } 01791 01795 - (void)unregisterDraggedTypes 01796 { 01797 [[self window] _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; 01798 01799 _registeredDraggedTypes = [CPSet set]; 01800 _registeredDraggedTypesArray = []; 01801 } 01802 01807 - (void)drawRect:(CPRect)aRect 01808 { 01809 01810 } 01811 01812 // Displaying 01813 01817 - (void)setNeedsDisplay:(BOOL)aFlag 01818 { 01819 if (aFlag) 01820 [self setNeedsDisplayInRect:[self bounds]]; 01821 } 01822 01827 - (void)setNeedsDisplayInRect:(CPRect)aRect 01828 { 01829 if (!(_viewClassFlags & CPViewHasCustomDrawRect)) 01830 return; 01831 01832 if (_CGRectIsEmpty(aRect)) 01833 return; 01834 01835 if (_dirtyRect && !_CGRectIsEmpty(_dirtyRect)) 01836 _dirtyRect = CGRectUnion(aRect, _dirtyRect); 01837 else 01838 _dirtyRect = _CGRectMakeCopy(aRect); 01839 01840 _CPDisplayServerAddDisplayObject(self); 01841 } 01842 01843 - (BOOL)needsDisplay 01844 { 01845 return _dirtyRect && !_CGRectIsEmpty(_dirtyRect); 01846 } 01847 01851 - (void)displayIfNeeded 01852 { 01853 if ([self needsDisplay]) 01854 [self displayRect:_dirtyRect]; 01855 } 01856 01860 - (void)display 01861 { 01862 [self displayRect:[self visibleRect]]; 01863 } 01864 01865 - (void)displayIfNeededInRect:(CGRect)aRect 01866 { 01867 if ([self needsDisplay]) 01868 [self displayRect:aRect]; 01869 } 01870 01875 - (void)displayRect:(CPRect)aRect 01876 { 01877 [self viewWillDraw]; 01878 01879 [self displayRectIgnoringOpacity:aRect inContext:nil]; 01880 01881 _dirtyRect = NULL; 01882 } 01883 01884 - (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext 01885 { 01886 if ([self isHidden]) 01887 return; 01888 01889 #if PLATFORM(DOM) 01890 [self lockFocus]; 01891 01892 CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect); 01893 01894 [self drawRect:aRect]; 01895 [self unlockFocus]; 01896 #endif 01897 } 01898 01899 - (void)viewWillDraw 01900 { 01901 } 01902 01906 - (void)lockFocus 01907 { 01908 if (!_graphicsContext) 01909 { 01910 var graphicsPort = CGBitmapGraphicsContextCreate(); 01911 01912 _DOMContentsElement = graphicsPort.DOMElement; 01913 01914 _DOMContentsElement.style.zIndex = -100; 01915 01916 _DOMContentsElement.style.overflow = "hidden"; 01917 _DOMContentsElement.style.position = "absolute"; 01918 _DOMContentsElement.style.visibility = "visible"; 01919 01920 _DOMContentsElement.width = ROUND(_CGRectGetWidth(_frame)); 01921 _DOMContentsElement.height = ROUND(_CGRectGetHeight(_frame)); 01922 01923 _DOMContentsElement.style.top = "0px"; 01924 _DOMContentsElement.style.left = "0px"; 01925 _DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px"; 01926 _DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px"; 01927 01928 #if PLATFORM(DOM) 01929 CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement); 01930 #endif 01931 _graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES]; 01932 } 01933 01934 [CPGraphicsContext setCurrentContext:_graphicsContext]; 01935 01936 CGContextSaveGState([_graphicsContext graphicsPort]); 01937 } 01938 01942 - (void)unlockFocus 01943 { 01944 CGContextRestoreGState([_graphicsContext graphicsPort]); 01945 01946 [CPGraphicsContext setCurrentContext:nil]; 01947 } 01948 01949 - (void)setNeedsLayout 01950 { 01951 if (!(_viewClassFlags & CPViewHasCustomLayoutSubviews)) 01952 return; 01953 01954 _needsLayout = YES; 01955 01956 _CPDisplayServerAddLayoutObject(self); 01957 } 01958 01959 - (void)layoutIfNeeded 01960 { 01961 if (_needsLayout) 01962 { 01963 _needsLayout = NO; 01964 01965 [self layoutSubviews]; 01966 } 01967 } 01968 01969 - (void)layoutSubviews 01970 { 01971 } 01972 01976 - (BOOL)isOpaque 01977 { 01978 return NO; 01979 } 01980 01984 - (CGRect)visibleRect 01985 { 01986 if (!_superview) 01987 return _bounds; 01988 01989 return CGRectIntersection([self convertRect:[_superview visibleRect] fromView:_superview], _bounds); 01990 } 01991 01992 // Scrolling 01993 /* @ignore */ 01994 - (CPScrollView)_enclosingClipView 01995 { 01996 var superview = _superview, 01997 clipViewClass = [CPClipView class]; 01998 01999 while (superview && ![superview isKindOfClass:clipViewClass]) 02000 superview = superview._superview; 02001 02002 return superview; 02003 } 02004 02009 - (void)scrollPoint:(CGPoint)aPoint 02010 { 02011 var clipView = [self _enclosingClipView]; 02012 02013 if (!clipView) 02014 return; 02015 02016 [clipView scrollToPoint:[self convertPoint:aPoint toView:clipView]]; 02017 } 02018 02024 - (BOOL)scrollRectToVisible:(CGRect)aRect 02025 { 02026 var visibleRect = [self visibleRect]; 02027 02028 // Make sure we have a rect that exists. 02029 aRect = CGRectIntersection(aRect, _bounds); 02030 02031 // If aRect is empty or is already visible then no scrolling required. 02032 if (_CGRectIsEmpty(aRect) || CGRectContainsRect(visibleRect, aRect)) 02033 return NO; 02034 02035 var enclosingClipView = [self _enclosingClipView]; 02036 02037 // If we're not in a clip view, then there isn't much we can do. 02038 if (!enclosingClipView) 02039 return NO; 02040 02041 var scrollPoint = _CGPointMakeCopy(visibleRect.origin); 02042 02043 // One of the following has to be true since our current visible rect didn't contain aRect. 02044 if (_CGRectGetMinX(aRect) <= _CGRectGetMinX(visibleRect)) 02045 scrollPoint.x = _CGRectGetMinX(aRect); 02046 else if (_CGRectGetMaxX(aRect) > _CGRectGetMaxX(visibleRect)) 02047 scrollPoint.x += _CGRectGetMaxX(aRect) - _CGRectGetMaxX(visibleRect); 02048 02049 if (_CGRectGetMinY(aRect) <= _CGRectGetMinY(visibleRect)) 02050 scrollPoint.y = CGRectGetMinY(aRect); 02051 else if (_CGRectGetMaxY(aRect) > _CGRectGetMaxY(visibleRect)) 02052 scrollPoint.y += _CGRectGetMaxY(aRect) - _CGRectGetMaxY(visibleRect); 02053 02054 [enclosingClipView scrollToPoint:CGPointMake(scrollPoint.x, scrollPoint.y)]; 02055 02056 return YES; 02057 } 02058 02059 /* 02060 FIXME Not yet implemented 02061 */ 02062 - (BOOL)autoscroll:(CPEvent)anEvent 02063 { 02064 return [[self superview] autoscroll:anEvent]; 02065 } 02066 02073 - (CGRect)adjustScroll:(CGRect)proposedVisibleRect 02074 { 02075 return proposedVisibleRect; 02076 } 02077 02081 - (void)scrollRect:(CGRect)aRect by:(float)anAmount 02082 { 02083 02084 } 02085 02090 - (CPScrollView)enclosingScrollView 02091 { 02092 var superview = _superview, 02093 scrollViewClass = [CPScrollView class]; 02094 02095 while (superview && ![superview isKindOfClass:scrollViewClass]) 02096 superview = superview._superview; 02097 02098 return superview; 02099 } 02100 02106 - (void)scrollClipView:(CPClipView)aClipView toPoint:(CGPoint)aPoint 02107 { 02108 [aClipView scrollToPoint:aPoint]; 02109 } 02110 02116 - (void)reflectScrolledClipView:(CPClipView)aClipView 02117 { 02118 } 02119 02120 @end 02121 02122 @implementation CPView (KeyView) 02123 02138 - (BOOL)performKeyEquivalent:(CPEvent)anEvent 02139 { 02140 var count = [_subviews count]; 02141 02142 // Is reverse iteration correct here? It matches the other (correct) code like hit testing. 02143 while (count--) 02144 if ([_subviews[count] performKeyEquivalent:anEvent]) 02145 return YES; 02146 02147 return NO; 02148 } 02149 02150 - (BOOL)canBecomeKeyView 02151 { 02152 return [self acceptsFirstResponder] && ![self isHiddenOrHasHiddenAncestor]; 02153 } 02154 02155 - (CPView)nextKeyView 02156 { 02157 return _nextKeyView; 02158 } 02159 02160 - (CPView)nextValidKeyView 02161 { 02162 var result = [self nextKeyView], 02163 firstResult = result; 02164 02165 while (result && ![result canBecomeKeyView]) 02166 { 02167 result = [result nextKeyView]; 02168 02169 // Cycled. 02170 if (result === firstResult) 02171 return nil; 02172 } 02173 02174 return result; 02175 } 02176 02177 - (CPView)previousKeyView 02178 { 02179 return _previousKeyView; 02180 } 02181 02182 - (CPView)previousValidKeyView 02183 { 02184 var result = [self previousKeyView], 02185 firstResult = result; 02186 02187 while (result && ![result canBecomeKeyView]) 02188 { 02189 result = [result previousKeyView]; 02190 02191 // Cycled. 02192 if (result === firstResult) 02193 return nil; 02194 } 02195 02196 return result; 02197 } 02198 02199 - (void)_setPreviousKeyView:(CPView)previous 02200 { 02201 if ([previous isEqual:self]) 02202 _previousKeyView = nil; 02203 else 02204 _previousKeyView = previous; 02205 } 02206 02207 - (void)setNextKeyView:(CPView)next 02208 { 02209 if ([next isEqual:self]) 02210 _nextKeyView = nil; 02211 else 02212 { 02213 _nextKeyView = next; 02214 [_nextKeyView _setPreviousKeyView:self]; 02215 } 02216 } 02217 02218 @end 02219 02220 @implementation CPView (CoreAnimationAdditions) 02221 02225 - (void)setLayer:(CALayer)aLayer 02226 { 02227 if (_layer == aLayer) 02228 return; 02229 02230 if (_layer) 02231 { 02232 _layer._owningView = nil; 02233 #if PLATFORM(DOM) 02234 _DOMElement.removeChild(_layer._DOMElement); 02235 #endif 02236 } 02237 02238 _layer = aLayer; 02239 02240 if (_layer) 02241 { 02242 var bounds = CGRectMakeCopy([self bounds]); 02243 02244 [_layer _setOwningView:self]; 02245 02246 #if PLATFORM(DOM) 02247 _layer._DOMElement.style.zIndex = 100; 02248 02249 _DOMElement.appendChild(_layer._DOMElement); 02250 #endif 02251 } 02252 } 02253 02257 - (CALayer)layer 02258 { 02259 return _layer; 02260 } 02261 02266 - (void)setWantsLayer:(BOOL)aFlag 02267 { 02268 _wantsLayer = !!aFlag; 02269 } 02270 02275 - (BOOL)wantsLayer 02276 { 02277 return _wantsLayer; 02278 } 02279 02280 @end 02281 02282 @implementation CPView (Theming) 02283 #pragma mark Theme States 02284 02285 - (unsigned)themeState 02286 { 02287 return _themeState; 02288 } 02289 02290 - (BOOL)hasThemeState:(CPThemeState)aState 02291 { 02292 // Because CPThemeStateNormal is defined as 0 we need to check for it explicitly here 02293 if (aState === CPThemeStateNormal && _themeState === CPThemeStateNormal) 02294 return YES; 02295 02296 return !!(_themeState & ((typeof aState === "string") ? CPThemeState(aState) : aState)); 02297 } 02298 02299 - (BOOL)setThemeState:(CPThemeState)aState 02300 { 02301 var newState = (typeof aState === "string") ? CPThemeState(aState) : aState; 02302 02303 if (_themeState & newState) 02304 return NO; 02305 02306 _themeState |= newState; 02307 02308 [self setNeedsLayout]; 02309 [self setNeedsDisplay:YES]; 02310 02311 return YES; 02312 } 02313 02314 - (BOOL)unsetThemeState:(CPThemeState)aState 02315 { 02316 var newState = ((typeof aState === "string") ? CPThemeState(aState) : aState); 02317 02318 if (!(_themeState & newState)) 02319 return NO; 02320 02321 _themeState &= ~newState; 02322 02323 [self setNeedsLayout]; 02324 [self setNeedsDisplay:YES]; 02325 02326 return YES; 02327 } 02328 02329 #pragma mark Theme Attributes 02330 02331 + (CPString)defaultThemeClass 02332 { 02333 return nil; 02334 } 02335 02336 - (CPString)themeClass 02337 { 02338 if (_themeClass) 02339 return _themeClass; 02340 02341 return [[self class] defaultThemeClass]; 02342 } 02343 02344 - (void)setThemeClass:(CPString)theClass 02345 { 02346 _themeClass = theClass; 02347 02348 [self _loadThemeAttributes]; 02349 02350 [self setNeedsLayout]; 02351 [self setNeedsDisplay:YES]; 02352 } 02353 02354 + (CPDictionary)themeAttributes 02355 { 02356 return nil; 02357 } 02358 02359 + (CPArray)_themeAttributes 02360 { 02361 if (!CachedThemeAttributes) 02362 CachedThemeAttributes = {}; 02363 02364 var theClass = [self class], 02365 CPViewClass = [CPView class], 02366 attributes = [], 02367 nullValue = [CPNull null]; 02368 02369 for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass]) 02370 { 02371 var cachedAttributes = CachedThemeAttributes[class_getName(theClass)]; 02372 02373 if (cachedAttributes) 02374 { 02375 attributes = attributes.length ? attributes.concat(cachedAttributes) : attributes; 02376 CachedThemeAttributes[[self className]] = attributes; 02377 02378 break; 02379 } 02380 02381 var attributeDictionary = [theClass themeAttributes]; 02382 02383 if (!attributeDictionary) 02384 continue; 02385 02386 var attributeKeys = [attributeDictionary allKeys], 02387 attributeCount = attributeKeys.length; 02388 02389 while (attributeCount--) 02390 { 02391 var attributeName = attributeKeys[attributeCount], 02392 attributeValue = [attributeDictionary objectForKey:attributeName]; 02393 02394 attributes.push(attributeValue === nullValue ? nil : attributeValue); 02395 attributes.push(attributeName); 02396 } 02397 } 02398 02399 return attributes; 02400 } 02401 02402 - (void)_loadThemeAttributes 02403 { 02404 var theClass = [self class], 02405 attributes = [theClass _themeAttributes], 02406 count = attributes.length; 02407 02408 if (!count) 02409 return; 02410 02411 var theme = [self theme], 02412 themeClass = [self themeClass]; 02413 02414 _themeAttributes = {}; 02415 02416 while (count--) 02417 { 02418 var attributeName = attributes[count--], 02419 attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]]; 02420 02421 [attribute setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]]; 02422 02423 _themeAttributes[attributeName] = attribute; 02424 } 02425 } 02426 02427 - (void)setTheme:(CPTheme)aTheme 02428 { 02429 if (_theme === aTheme) 02430 return; 02431 02432 _theme = aTheme; 02433 02434 [self viewDidChangeTheme]; 02435 } 02436 02437 - (CPTheme)theme 02438 { 02439 return _theme; 02440 } 02441 02442 - (void)viewDidChangeTheme 02443 { 02444 if (!_themeAttributes) 02445 return; 02446 02447 var theme = [self theme], 02448 themeClass = [self themeClass]; 02449 02450 for (var attributeName in _themeAttributes) 02451 if (_themeAttributes.hasOwnProperty(attributeName)) 02452 [_themeAttributes[attributeName] setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]]; 02453 02454 [self setNeedsLayout]; 02455 [self setNeedsDisplay:YES]; 02456 } 02457 02458 - (CPDictionary)_themeAttributeDictionary 02459 { 02460 var dictionary = [CPDictionary dictionary]; 02461 02462 if (_themeAttributes) 02463 { 02464 var theme = [self theme]; 02465 02466 for (var attributeName in _themeAttributes) 02467 if (_themeAttributes.hasOwnProperty(attributeName)) 02468 [dictionary setObject:_themeAttributes[attributeName] forKey:attributeName]; 02469 } 02470 02471 return dictionary; 02472 } 02473 02474 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState 02475 { 02476 if (!_themeAttributes || !_themeAttributes[aName]) 02477 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; 02478 02479 var currentValue = [self currentValueForThemeAttribute:aName]; 02480 02481 [_themeAttributes[aName] setValue:aValue forState:aState]; 02482 02483 if ([self currentValueForThemeAttribute:aName] === currentValue) 02484 return; 02485 02486 [self setNeedsDisplay:YES]; 02487 [self setNeedsLayout]; 02488 } 02489 02490 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName 02491 { 02492 if (!_themeAttributes || !_themeAttributes[aName]) 02493 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; 02494 02495 var currentValue = [self currentValueForThemeAttribute:aName]; 02496 02497 [_themeAttributes[aName] setValue:aValue]; 02498 02499 if ([self currentValueForThemeAttribute:aName] === currentValue) 02500 return; 02501 02502 [self setNeedsDisplay:YES]; 02503 [self setNeedsLayout]; 02504 } 02505 02506 - (id)valueForThemeAttribute:(CPString)aName inState:(CPThemeState)aState 02507 { 02508 if (!_themeAttributes || !_themeAttributes[aName]) 02509 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; 02510 02511 return [_themeAttributes[aName] valueForState:aState]; 02512 } 02513 02514 - (id)valueForThemeAttribute:(CPString)aName 02515 { 02516 if (!_themeAttributes || !_themeAttributes[aName]) 02517 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; 02518 02519 return [_themeAttributes[aName] value]; 02520 } 02521 02522 - (id)currentValueForThemeAttribute:(CPString)aName 02523 { 02524 if (!_themeAttributes || !_themeAttributes[aName]) 02525 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; 02526 02527 return [_themeAttributes[aName] valueForState:_themeState]; 02528 } 02529 02530 - (BOOL)hasThemeAttribute:(CPString)aName 02531 { 02532 return (_themeAttributes && _themeAttributes[aName] !== undefined); 02533 } 02534 02535 - (CPView)createEphemeralSubviewNamed:(CPString)aViewName 02536 { 02537 return nil; 02538 } 02539 02540 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName 02541 { 02542 return _CGRectMakeZero(); 02543 } 02544 02545 - (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName 02546 positioned:(CPWindowOrderingMode)anOrderingMode 02547 relativeToEphemeralSubviewNamed:(CPString)relativeToViewName 02548 { 02549 if (!_ephemeralSubviewsForNames) 02550 { 02551 _ephemeralSubviewsForNames = {}; 02552 _ephemeralSubviews = [CPSet set]; 02553 } 02554 02555 var frame = [self rectForEphemeralSubviewNamed:aViewName]; 02556 02557 if (frame) 02558 { 02559 if (!_ephemeralSubviewsForNames[aViewName]) 02560 { 02561 _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName]; 02562 02563 [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]]; 02564 02565 if (_ephemeralSubviewsForNames[aViewName]) 02566 [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]]; 02567 } 02568 02569 if (_ephemeralSubviewsForNames[aViewName]) 02570 [_ephemeralSubviewsForNames[aViewName] setFrame:frame]; 02571 } 02572 else if (_ephemeralSubviewsForNames[aViewName]) 02573 { 02574 [_ephemeralSubviewsForNames[aViewName] removeFromSuperview]; 02575 02576 [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]]; 02577 delete _ephemeralSubviewsForNames[aViewName]; 02578 } 02579 02580 return _ephemeralSubviewsForNames[aViewName]; 02581 } 02582 02583 - (CPView)ephemeralSubviewNamed:(CPString)aViewName 02584 { 02585 if (!_ephemeralSubviewsForNames) 02586 return nil; 02587 02588 return (_ephemeralSubviewsForNames[aViewName] || nil); 02589 } 02590 02591 @end 02592 02593 var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", 02594 CPViewAutoresizesSubviewsKey = @"CPViewAutoresizesSubviews", 02595 CPViewBackgroundColorKey = @"CPViewBackgroundColor", 02596 CPViewBoundsKey = @"CPViewBoundsKey", 02597 CPViewFrameKey = @"CPViewFrameKey", 02598 CPViewHitTestsKey = @"CPViewHitTestsKey", 02599 CPViewIsHiddenKey = @"CPViewIsHiddenKey", 02600 CPViewOpacityKey = @"CPViewOpacityKey", 02601 CPViewSubviewsKey = @"CPViewSubviewsKey", 02602 CPViewSuperviewKey = @"CPViewSuperviewKey", 02603 CPViewTagKey = @"CPViewTagKey", 02604 CPViewThemeClassKey = @"CPViewThemeClassKey", 02605 CPViewThemeStateKey = @"CPViewThemeStateKey", 02606 CPViewWindowKey = @"CPViewWindowKey", 02607 CPViewNextKeyViewKey = @"CPViewNextKeyViewKey", 02608 CPViewPreviousKeyViewKey = @"CPViewPreviousKeyViewKey"; 02609 02610 @implementation CPView (CPCoding) 02611 02617 - (id)initWithCoder:(CPCoder)aCoder 02618 { 02619 // We create the DOMElement "early" because there is a chance that we 02620 // will decode our superview before we are done decoding, at which point 02621 // we have to have an element to place in the tree. Perhaps there is 02622 // a more "elegant" way to do this...? 02623 #if PLATFORM(DOM) 02624 _DOMElement = DOMElementPrototype.cloneNode(false); 02625 #endif 02626 02627 // Also decode these "early". 02628 _frame = [aCoder decodeRectForKey:CPViewFrameKey]; 02629 _bounds = [aCoder decodeRectForKey:CPViewBoundsKey]; 02630 02631 self = [super initWithCoder:aCoder]; 02632 02633 if (self) 02634 { 02635 // We have to manually check because it may be 0, so we can't use || 02636 _tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1; 02637 02638 _window = [aCoder decodeObjectForKey:CPViewWindowKey]; 02639 _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || []; 02640 _superview = [aCoder decodeObjectForKey:CPViewSuperviewKey]; 02641 02642 // FIXME: Should we encode/decode this? 02643 _registeredDraggedTypes = [CPSet set]; 02644 _registeredDraggedTypesArray = []; 02645 02646 // Other views (CPBox) might set an autoresizes mask on their subviews before it is actually decoded. 02647 // We make sure we don't override the value by checking if it was already set. 02648 if (_autoresizingMask === nil) 02649 _autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable; 02650 02651 _autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey]; 02652 02653 _hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey]; 02654 02655 // DOM SETUP 02656 #if PLATFORM(DOM) 02657 _DOMImageParts = []; 02658 _DOMImageSizes = []; 02659 02660 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame)); 02661 CPDOMDisplayServerSetStyleSize(_DOMElement, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)); 02662 02663 var index = 0, 02664 count = _subviews.length; 02665 02666 for (; index < count; ++index) 02667 { 02668 CPDOMDisplayServerAppendChild(_DOMElement, _subviews[index]._DOMElement); 02669 //_subviews[index]._superview = self; 02670 } 02671 #endif 02672 02673 if ([aCoder containsValueForKey:CPViewIsHiddenKey]) 02674 [self setHidden:[aCoder decodeBoolForKey:CPViewIsHiddenKey]]; 02675 else 02676 _isHidden = NO; 02677 02678 if ([aCoder containsValueForKey:CPViewOpacityKey]) 02679 [self setAlphaValue:[aCoder decodeIntForKey:CPViewOpacityKey]]; 02680 else 02681 _opacity = 1.0; 02682 02683 [self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]]; 02684 02685 [self setupViewFlags]; 02686 02687 _theme = [CPTheme defaultTheme]; 02688 _themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey]; 02689 _themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]); 02690 _themeAttributes = {}; 02691 02692 var theClass = [self class], 02693 themeClass = [self themeClass], 02694 attributes = [theClass _themeAttributes], 02695 count = attributes.length; 02696 02697 while (count--) 02698 { 02699 var attributeName = attributes[count--]; 02700 02701 _themeAttributes[attributeName] = CPThemeAttributeDecode(aCoder, attributeName, attributes[count], _theme, themeClass); 02702 } 02703 02704 [self setNeedsDisplay:YES]; 02705 [self setNeedsLayout]; 02706 } 02707 02708 return self; 02709 } 02710 02715 - (void)encodeWithCoder:(CPCoder)aCoder 02716 { 02717 [super encodeWithCoder:aCoder]; 02718 02719 if (_tag !== -1) 02720 [aCoder encodeInt:_tag forKey:CPViewTagKey]; 02721 02722 [aCoder encodeRect:_frame forKey:CPViewFrameKey]; 02723 [aCoder encodeRect:_bounds forKey:CPViewBoundsKey]; 02724 02725 // This will come out nil on the other side with decodeObjectForKey: 02726 if (_window !== nil) 02727 [aCoder encodeConditionalObject:_window forKey:CPViewWindowKey]; 02728 02729 var count = [_subviews count], 02730 encodedSubviews = _subviews; 02731 02732 if (count > 0 && [_ephemeralSubviews count] > 0) 02733 { 02734 encodedSubviews = [encodedSubviews copy]; 02735 02736 while (count--) 02737 if ([_ephemeralSubviews containsObject:encodedSubviews[count]]) 02738 encodedSubviews.splice(count, 1); 02739 } 02740 02741 if (encodedSubviews.length > 0) 02742 [aCoder encodeObject:encodedSubviews forKey:CPViewSubviewsKey]; 02743 02744 // This will come out nil on the other side with decodeObjectForKey: 02745 if (_superview !== nil) 02746 [aCoder encodeConditionalObject:_superview forKey:CPViewSuperviewKey]; 02747 02748 if (_autoresizingMask !== CPViewNotSizable) 02749 [aCoder encodeInt:_autoresizingMask forKey:CPViewAutoresizingMaskKey]; 02750 02751 if (!_autoresizesSubviews) 02752 [aCoder encodeBool:_autoresizesSubviews forKey:CPViewAutoresizesSubviewsKey]; 02753 02754 if (_backgroundColor !== nil) 02755 [aCoder encodeObject:_backgroundColor forKey:CPViewBackgroundColorKey]; 02756 02757 if (_hitTests !== YES) 02758 [aCoder encodeBool:_hitTests forKey:CPViewHitTestsKey]; 02759 02760 if (_opacity !== 1.0) 02761 [aCoder encodeFloat:_opacity forKey:CPViewOpacityKey]; 02762 02763 if (_isHidden) 02764 [aCoder encodeBool:_isHidden forKey:CPViewIsHiddenKey]; 02765 02766 var nextKeyView = [self nextKeyView]; 02767 02768 if (nextKeyView !== nil && ![nextKeyView isEqual:self]) 02769 [aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey]; 02770 02771 var previousKeyView = [self previousKeyView]; 02772 02773 if (previousKeyView !== nil && ![previousKeyView isEqual:self]) 02774 [aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey]; 02775 02776 [aCoder encodeObject:[self themeClass] forKey:CPViewThemeClassKey]; 02777 [aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey]; 02778 02779 for (var attributeName in _themeAttributes) 02780 if (_themeAttributes.hasOwnProperty(attributeName)) 02781 CPThemeAttributeEncode(aCoder, _themeAttributes[attributeName]); 02782 } 02783 02784 @end 02785 02786 var _CPViewFullScreenModeStateMake = function(aView) 02787 { 02788 var superview = aView._superview; 02789 02790 return { autoresizingMask:aView._autoresizingMask, frame:CGRectMakeCopy(aView._frame), index:(superview ? [superview._subviews indexOfObjectIdenticalTo:aView] : 0), superview:superview }; 02791 } 02792 02793 var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView) 02794 { 02795 var transform = CGAffineTransformMakeIdentity(), 02796 sameWindow = YES, 02797 fromWindow = nil, 02798 toWindow = nil; 02799 02800 if (fromView) 02801 { 02802 var view = fromView; 02803 02804 // FIXME: This doesn't handle the case when the outside views are equal. 02805 // If we have a fromView, "climb up" the view tree until 02806 // we hit the root node or we hit the toLayer. 02807 while (view && view != toView) 02808 { 02809 var frame = view._frame; 02810 02811 transform.tx += _CGRectGetMinX(frame); 02812 transform.ty += _CGRectGetMinY(frame); 02813 02814 if (view._boundsTransform) 02815 { 02816 _CGAffineTransformConcatTo(transform, view._boundsTransform, transform); 02817 } 02818 02819 view = view._superview; 02820 } 02821 02822 // If we hit toView, then we're done. 02823 if (view === toView) 02824 return transform; 02825 02826 else if (fromView && toView) 02827 { 02828 fromWindow = [fromView window]; 02829 toWindow = [toView window]; 02830 02831 if (fromWindow && toWindow && fromWindow !== toWindow) 02832 { 02833 sameWindow = NO; 02834 02835 var frame = [fromWindow frame]; 02836 02837 transform.tx += _CGRectGetMinX(frame); 02838 transform.ty += _CGRectGetMinY(frame); 02839 } 02840 } 02841 } 02842 02843 // FIXME: For now we can do things this way, but eventually we need to do them the "hard" way. 02844 var view = toView; 02845 02846 while (view) 02847 { 02848 var frame = view._frame; 02849 02850 transform.tx -= _CGRectGetMinX(frame); 02851 transform.ty -= _CGRectGetMinY(frame); 02852 02853 if (view._boundsTransform) 02854 { 02855 _CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform); 02856 } 02857 02858 view = view._superview; 02859 } 02860 02861 if (!sameWindow) 02862 { 02863 var frame = [toWindow frame]; 02864 02865 transform.tx -= _CGRectGetMinX(frame); 02866 transform.ty -= _CGRectGetMinY(frame); 02867 } 02868 /* var views = [], 02869 view = toView; 02870 02871 while (view) 02872 { 02873 views.push(view); 02874 view = view._superview; 02875 } 02876 02877 var index = views.length; 02878 02879 while (index--) 02880 { 02881 var frame = views[index]._frame; 02882 02883 transform.tx -= _CGRectGetMinX(frame); 02884 transform.ty -= _CGRectGetMinY(frame); 02885 }*/ 02886 02887 return transform; 02888 } 02889 02890 @implementation CPView (CPSynthesizedAccessors) 02891 02895 - (CPString)toolTip 02896 { 02897 return _toolTip; 02898 } 02899 02903 - (void)setToolTip:(CPString)aValue 02904 { 02905 _toolTip = aValue; 02906 } 02907 02908 @end