00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPArray.j>
00024 @import <Foundation/CPObjJRuntime.j>
00025
00026 @import "CGAffineTransform.j"
00027 @import "CGGeometry.j"
00028
00029 @import "CPColor.j"
00030 @import "CPDOMDisplayServer.j"
00031 @import "CPGeometry.j"
00032 @import "CPGraphicsContext.j"
00033 @import "CPResponder.j"
00034 @import "CPTheme.j"
00035
00036
00037 #include "Platform/Platform.h"
00038 #include "CoreGraphics/CGAffineTransform.h"
00039 #include "CoreGraphics/CGGeometry.h"
00040 #include "Platform/DOM/CPDOMDisplayServer.h"
00041
00042
00043
00044
00045
00046
00047 CPViewNotSizable = 0;
00048
00049
00050
00051
00052
00053 CPViewMinXMargin = 1;
00054
00055
00056
00057
00058
00059 CPViewWidthSizable = 2;
00060
00061
00062
00063
00064
00065 CPViewMaxXMargin = 4;
00066
00067
00068
00069
00070
00071 CPViewMinYMargin = 8;
00072
00073
00074
00075
00076
00077 CPViewHeightSizable = 16;
00078
00079
00080
00081
00082
00083 CPViewMaxYMargin = 32;
00084
00085 CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification";
00086 CPViewFrameDidChangeNotification = @"CPViewFrameDidChangeNotification";
00087
00088 var CachedNotificationCenter = nil,
00089 CachedThemeAttributes = nil;
00090
00091 #if PLATFORM(DOM)
00092 var DOMElementPrototype = nil,
00093
00094 BackgroundTrivialColor = 0,
00095 BackgroundVerticalThreePartImage = 1,
00096 BackgroundHorizontalThreePartImage = 2,
00097 BackgroundNinePartImage = 3,
00098
00099 CustomDrawRectViews = {},
00100 CustomLayoutSubviewsViews = {};
00101 #endif
00102
00120 @implementation CPView : CPResponder
00121 {
00122 CPWindow _window;
00123
00124 CPView _superview;
00125 CPArray _subviews;
00126
00127 CPGraphicsContext _graphicsContext;
00128
00129 int _tag;
00130
00131 CGRect _frame;
00132 CGRect _bounds;
00133 CGAffineTransform _boundsTransform;
00134 CGAffineTransform _inverseBoundsTransform;
00135
00136 CPSet _registeredDraggedTypes;
00137 CPArray _registeredDraggedTypesArray;
00138
00139 BOOL _isHidden;
00140 BOOL _hitTests;
00141
00142 BOOL _postsFrameChangedNotifications;
00143 BOOL _postsBoundsChangedNotifications;
00144 BOOL _inhibitFrameAndBoundsChangedNotifications;
00145
00146 CPString _displayHash;
00147
00148 #if PLATFORM(DOM)
00149 DOMElement _DOMElement;
00150 DOMElement _DOMContentsElement;
00151
00152 CPArray _DOMImageParts;
00153 CPArray _DOMImageSizes;
00154
00155 unsigned _backgroundType;
00156 #endif
00157
00158 CGRect _dirtyRect;
00159
00160 float _opacity;
00161 CPColor _backgroundColor;
00162
00163 BOOL _autoresizesSubviews;
00164 unsigned _autoresizingMask;
00165
00166 CALayer _layer;
00167 BOOL _wantsLayer;
00168
00169
00170 BOOL _isInFullScreenMode;
00171
00172 _CPViewFullScreenModeState _fullScreenModeState;
00173
00174
00175 BOOL _needsLayout;
00176 JSObject _ephemeralSubviews;
00177
00178
00179 CPTheme _theme;
00180 JSObject _themeAttributes;
00181 unsigned _themeState;
00182
00183
00184 CPView _nextKeyView;
00185 CPView _previousKeyView;
00186 }
00187
00188
00189
00190
00191
00192 + (void)initialize
00193 {
00194 if (self !== [CPView class])
00195 return;
00196
00197 #if PLATFORM(DOM)
00198 DOMElementPrototype = document.createElement("div");
00199
00200 var style = DOMElementPrototype.style;
00201
00202 style.overflow = "hidden";
00203 style.position = "absolute";
00204 style.visibility = "visible";
00205 style.zIndex = 0;
00206 #endif
00207
00208 CachedNotificationCenter = [CPNotificationCenter defaultCenter];
00209 }
00210
00211 - (id)init
00212 {
00213 return [self initWithFrame:CGRectMakeZero()];
00214 }
00215
00220 - (id)initWithFrame:(CGRect)aFrame
00221 {
00222 self = [super init];
00223
00224 if (self)
00225 {
00226 var width = _CGRectGetWidth(aFrame),
00227 height = _CGRectGetHeight(aFrame);
00228
00229 _subviews = [];
00230 _registeredDraggedTypes = [CPSet set];
00231 _registeredDraggedTypesArray = [];
00232
00233 _tag = -1;
00234
00235 _frame = _CGRectMakeCopy(aFrame);
00236 _bounds = _CGRectMake(0.0, 0.0, width, height);
00237
00238 _autoresizingMask = CPViewNotSizable;
00239 _autoresizesSubviews = YES;
00240
00241 _opacity = 1.0;
00242 _isHidden = NO;
00243 _hitTests = YES;
00244
00245 _displayHash = [self hash];
00246
00247 #if PLATFORM(DOM)
00248 _DOMElement = DOMElementPrototype.cloneNode(false);
00249
00250 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame));
00251 CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
00252
00253 _DOMImageParts = [];
00254 _DOMImageSizes = [];
00255 #endif
00256
00257 _theme = [CPTheme defaultTheme];
00258 _themeState = CPThemeStateNormal;
00259
00260 [self _loadThemeAttributes];
00261 }
00262
00263 return self;
00264 }
00265
00270 - (CPView)superview
00271 {
00272 return _superview;
00273 }
00274
00279 - (CPArray)subviews
00280 {
00281 return _subviews;
00282 }
00283
00287 - (CPWindow)window
00288 {
00289 return _window;
00290 }
00291
00296 - (void)addSubview:(CPView)aSubview
00297 {
00298 [self _insertSubview:aSubview atIndex:CPNotFound];
00299 }
00300
00307 - (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView
00308 {
00309 var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound;
00310
00311
00312 if (index === CPNotFound)
00313 index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0;
00314
00315
00316 else if (anOrderingMode === CPWindowAbove)
00317 ++index;
00318
00319 [self _insertSubview:aSubview atIndex:index];
00320 }
00321
00322
00323 - (void)_insertSubview:(CPView)aSubview atIndex:(int)anIndex
00324 {
00325
00326 var count = _subviews.length;
00327
00328
00329 [[self window] _dirtyKeyViewLoop];
00330
00331
00332 if (aSubview._superview == self)
00333 {
00334 var index = [_subviews indexOfObjectIdenticalTo:aSubview];
00335
00336
00337 if (index === anIndex || index === count - 1 && anIndex === count)
00338 return;
00339
00340 [_subviews removeObjectAtIndex:index];
00341
00342 #if PLATFORM(DOM)
00343 CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement);
00344 #endif
00345
00346 if (anIndex > index)
00347 --anIndex;
00348
00349
00350 --count;
00351 }
00352 else
00353 {
00354
00355 [aSubview removeFromSuperview];
00356
00357
00358 [aSubview _setWindow:_window];
00359
00360
00361 [aSubview viewWillMoveToSuperview:self];
00362
00363
00364 aSubview._superview = self;
00365 }
00366
00367 if (anIndex === CPNotFound || anIndex >= count)
00368 {
00369 _subviews.push(aSubview);
00370
00371 #if PLATFORM(DOM)
00372
00373 CPDOMDisplayServerAppendChild(_DOMElement, aSubview._DOMElement);
00374 #endif
00375 }
00376 else
00377 {
00378 _subviews.splice(anIndex, 0, aSubview);
00379
00380 #if PLATFORM(DOM)
00381
00382 CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement);
00383 #endif
00384 }
00385
00386 [aSubview setNextResponder:self];
00387 [aSubview viewDidMoveToSuperview];
00388
00389 [self didAddSubview:aSubview];
00390 }
00391
00396 - (void)didAddSubview:(CPView)aSubview
00397 {
00398 }
00399
00404 - (void)removeFromSuperview
00405 {
00406 if (!_superview)
00407 return;
00408
00409
00410 [[self window] _dirtyKeyViewLoop];
00411
00412 [_superview willRemoveSubview:self];
00413
00414 [[_superview subviews] removeObject:self];
00415
00416 #if PLATFORM(DOM)
00417 CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
00418 #endif
00419 _superview = nil;
00420
00421 [self _setWindow:nil];
00422 }
00423
00429 - (void)replaceSubview:(CPView)aSubview with:(CPView)aView
00430 {
00431 if (aSubview._superview != self)
00432 return;
00433
00434 var index = [_subviews indexOfObjectIdenticalTo:aSubview];
00435
00436 [aSubview removeFromSuperview];
00437
00438 [self _insertSubview:aView atIndex:index];
00439 }
00440
00441
00442 - (void)_setWindow:(CPWindow)aWindow
00443 {
00444 if (_window === aWindow)
00445 return;
00446
00447 [[self window] _dirtyKeyViewLoop];
00448
00449
00450 if ([_window firstResponder] === self)
00451 [_window makeFirstResponder:nil];
00452
00453
00454 [self viewWillMoveToWindow:aWindow];
00455
00456
00457
00458 if (_registeredDraggedTypes)
00459 {
00460 [_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
00461 [aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
00462 }
00463
00464 _window = aWindow;
00465
00466 var count = [_subviews count];
00467
00468 while (count--)
00469 [_subviews[count] _setWindow:aWindow];
00470
00471 [self viewDidMoveToWindow];
00472
00473 [[self window] _dirtyKeyViewLoop];
00474 }
00475
00480 - (BOOL)isDescendantOf:(CPView)aView
00481 {
00482 var view = self;
00483
00484 do
00485 {
00486 if (view == aView)
00487 return YES;
00488 } while(view = [view superview])
00489
00490 return NO;
00491 }
00492
00496 - (void)viewDidMoveToSuperview
00497 {
00498
00499 [self setNeedsDisplay:YES];
00500 }
00501
00505 - (void)viewDidMoveToWindow
00506 {
00507 }
00508
00513 - (void)viewWillMoveToSuperview:(CPView)aView
00514 {
00515 }
00516
00521 - (void)viewWillMoveToWindow:(CPWindow)aWindow
00522 {
00523 }
00524
00529 - (void)willRemoveSubview:(CPView)aView
00530 {
00531 }
00532
00537 - (CPMenuItem)enclosingMenuItem
00538 {
00539 var view = self;
00540
00541 while (view && ![view isKindOfClass:[_CPMenuItemView class]])
00542 view = [view superview];
00543
00544 if (view)
00545 return view._menuItem;
00546
00547 return nil;
00548
00549
00550
00551
00552
00553
00554
00555 }
00556
00557 - (void)setTag:(CPInteger)aTag
00558 {
00559 _tag = aTag;
00560 }
00561
00562 - (CPInteger)tag
00563 {
00564 return _tag;
00565 }
00566
00567 - (void)viewWithTag:(CPInteger)aTag
00568 {
00569 if ([self tag] === aTag)
00570 return self;
00571
00572 var index = 0,
00573 count = _subviews.length;
00574
00575 for (; index < count; ++index)
00576 {
00577 var view = [_subviews[index] viewWithTag:aTag];
00578
00579 if (view)
00580 return view;
00581 }
00582
00583 return nil;
00584 }
00585
00590 - (BOOL)isFlipped
00591 {
00592 return YES;
00593 }
00594
00602 - (void)setFrame:(CGRect)aFrame
00603 {
00604 if (_CGRectEqualToRect(_frame, aFrame))
00605 return;
00606
00607 _inhibitFrameAndBoundsChangedNotifications = YES;
00608
00609 [self setFrameOrigin:aFrame.origin];
00610 [self setFrameSize:aFrame.size];
00611
00612 _inhibitFrameAndBoundsChangedNotifications = NO;
00613
00614 if (_postsFrameChangedNotifications)
00615 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00616 }
00617
00622 - (CGRect)frame
00623 {
00624 return _CGRectMakeCopy(_frame);
00625 }
00626
00634 - (void)setCenter:(CGPoint)aPoint
00635 {
00636 [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)];
00637 }
00638
00643 - (CGPoint)center
00644 {
00645 return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y);
00646 }
00647
00655 - (void)setFrameOrigin:(CGPoint)aPoint
00656 {
00657 var origin = _frame.origin;
00658
00659 if (!aPoint || _CGPointEqualToPoint(origin, aPoint))
00660 return;
00661
00662 origin.x = aPoint.x;
00663 origin.y = aPoint.y;
00664
00665 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00666 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00667
00668 #if PLATFORM(DOM)
00669 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, _superview ? _superview._boundsTransform : NULL, origin.x, origin.y);
00670 #endif
00671 }
00672
00679 - (void)setFrameSize:(CGSize)aSize
00680 {
00681 var size = _frame.size;
00682
00683 if (!aSize || _CGSizeEqualToSize(size, aSize))
00684 return;
00685
00686 var oldSize = _CGSizeMakeCopy(size);
00687
00688 size.width = aSize.width;
00689 size.height = aSize.height;
00690
00691 if (YES)
00692 {
00693 _bounds.size.width = aSize.width;
00694 _bounds.size.height = aSize.height;
00695 }
00696
00697 if (_layer)
00698 [_layer _owningViewBoundsChanged];
00699
00700 if (_autoresizesSubviews)
00701 [self resizeSubviewsWithOldSize:oldSize];
00702
00703 [self setNeedsLayout];
00704 [self setNeedsDisplay:YES];
00705
00706 #if PLATFORM(DOM)
00707 CPDOMDisplayServerSetStyleSize(_DOMElement, size.width, size.height);
00708
00709 if (_DOMContentsElement)
00710 {
00711 CPDOMDisplayServerSetSize(_DOMContentsElement, size.width, size.height);
00712 CPDOMDisplayServerSetStyleSize(_DOMContentsElement, size.width, size.height);
00713 }
00714
00715 if (_backgroundType !== BackgroundTrivialColor)
00716 {
00717 var images = [[_backgroundColor patternImage] imageSlices];
00718
00719 if (_backgroundType === BackgroundVerticalThreePartImage)
00720 {
00721 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
00722 }
00723
00724 else if (_backgroundType === BackgroundHorizontalThreePartImage)
00725 {
00726 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
00727 }
00728
00729 else if (_backgroundType === BackgroundNinePartImage)
00730 {
00731 var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
00732 height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
00733
00734 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
00735 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
00736 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
00737 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
00738 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
00739 }
00740 }
00741 #endif
00742
00743 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00744 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00745 }
00746
00752 - (void)setBounds:(CGRect)bounds
00753 {
00754 if (_CGRectEqualToRect(_bounds, bounds))
00755 return;
00756
00757 _inhibitFrameAndBoundsChangedNotifications = YES;
00758
00759 [self setBoundsOrigin:bounds.origin];
00760 [self setBoundsSize:bounds.size];
00761
00762 _inhibitFrameAndBoundsChangedNotifications = NO;
00763
00764 if (_postsBoundsChangedNotifications)
00765 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00766 }
00767
00772 - (CGRect)bounds
00773 {
00774 return _CGRectMakeCopy(_bounds);
00775 }
00776
00783 - (void)setBoundsOrigin:(CGPoint)aPoint
00784 {
00785 var origin = _bounds.origin;
00786
00787 if (_CGPointEqualToPoint(origin, aPoint))
00788 return;
00789
00790 origin.x = aPoint.x;
00791 origin.y = aPoint.y;
00792
00793 if (origin.x != 0 || origin.y != 0)
00794 {
00795 _boundsTransform = _CGAffineTransformMakeTranslation(-origin.x, -origin.y);
00796 _inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform);
00797 }
00798 else
00799 {
00800 _boundsTransform = nil;
00801 _inverseBoundsTransform = nil;
00802 }
00803
00804 #if PLATFORM(DOM)
00805 var index = _subviews.length;
00806
00807 while (index--)
00808 {
00809 var view = _subviews[index],
00810 origin = view._frame.origin;
00811
00812 CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y);
00813 }
00814 #endif
00815
00816 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00817 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00818 }
00819
00826 - (void)setBoundsSize:(CGSize)aSize
00827 {
00828 var size = _bounds.size;
00829
00830 if (_CGSizeEqualToSize(size, aSize))
00831 return;
00832
00833 var frameSize = _frame.size;
00834
00835 if (!_CGSizeEqualToSize(size, frameSize))
00836 {
00837 var origin = _bounds.origin;
00838
00839 origin.x /= size.width / frameSize.width;
00840 origin.y /= size.height / frameSize.height;
00841 }
00842
00843 size.width = aSize.width;
00844 size.height = aSize.height;
00845
00846 if (!_CGSizeEqualToSize(size, frameSize))
00847 {
00848 var origin = _bounds.origin;
00849
00850 origin.x *= size.width / frameSize.width;
00851 origin.y *= size.height / frameSize.height;
00852 }
00853
00854 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00855 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00856 }
00857
00858
00863 - (void)resizeWithOldSuperviewSize:(CGSize)aSize
00864 {
00865 var mask = [self autoresizingMask];
00866
00867 if(mask == CPViewNotSizable)
00868 return;
00869
00870 var frame = _superview._frame,
00871 newFrame = _CGRectMakeCopy(_frame),
00872 dX = (_CGRectGetWidth(frame) - aSize.width) /
00873 (((mask & CPViewMinXMargin) ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
00874 dY = (_CGRectGetHeight(frame) - aSize.height) /
00875 ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0));
00876
00877 if (mask & CPViewMinXMargin)
00878 newFrame.origin.x += dX;
00879 if (mask & CPViewWidthSizable)
00880 newFrame.size.width += dX;
00881
00882 if (mask & CPViewMinYMargin)
00883 newFrame.origin.y += dY;
00884 if (mask & CPViewHeightSizable)
00885 newFrame.size.height += dY;
00886
00887 [self setFrame:newFrame];
00888 }
00889
00894 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
00895 {
00896 var count = _subviews.length;
00897
00898 while (count--)
00899 [_subviews[count] resizeWithOldSuperviewSize:aSize];
00900 }
00901
00909 - (void)setAutoresizesSubviews:(BOOL)aFlag
00910 {
00911 _autoresizesSubviews = !!aFlag;
00912 }
00913
00918 - (BOOL)autoresizesSubviews
00919 {
00920 return _autoresizesSubviews;
00921 }
00922
00927 - (void)setAutoresizingMask:(unsigned)aMask
00928 {
00929 _autoresizingMask = aMask;
00930 }
00931
00935 - (unsigned)autoresizingMask
00936 {
00937 return _autoresizingMask;
00938 }
00939
00940
00941
00945 - (BOOL)enterFullScreenMode
00946 {
00947 return [self enterFullScreenMode:nil withOptions:nil];
00948 }
00949
00955 - (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options
00956 {
00957 _fullScreenModeState = _CPViewFullScreenModeStateMake(self);
00958
00959 var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds] styleMask:CPBorderlessWindowMask];
00960
00961 [fullScreenWindow setLevel:CPScreenSaverWindowLevel];
00962 [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
00963
00964 var contentView = [fullScreenWindow contentView];
00965
00966 [contentView setBackgroundColor:[CPColor blackColor]];
00967 [contentView addSubview:self];
00968
00969 [self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
00970 [self setFrame:CGRectMakeCopy([contentView bounds])];
00971
00972 [fullScreenWindow makeKeyAndOrderFront:self];
00973
00974 [fullScreenWindow makeFirstResponder:self];
00975
00976 _isInFullScreenMode = YES;
00977
00978 return YES;
00979 }
00980
00984 - (void)exitFullScreenMode
00985 {
00986 [self exitFullScreenModeWithOptions:nil];
00987 }
00988
00993 - (void)exitFullScreenModeWithOptions:(CPDictionary)options
00994 {
00995 if (!_isInFullScreenMode)
00996 return;
00997
00998 _isInFullScreenMode = NO;
00999
01000 [self setFrame:_fullScreenModeState.frame];
01001 [self setAutoresizingMask:_fullScreenModeState.autoresizingMask];
01002 [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index];
01003
01004 [[self window] orderOut:self];
01005 }
01006
01010 - (BOOL)isInFullScreenMode
01011 {
01012 return _isInFullScreenMode;
01013 }
01014
01019 - (void)setHidden:(BOOL)aFlag
01020 {
01021 aFlag = !!aFlag;
01022
01023 if(_isHidden === aFlag)
01024 return;
01025
01026
01027
01028 _isHidden = aFlag;
01029 #if PLATFORM(DOM)
01030 _DOMElement.style.display = _isHidden ? "none" : "block";
01031 #endif
01032
01033 if (aFlag)
01034 {
01035 var view = [_window firstResponder];
01036
01037 if ([view isKindOfClass:[CPView class]])
01038 {
01039 do
01040 {
01041 if (self == view)
01042 {
01043 [_window makeFirstResponder:[self nextValidKeyView]];
01044 break;
01045 }
01046 }
01047 while (view = [view superview]);
01048 }
01049 }
01050 }
01051
01055 - (BOOL)isHidden
01056 {
01057 return _isHidden;
01058 }
01059
01065 - (void)setAlphaValue:(float)anAlphaValue
01066 {
01067 if (_opacity == anAlphaValue)
01068 return;
01069
01070 _opacity = anAlphaValue;
01071
01072 #if PLATFORM(DOM)
01073
01074 if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
01075 {
01076 if (anAlphaValue == 1.0)
01077 try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
01078 else
01079 _DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
01080 }
01081 else
01082 _DOMElement.style.opacity = anAlphaValue;
01083
01084 #endif
01085 }
01086
01091 - (float)alphaValue
01092 {
01093 return _opacity;
01094 }
01095
01100 - (BOOL)isHiddenOrHasHiddenAncestor
01101 {
01102 var view = self;
01103
01104 while (view && ![view isHidden])
01105 view = [view superview];
01106
01107 return view !== nil;
01108 }
01109
01115
01116 - (BOOL)acceptsFirstMouse:(CPEvent)anEvent
01117 {
01118 return YES;
01119 }
01120
01125 - (BOOL)hitTests
01126 {
01127 return _hitTests;
01128 }
01129
01134 - (void)setHitTests:(BOOL)shouldHitTest
01135 {
01136 _hitTests = !!shouldHitTest;
01137 }
01138
01144 - (CPView)hitTest:(CPPoint)aPoint
01145 {
01146 if(_isHidden || !_hitTests || !CPRectContainsPoint(_frame, aPoint))
01147 return nil;
01148
01149 var view = nil,
01150 i = _subviews.length,
01151 adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame));
01152
01153 if (_inverseBoundsTransform)
01154 adjustedPoint = _CGPointApplyAffineTransform(adjustedPoint, _inverseBoundsTransform);
01155
01156 while (i--)
01157 if (view = [_subviews[i] hitTest:adjustedPoint])
01158 return view;
01159
01160 return self;
01161 }
01162
01167 - (BOOL)mouseDownCanMoveWindow
01168 {
01169 return ![self isOpaque];
01170 }
01171
01172 - (void)mouseDown:(CPEvent)anEvent
01173 {
01174 if ([self mouseDownCanMoveWindow])
01175 [super mouseDown:anEvent];
01176 }
01177
01182 - (void)setBackgroundColor:(CPColor)aColor
01183 {
01184 if (_backgroundColor == aColor)
01185 return;
01186
01187 _backgroundColor = aColor;
01188
01189 #if PLATFORM(DOM)
01190 var patternImage = [_backgroundColor patternImage],
01191 amount = 0;
01192
01193 if ([patternImage isThreePartImage])
01194 {
01195 _backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
01196
01197 amount = 3 - _DOMImageParts.length;
01198 }
01199 else if ([patternImage isNinePartImage])
01200 {
01201 _backgroundType = BackgroundNinePartImage;
01202
01203 amount = 9 - _DOMImageParts.length;
01204 }
01205 else
01206 {
01207 _backgroundType = BackgroundTrivialColor;
01208
01209 amount = 0 - _DOMImageParts.length;
01210 }
01211
01212 if (amount > 0)
01213 while (amount--)
01214 {
01215 var DOMElement = DOMElementPrototype.cloneNode(false);
01216
01217 DOMElement.style.zIndex = -1000;
01218
01219 _DOMImageParts.push(DOMElement);
01220 _DOMElement.appendChild(DOMElement);
01221 }
01222 else
01223 {
01224 amount = -amount;
01225
01226 while (amount--)
01227 _DOMElement.removeChild(_DOMImageParts.pop());
01228 }
01229
01230 if (_backgroundType == BackgroundTrivialColor)
01231
01232
01233
01234 _DOMElement.style.background = _backgroundColor ? [_backgroundColor cssString] : "";
01235
01236 else
01237 {
01238 var slices = [patternImage imageSlices],
01239 count = slices.length,
01240 frameSize = _frame.size;
01241
01242 while (count--)
01243 {
01244 var image = slices[count],
01245 size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero();
01246
01247 CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
01248
01249 _DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
01250 }
01251
01252 if (_backgroundType == BackgroundNinePartImage)
01253 {
01254 var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
01255 height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
01256
01257 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
01258 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
01259 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
01260 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
01261 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
01262
01263 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01264 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
01265 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
01266 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[3], NULL, 0.0, _DOMImageSizes[1].height);
01267 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[4], NULL, _DOMImageSizes[0].width, _DOMImageSizes[0].height);
01268 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[5], NULL, 0.0, _DOMImageSizes[1].height);
01269 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[6], NULL, 0.0, 0.0);
01270 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[7], NULL, _DOMImageSizes[6].width, 0.0);
01271 CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0);
01272 }
01273 else if (_backgroundType == BackgroundVerticalThreePartImage)
01274 {
01275 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
01276
01277 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01278 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height);
01279 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0);
01280 }
01281 else if (_backgroundType == BackgroundHorizontalThreePartImage)
01282 {
01283 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height);
01284
01285 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01286 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
01287 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
01288 }
01289 }
01290 #endif
01291 }
01292
01296 - (CPColor)backgroundColor
01297 {
01298 return _backgroundColor;
01299 }
01300
01301
01308 - (CGPoint)convertPoint:(CGPoint)aPoint fromView:(CPView)aView
01309 {
01310 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(aView, self));
01311 }
01312
01319 - (CGPoint)convertPoint:(CGPoint)aPoint toView:(CPView)aView
01320 {
01321 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, aView));
01322 }
01323
01330 - (CGSize)convertSize:(CGSize)aSize fromView:(CPView)aView
01331 {
01332 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(aView, self));
01333 }
01334
01341 - (CGSize)convertSize:(CGSize)aSize toView:(CPView)aView
01342 {
01343 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(self, aView));
01344 }
01345
01352 - (CGRect)convertRect:(CGRect)aRect fromView:(CPView)aView
01353 {
01354 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(aView, self));
01355 }
01356
01363 - (CGRect)convertRect:(CGRect)aRect toView:(CPView)aView
01364 {
01365 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, aView));
01366 }
01367
01380 - (void)setPostsFrameChangedNotifications:(BOOL)shouldPostFrameChangedNotifications
01381 {
01382 shouldPostFrameChangedNotifications = !!shouldPostFrameChangedNotifications;
01383
01384 if (_postsFrameChangedNotifications === shouldPostFrameChangedNotifications)
01385 return;
01386
01387 _postsFrameChangedNotifications = shouldPostFrameChangedNotifications;
01388
01389 if (_postsFrameChangedNotifications)
01390 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
01391 }
01392
01396 - (BOOL)postsFrameChangedNotifications
01397 {
01398 return _postsFrameChangedNotifications;
01399 }
01400
01413 - (void)setPostsBoundsChangedNotifications:(BOOL)shouldPostBoundsChangedNotifications
01414 {
01415 shouldPostBoundsChangedNotifications = !!shouldPostBoundsChangedNotifications;
01416
01417 if (_postsBoundsChangedNotifications === shouldPostBoundsChangedNotifications)
01418 return;
01419
01420 _postsBoundsChangedNotifications = shouldPostBoundsChangedNotifications;
01421
01422 if (_postsBoundsChangedNotifications)
01423 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
01424 }
01425
01431 - (BOOL)postsBoundsChangedNotifications
01432 {
01433 return _postsBoundsChangedNotifications;
01434 }
01435
01446 - (void)dragImage:(CPImage)anImage at:(CGPoint)aLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
01447 {
01448 [_window dragImage:anImage at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
01449 }
01450
01461 - (void)dragView:(CPView)aView at:(CPPoint)aLocation offset:(CPSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
01462 {
01463 [_window dragView:aView at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
01464 }
01465
01470 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes
01471 {
01472 if (!pasteboardTypes)
01473 return;
01474
01475 var theWindow = [self window];
01476
01477 [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
01478 [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
01479 [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
01480
01481 _registeredDraggedTypesArray = nil;
01482 }
01483
01488 - (CPArray)registeredDraggedTypes
01489 {
01490 if (!_registeredDraggedTypesArray)
01491 _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
01492
01493 return _registeredDraggedTypesArray;
01494 }
01495
01499 - (void)unregisterDraggedTypes
01500 {
01501 [[self window] _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
01502
01503 _registeredDraggedTypes = [CPSet set];
01504 _registeredDraggedTypesArray = [];
01505 }
01506
01511 - (void)drawRect:(CPRect)aRect
01512 {
01513
01514 }
01515
01516
01517
01521 - (void)setNeedsDisplay:(BOOL)aFlag
01522 {
01523 if (aFlag)
01524 [self setNeedsDisplayInRect:[self bounds]];
01525 #if PLATFORM(DOM)
01526 else
01527 CPDOMDisplayServerRemoveView(self);
01528 #endif
01529 }
01530
01535 - (void)setNeedsDisplayInRect:(CPRect)aRect
01536 {
01537 #if PLATFORM(DOM)
01538 var hash = [[self class] hash],
01539 hasCustomDrawRect = CustomDrawRectViews[hash];
01540
01541 if (!hasCustomDrawRect && typeof hasCustomDrawRect === "undefined")
01542 {
01543 hasCustomDrawRect = [self methodForSelector:@selector(drawRect:)] != [CPView instanceMethodForSelector:@selector(drawRect:)];
01544 CustomDrawRectViews[hash] = hasCustomDrawRect;
01545 }
01546
01547 if (!hasCustomDrawRect)
01548 return;
01549 #endif
01550
01551 if (_CGRectIsEmpty(aRect))
01552 return;
01553
01554 if (_dirtyRect && !_CGRectIsEmpty(_dirtyRect))
01555 _dirtyRect = CGRectUnion(aRect, _dirtyRect);
01556 else
01557 _dirtyRect = _CGRectMakeCopy(aRect);
01558
01559 #if PLATFORM(DOM)
01560 CPDOMDisplayServerAddView(self);
01561 #endif
01562 }
01563
01564 - (BOOL)needsDisplay
01565 {
01566 return _dirtyRect && !_CGRectIsEmpty(_dirtyRect);
01567 }
01568
01572 - (void)displayIfNeeded
01573 {
01574 if ([self needsDisplay])
01575 [self displayRect:_dirtyRect];
01576 }
01577
01581 - (void)display
01582 {
01583 [self displayRect:[self visibleRect]];
01584 }
01585
01586 - (void)displayIfNeededInRect:(CGRect)aRect
01587 {
01588 if ([self needsDisplay])
01589 [self displayRect:aRect];
01590 }
01591
01596 - (void)displayRect:(CPRect)aRect
01597 {
01598 [self viewWillDraw];
01599
01600 [self displayRectIgnoringOpacity:aRect inContext:nil];
01601
01602 _dirtyRect = NULL;
01603 }
01604
01605 - (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext
01606 {
01607 [self lockFocus];
01608
01609 CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect);
01610
01611 [self drawRect:aRect];
01612 [self unlockFocus];
01613 }
01614
01615 - (void)viewWillDraw
01616 {
01617 }
01618
01622 - (void)lockFocus
01623 {
01624 if (!_graphicsContext)
01625 {
01626 var graphicsPort = CGBitmapGraphicsContextCreate();
01627
01628 _DOMContentsElement = graphicsPort.DOMElement;
01629
01630 _DOMContentsElement.style.zIndex = -100;
01631
01632 _DOMContentsElement.style.overflow = "hidden";
01633 _DOMContentsElement.style.position = "absolute";
01634 _DOMContentsElement.style.visibility = "visible";
01635
01636 _DOMContentsElement.width = ROUND(_CGRectGetWidth(_frame));
01637 _DOMContentsElement.height = ROUND(_CGRectGetHeight(_frame));
01638
01639 _DOMContentsElement.style.top = "0px";
01640 _DOMContentsElement.style.left = "0px";
01641 _DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
01642 _DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
01643
01644 CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement);
01645
01646 _graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES];
01647 }
01648
01649 [CPGraphicsContext setCurrentContext:_graphicsContext];
01650
01651 CGContextSaveGState([_graphicsContext graphicsPort]);
01652 }
01653
01657 - (void)unlockFocus
01658 {
01659 CGContextRestoreGState([_graphicsContext graphicsPort]);
01660
01661 [CPGraphicsContext setCurrentContext:nil];
01662 }
01663
01664 - (void)setNeedsLayout
01665 {
01666 _needsLayout = YES;
01667
01668 #if PLATFORM(DOM)
01669 var hash = [[self class] hash],
01670 hasCustomLayoutSubviews = CustomLayoutSubviewsViews[hash];
01671
01672 if (hasCustomLayoutSubviews === undefined)
01673 {
01674 hasCustomLayoutSubviews = [self methodForSelector:@selector(layoutSubviews)] != [CPView instanceMethodForSelector:@selector(layoutSubviews)];
01675 CustomLayoutSubviewsViews[hash] = hasCustomLayoutSubviews;
01676 }
01677
01678 if (!hasCustomLayoutSubviews)
01679 return;
01680
01681 if (_needsLayout)
01682 {
01683 CPDOMDisplayServerAddView(self);
01684 }
01685 #endif
01686 }
01687
01688 - (void)layoutIfNeeded
01689 {
01690 if (_needsLayout)
01691 {
01692 _needsLayout = NO;
01693
01694 [self layoutSubviews];
01695 }
01696 }
01697
01698 - (void)layoutSubviews
01699 {
01700 }
01701
01705 - (BOOL)isOpaque
01706 {
01707 return NO;
01708 }
01709
01713 - (CGRect)visibleRect
01714 {
01715 if (!_superview)
01716 return _bounds;
01717
01718 return CGRectIntersection([self convertRect:[_superview visibleRect] fromView:_superview], _bounds);
01719 }
01720
01721
01722
01723 - (CPScrollView)_enclosingClipView
01724 {
01725 var superview = _superview,
01726 clipViewClass = [CPClipView class];
01727
01728 while(superview && ![superview isKindOfClass:clipViewClass])
01729 superview = superview._superview;
01730
01731 return superview;
01732 }
01733
01738 - (void)scrollPoint:(CGPoint)aPoint
01739 {
01740 var clipView = [self _enclosingClipView];
01741
01742 if (!clipView)
01743 return;
01744
01745 [clipView scrollToPoint:[self convertPoint:aPoint toView:clipView]];
01746 }
01747
01753 - (BOOL)scrollRectToVisible:(CGRect)aRect
01754 {
01755 var visibleRect = [self visibleRect];
01756
01757
01758 aRect = CGRectIntersection(aRect, _bounds);
01759
01760
01761 if (_CGRectIsEmpty(aRect) || CGRectContainsRect(visibleRect, aRect))
01762 return NO;
01763
01764 var enclosingClipView = [self _enclosingClipView];
01765
01766
01767 if (!enclosingClipView)
01768 return NO;
01769
01770 var scrollPoint = _CGPointMakeCopy(visibleRect.origin);
01771
01772
01773 if (_CGRectGetMinX(aRect) <= _CGRectGetMinX(visibleRect))
01774 scrollPoint.x = _CGRectGetMinX(aRect);
01775 else if (_CGRectGetMaxX(aRect) > _CGRectGetMaxX(visibleRect))
01776 scrollPoint.x += _CGRectGetMaxX(aRect) - _CGRectGetMaxX(visibleRect);
01777
01778 if (_CGRectGetMinY(aRect) <= _CGRectGetMinY(visibleRect))
01779 scrollPoint.y = CGRectGetMinY(aRect);
01780 else if (_CGRectGetMaxY(aRect) > _CGRectGetMaxY(visibleRect))
01781 scrollPoint.y += _CGRectGetMaxY(aRect) - _CGRectGetMaxY(visibleRect);
01782
01783 [enclosingClipView scrollToPoint:CGPointMake(scrollPoint.x, scrollPoint.y)];
01784
01785 return YES;
01786 }
01787
01788
01789
01790
01791 - (BOOL)autoscroll:(CPEvent)anEvent
01792 {
01793 return [[self superview] autoscroll:anEvent];
01794 }
01795
01802 - (CGRect)adjustScroll:(CGRect)proposedVisibleRect
01803 {
01804 return proposedVisibleRect;
01805 }
01806
01810 - (void)scrollRect:(CGRect)aRect by:(float)anAmount
01811 {
01812
01813 }
01814
01819 - (CPScrollView)enclosingScrollView
01820 {
01821 var superview = _superview,
01822 scrollViewClass = [CPScrollView class];
01823
01824 while(superview && ![superview isKindOfClass:scrollViewClass])
01825 superview = superview._superview;
01826
01827 return superview;
01828 }
01829
01835 - (void)scrollClipView:(CPClipView)aClipView toPoint:(CGPoint)aPoint
01836 {
01837 [aClipView scrollToPoint:aPoint];
01838 }
01839
01845 - (void)reflectScrolledClipView:(CPClipView)aClipView
01846 {
01847 }
01848
01849 @end
01850
01851 @implementation CPView (KeyView)
01852
01853 - (BOOL)canBecomeKeyView
01854 {
01855 return [self acceptsFirstResponder] && ![self isHiddenOrHasHiddenAncestor];
01856 }
01857
01858 - (CPView)nextKeyView
01859 {
01860 return _nextKeyView;
01861 }
01862
01863 - (CPView)nextValidKeyView
01864 {
01865 var result = [self nextKeyView];
01866
01867 while (result && ![result canBecomeKeyView])
01868 result = [result nextKeyView];
01869
01870 return result;
01871 }
01872
01873 - (CPView)previousKeyView
01874 {
01875 return _previousKeyView;
01876 }
01877
01878 - (CPView)previousValidKeyView
01879 {
01880 var result = [self previousKeyView];
01881
01882 while (result && ![result canBecomeKeyView])
01883 result = [result previousKeyView];
01884
01885 return result;
01886 }
01887
01888 - (void)_setPreviousKeyView:(CPView)previous
01889 {
01890 _previousKeyView = previous;
01891 }
01892
01893 - (void)setNextKeyView:(CPView)next
01894 {
01895 _nextKeyView = next;
01896 [_nextKeyView _setPreviousKeyView:self];
01897 }
01898
01899 @end
01900
01901 @implementation CPView (CoreAnimationAdditions)
01902
01906 - (void)setLayer:(CALayer)aLayer
01907 {
01908 if (_layer == aLayer)
01909 return;
01910
01911 if (_layer)
01912 {
01913 _layer._owningView = nil;
01914 #if PLATFORM(DOM)
01915 _DOMElement.removeChild(_layer._DOMElement);
01916 #endif
01917 }
01918
01919 _layer = aLayer;
01920
01921 if (_layer)
01922 {
01923 var bounds = CGRectMakeCopy([self bounds]);
01924
01925 [_layer _setOwningView:self];
01926
01927 #if PLATFORM(DOM)
01928 _layer._DOMElement.style.zIndex = 100;
01929
01930 _DOMElement.appendChild(_layer._DOMElement);
01931 #endif
01932 }
01933 }
01934
01938 - (CALayer)layer
01939 {
01940 return _layer;
01941 }
01942
01947 - (void)setWantsLayer:(BOOL)aFlag
01948 {
01949 _wantsLayer = !!aFlag;
01950 }
01951
01956 - (BOOL)wantsLayer
01957 {
01958 return _wantsLayer;
01959 }
01960
01961 @end
01962
01963 @implementation CPView (Theming)
01964 #pragma mark Theme States
01965
01966 - (unsigned)themeState
01967 {
01968 return _themeState;
01969 }
01970
01971 - (BOOL)hasThemeState:(CPThemeState)aState
01972 {
01973 return !!(_themeState & ((typeof aState === "string") ? CPThemeState(aState) : aState));
01974 }
01975
01976 - (BOOL)setThemeState:(CPThemeState)aState
01977 {
01978 var newState = (typeof aState === "string") ? CPThemeState(aState) : aState;
01979
01980 if (_themeState & newState)
01981 return NO;
01982
01983 _themeState |= newState;
01984
01985 [self setNeedsLayout];
01986 [self setNeedsDisplay:YES];
01987
01988 return YES;
01989 }
01990
01991 - (BOOL)unsetThemeState:(CPThemeState)aState
01992 {
01993 var newState = ((typeof aState === "string") ? CPThemeState(aState) : aState);
01994
01995 if (!(_themeState & newState))
01996 return NO;
01997
01998 _themeState &= ~newState;
01999
02000 [self setNeedsLayout];
02001 [self setNeedsDisplay:YES];
02002
02003 return YES;
02004 }
02005
02006 #pragma mark Theme Attributes
02007
02008 + (CPString)themeClass
02009 {
02010 return nil;
02011 }
02012
02013 + (CPDictionary)themeAttributes
02014 {
02015 return nil;
02016 }
02017
02018 + (CPArray)_themeAttributes
02019 {
02020 if (!CachedThemeAttributes)
02021 CachedThemeAttributes = {};
02022
02023 var theClass = [self class],
02024 CPViewClass = [CPView class],
02025 attributes = [];
02026
02027 for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
02028 {
02029 var cachedAttributes = CachedThemeAttributes[class_getName(theClass)];
02030
02031 if (cachedAttributes)
02032 {
02033 attributes = attributes.length ? attributes.concat(cachedAttributes) : attributes;
02034 CachedThemeAttributes[[self className]] = attributes;
02035
02036 break;
02037 }
02038
02039 var attributeDictionary = [theClass themeAttributes];
02040
02041 if (!attributeDictionary)
02042 continue;
02043
02044 var attributeKeys = [attributeDictionary allKeys],
02045 attributeCount = attributeKeys.length;
02046
02047 while (attributeCount--)
02048 {
02049 var attributeName = attributeKeys[attributeCount];
02050
02051 attributes.push([attributeDictionary objectForKey:attributeName]);
02052 attributes.push(attributeName);
02053 }
02054 }
02055
02056 return attributes;
02057 }
02058
02059 - (void)_loadThemeAttributes
02060 {
02061 var theClass = [self class],
02062 attributes = [theClass _themeAttributes],
02063 count = attributes.length;
02064
02065 if (!count)
02066 return;
02067
02068 var theme = [self theme],
02069 themeClass = [theClass themeClass];
02070
02071 _themeAttributes = {};
02072
02073 while (count--)
02074 {
02075 var attributeName = attributes[count--],
02076 attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]];
02077
02078 [attribute setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
02079
02080 _themeAttributes[attributeName] = attribute;
02081 }
02082 }
02083
02084 - (void)setTheme:(CPTheme)aTheme
02085 {
02086 if (_theme === aTheme)
02087 return;
02088
02089 _theme = aTheme;
02090
02091 [self viewDidChangeTheme];
02092 }
02093
02094 - (CPTheme)theme
02095 {
02096 return _theme;
02097 }
02098
02099 - (void)viewDidChangeTheme
02100 {
02101 if (!_themeAttributes)
02102 return;
02103
02104 var theme = [self theme],
02105 themeClass = [[self class] themeClass];
02106
02107 for (var attributeName in _themeAttributes)
02108 if (_themeAttributes.hasOwnProperty(attributeName))
02109 [_themeAttributes[attributeName] setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
02110 }
02111
02112 - (CPDictionary)_themeAttributeDictionary
02113 {
02114 var dictionary = [CPDictionary dictionary];
02115
02116 if (_themeAttributes)
02117 {
02118 var theme = [self theme];
02119
02120 for (var attributeName in _themeAttributes)
02121 if (_themeAttributes.hasOwnProperty(attributeName))
02122 [dictionary setObject:_themeAttributes[attributeName] forKey:attributeName];
02123 }
02124
02125 return dictionary;
02126 }
02127
02128 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState
02129 {
02130 if (!_themeAttributes || !_themeAttributes[aName])
02131 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02132
02133 var currentValue = [self currentValueForThemeAttribute:aName];
02134
02135 [_themeAttributes[aName] setValue:aValue forState:aState];
02136
02137 if ([self currentValueForThemeAttribute:aName] === currentValue)
02138 return;
02139
02140 [self setNeedsDisplay:YES];
02141 [self setNeedsLayout];
02142 }
02143
02144 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName
02145 {
02146 if (!_themeAttributes || !_themeAttributes[aName])
02147 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02148
02149 var currentValue = [self currentValueForThemeAttribute:aName];
02150
02151 [_themeAttributes[aName] setValue:aValue];
02152
02153 if ([self currentValueForThemeAttribute:aName] === currentValue)
02154 return;
02155
02156 [self setNeedsDisplay:YES];
02157 [self setNeedsLayout];
02158 }
02159
02160 - (id)valueForThemeAttribute:(CPString)aName inState:(CPThemeState)aState
02161 {
02162 if (!_themeAttributes || !_themeAttributes[aName])
02163 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02164
02165 return [_themeAttributes[aName] valueForState:aState];
02166 }
02167
02168 - (id)valueForThemeAttribute:(CPString)aName
02169 {
02170 if (!_themeAttributes || !_themeAttributes[aName])
02171 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02172
02173 return [_themeAttributes[aName] value];
02174 }
02175
02176 - (void)currentValueForThemeAttribute:(CPString)aName
02177 {
02178 if (!_themeAttributes || !_themeAttributes[aName])
02179 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02180
02181 return [_themeAttributes[aName] valueForState:_themeState];
02182 }
02183
02184 @end
02185
02186 var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
02187 CPViewAutoresizesSubviewsKey = @"CPViewAutoresizesSubviews",
02188 CPViewBackgroundColorKey = @"CPViewBackgroundColor",
02189 CPViewBoundsKey = @"CPViewBoundsKey",
02190 CPViewFrameKey = @"CPViewFrameKey",
02191 CPViewHitTestsKey = @"CPViewHitTestsKey",
02192 CPViewIsHiddenKey = @"CPViewIsHiddenKey",
02193 CPViewOpacityKey = @"CPViewOpacityKey",
02194 CPViewSubviewsKey = @"CPViewSubviewsKey",
02195 CPViewSuperviewKey = @"CPViewSuperviewKey",
02196 CPViewTagKey = @"CPViewTagKey",
02197 CPViewThemeStateKey = @"CPViewThemeStateKey",
02198 CPViewWindowKey = @"CPViewWindowKey",
02199 CPViewNextKeyViewKey = @"CPViewNextKeyViewKey",
02200 CPViewPreviousKeyViewKey = @"CPViewPreviousKeyViewKey";
02201
02202 @implementation CPView (CPCoding)
02203
02209 - (id)initWithCoder:(CPCoder)aCoder
02210 {
02211
02212
02213
02214
02215 #if PLATFORM(DOM)
02216 _DOMElement = DOMElementPrototype.cloneNode(false);
02217 #endif
02218
02219
02220 _frame = [aCoder decodeRectForKey:CPViewFrameKey];
02221 _bounds = [aCoder decodeRectForKey:CPViewBoundsKey];
02222
02223 self = [super initWithCoder:aCoder];
02224
02225 if (self)
02226 {
02227
02228 _tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1;
02229
02230 _window = [aCoder decodeObjectForKey:CPViewWindowKey];
02231 _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || [];
02232 _superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
02233
02234 _autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
02235 _autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
02236
02237 _hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey];
02238
02239
02240 #if PLATFORM(DOM)
02241 _DOMImageParts = [];
02242 _DOMImageSizes = [];
02243
02244 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame));
02245 CPDOMDisplayServerSetStyleSize(_DOMElement, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame));
02246
02247 var index = 0,
02248 count = _subviews.length;
02249
02250 for (; index < count; ++index)
02251 {
02252 CPDOMDisplayServerAppendChild(_DOMElement, _subviews[index]._DOMElement);
02253
02254 }
02255 #endif
02256 _displayHash = [self hash];
02257
02258 if ([aCoder containsValueForKey:CPViewIsHiddenKey])
02259 [self setHidden:[aCoder decodeBoolForKey:CPViewIsHiddenKey]];
02260 else
02261 _isHidden = NO;
02262
02263 if ([aCoder containsValueForKey:CPViewOpacityKey])
02264 [self setAlphaValue:[aCoder decodeIntForKey:CPViewOpacityKey]];
02265 else
02266 _opacity = 1.0;
02267
02268 [self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]];
02269
02270 _theme = [CPTheme defaultTheme];
02271 _themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
02272 _themeAttributes = {};
02273
02274 var theClass = [self class],
02275 themeClass = [theClass themeClass],
02276 attributes = [theClass _themeAttributes],
02277 count = attributes.length;
02278
02279 while (count--)
02280 {
02281 var attributeName = attributes[count--];
02282
02283 _themeAttributes[attributeName] = CPThemeAttributeDecode(aCoder, attributeName, attributes[count], _theme, themeClass);
02284 }
02285
02286 [self setNeedsDisplay:YES];
02287 }
02288
02289 return self;
02290 }
02291
02296 - (void)encodeWithCoder:(CPCoder)aCoder
02297 {
02298 [super encodeWithCoder:aCoder];
02299
02300 if (_tag !== -1)
02301 [aCoder encodeInt:_tag forKey:CPViewTagKey];
02302
02303 [aCoder encodeRect:_frame forKey:CPViewFrameKey];
02304 [aCoder encodeRect:_bounds forKey:CPViewBoundsKey];
02305
02306
02307 if (_window !== nil)
02308 [aCoder encodeConditionalObject:_window forKey:CPViewWindowKey];
02309
02310 if (_subviews.length > 0)
02311 [aCoder encodeObject:_subviews forKey:CPViewSubviewsKey];
02312
02313
02314 if (_superview !== nil)
02315 [aCoder encodeConditionalObject:_superview forKey:CPViewSuperviewKey];
02316
02317 if (_autoresizingMask !== CPViewNotSizable)
02318 [aCoder encodeInt:_autoresizingMask forKey:CPViewAutoresizingMaskKey];
02319
02320 if (!_autoresizesSubviews)
02321 [aCoder encodeBool:_autoresizesSubviews forKey:CPViewAutoresizesSubviewsKey];
02322
02323 if (_backgroundColor !== nil)
02324 [aCoder encodeObject:_backgroundColor forKey:CPViewBackgroundColorKey];
02325
02326 if (_hitTests !== YES)
02327 [aCoder encodeBool:_hitTests forKey:CPViewHitTestsKey];
02328
02329 if (_opacity !== 1.0)
02330 [aCoder encodeFloat:_opacity forKey:CPViewOpacityKey];
02331
02332 if (_isHidden)
02333 [aCoder encodeBool:_isHidden forKey:CPViewIsHiddenKey];
02334
02335 var nextKeyView = [self nextKeyView];
02336
02337 if (nextKeyView !== nil)
02338 [aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey];
02339
02340 var previousKeyView = [self previousKeyView];
02341
02342 if (previousKeyView !== nil)
02343 [aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
02344
02345 [aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey];
02346
02347 for (var attributeName in _themeAttributes)
02348 if (_themeAttributes.hasOwnProperty(attributeName))
02349 CPThemeAttributeEncode(aCoder, _themeAttributes[attributeName]);
02350 }
02351
02352 @end
02353
02354 var _CPViewFullScreenModeStateMake = function(aView)
02355 {
02356 var superview = aView._superview;
02357
02358 return { autoresizingMask:aView._autoresizingMask, frame:CGRectMakeCopy(aView._frame), index:(superview ? [superview._subviews indexOfObjectIdenticalTo:aView] : 0), superview:superview };
02359 }
02360
02361 var _CPViewGetTransform = function( fromView, toView)
02362 {
02363 var transform = CGAffineTransformMakeIdentity(),
02364 sameWindow = YES,
02365 fromWindow = nil,
02366 toWindow = nil;
02367
02368 if (fromView)
02369 {
02370 var view = fromView;
02371
02372
02373
02374 while (view && view != toView)
02375 {
02376 var frame = view._frame;
02377
02378 transform.tx += _CGRectGetMinX(frame);
02379 transform.ty += _CGRectGetMinY(frame);
02380
02381 if (view._boundsTransform)
02382 {
02383 _CGAffineTransformConcatTo(transform, view._boundsTransform, transform);
02384 }
02385
02386 view = view._superview;
02387 }
02388
02389
02390 if (view === toView)
02391 return transform;
02392
02393 else if (fromView && toView)
02394 {
02395 fromWindow = [fromView window];
02396 toWindow = [toView window];
02397
02398 if (fromWindow && toWindow && fromWindow !== toWindow)
02399 {
02400 sameWindow = NO;
02401
02402 var frame = [fromWindow frame];
02403
02404 transform.tx += _CGRectGetMinX(frame);
02405 transform.ty += _CGRectGetMinY(frame);
02406 }
02407 }
02408 }
02409
02410
02411 var view = toView;
02412
02413 while (view)
02414 {
02415 var frame = view._frame;
02416
02417 transform.tx -= _CGRectGetMinX(frame);
02418 transform.ty -= _CGRectGetMinY(frame);
02419
02420 if (view._boundsTransform)
02421 {
02422 _CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform);
02423 }
02424
02425 view = view._superview;
02426 }
02427
02428 if (!sameWindow)
02429 {
02430 var frame = [toWindow frame];
02431
02432 transform.tx -= _CGRectGetMinX(frame);
02433 transform.ty -= _CGRectGetMinY(frame);
02434 }
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454 return transform;
02455 }