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 "CPGeometry.j"
00031 @import "CPGraphicsContext.j"
00032 @import "CPResponder.j"
00033 @import "CPTheme.j"
00034 @import "_CPDisplayServer.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 #endif
00099
00100 var CPViewFlags = { },
00101 CPViewHasCustomDrawRect = 1 << 0,
00102 CPViewHasCustomLayoutSubviews = 1 << 1;
00103
00121 @implementation CPView : CPResponder
00122 {
00123 CPWindow _window;
00124
00125 CPView _superview;
00126 CPArray _subviews;
00127
00128 CPGraphicsContext _graphicsContext;
00129
00130 int _tag;
00131
00132 CGRect _frame;
00133 CGRect _bounds;
00134 CGAffineTransform _boundsTransform;
00135 CGAffineTransform _inverseBoundsTransform;
00136
00137 CPSet _registeredDraggedTypes;
00138 CPArray _registeredDraggedTypesArray;
00139
00140 BOOL _isHidden;
00141 BOOL _hitTests;
00142
00143 BOOL _postsFrameChangedNotifications;
00144 BOOL _postsBoundsChangedNotifications;
00145 BOOL _inhibitFrameAndBoundsChangedNotifications;
00146
00147 #if PLATFORM(DOM)
00148 DOMElement _DOMElement;
00149 DOMElement _DOMContentsElement;
00150
00151 CPArray _DOMImageParts;
00152 CPArray _DOMImageSizes;
00153
00154 unsigned _backgroundType;
00155 #endif
00156
00157 CGRect _dirtyRect;
00158
00159 float _opacity;
00160 CPColor _backgroundColor;
00161
00162 BOOL _autoresizesSubviews;
00163 unsigned _autoresizingMask;
00164
00165 CALayer _layer;
00166 BOOL _wantsLayer;
00167
00168
00169 BOOL _isInFullScreenMode;
00170
00171 _CPViewFullScreenModeState _fullScreenModeState;
00172
00173
00174 BOOL _needsLayout;
00175 JSObject _ephemeralSubviews;
00176
00177
00178 CPTheme _theme;
00179 JSObject _themeAttributes;
00180 unsigned _themeState;
00181
00182 JSObject _ephemeralSubviewsForNames;
00183 CPSet _ephereralSubviews;
00184
00185
00186 CPView _nextKeyView;
00187 CPView _previousKeyView;
00188
00189 unsigned _viewClassFlags;
00190 }
00191
00192
00193
00194
00195
00196 + (void)initialize
00197 {
00198 if (self !== [CPView class])
00199 return;
00200
00201 #if PLATFORM(DOM)
00202 DOMElementPrototype = document.createElement("div");
00203
00204 var style = DOMElementPrototype.style;
00205
00206 style.overflow = "hidden";
00207 style.position = "absolute";
00208 style.visibility = "visible";
00209 style.zIndex = 0;
00210 #endif
00211
00212 CachedNotificationCenter = [CPNotificationCenter defaultCenter];
00213 }
00214
00215 - (void)setupViewFlags
00216 {
00217 var theClass = [self class],
00218 classUID = [theClass UID];
00219
00220 if (CPViewFlags[classUID] === undefined)
00221 {
00222 var flags = 0;
00223
00224 if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)])
00225 flags |= CPViewHasCustomDrawRect;
00226
00227 if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)])
00228 flags |= CPViewHasCustomLayoutSubviews;
00229
00230 CPViewFlags[classUID] = flags;
00231 }
00232
00233 _viewClassFlags = CPViewFlags[classUID];
00234 }
00235
00236 + (CPSet)keyPathsForValuesAffectingFrame
00237 {
00238 return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
00239 }
00240
00241 + (CPSet)keyPathsForValuesAffectingBounds
00242 {
00243 return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
00244 }
00245
00246 - (id)init
00247 {
00248 return [self initWithFrame:CGRectMakeZero()];
00249 }
00250
00255 - (id)initWithFrame:(CGRect)aFrame
00256 {
00257 self = [super init];
00258
00259 if (self)
00260 {
00261 var width = _CGRectGetWidth(aFrame),
00262 height = _CGRectGetHeight(aFrame);
00263
00264 _subviews = [];
00265 _registeredDraggedTypes = [CPSet set];
00266 _registeredDraggedTypesArray = [];
00267
00268 _tag = -1;
00269
00270 _frame = _CGRectMakeCopy(aFrame);
00271 _bounds = _CGRectMake(0.0, 0.0, width, height);
00272
00273 _autoresizingMask = CPViewNotSizable;
00274 _autoresizesSubviews = YES;
00275
00276 _opacity = 1.0;
00277 _isHidden = NO;
00278 _hitTests = YES;
00279
00280 #if PLATFORM(DOM)
00281 _DOMElement = DOMElementPrototype.cloneNode(false);
00282
00283 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame));
00284 CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
00285
00286 _DOMImageParts = [];
00287 _DOMImageSizes = [];
00288 #endif
00289
00290 _theme = [CPTheme defaultTheme];
00291 _themeState = CPThemeStateNormal;
00292
00293 [self setupViewFlags];
00294
00295 [self _loadThemeAttributes];
00296 }
00297
00298 return self;
00299 }
00300
00305 - (CPView)superview
00306 {
00307 return _superview;
00308 }
00309
00314 - (CPArray)subviews
00315 {
00316 return [_subviews copy];
00317 }
00318
00322 - (CPWindow)window
00323 {
00324 return _window;
00325 }
00326
00331 - (void)addSubview:(CPView)aSubview
00332 {
00333 [self _insertSubview:aSubview atIndex:CPNotFound];
00334 }
00335
00342 - (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView
00343 {
00344 var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound;
00345
00346
00347 if (index === CPNotFound)
00348 index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0;
00349
00350
00351 else if (anOrderingMode === CPWindowAbove)
00352 ++index;
00353
00354 [self _insertSubview:aSubview atIndex:index];
00355 }
00356
00357
00358 - (void)_insertSubview:(CPView)aSubview atIndex:(int)anIndex
00359 {
00360
00361 var count = _subviews.length;
00362
00363
00364 [[self window] _dirtyKeyViewLoop];
00365
00366
00367 if (aSubview._superview == self)
00368 {
00369 var index = [_subviews indexOfObjectIdenticalTo:aSubview];
00370
00371
00372 if (index === anIndex || index === count - 1 && anIndex === count)
00373 return;
00374
00375 [_subviews removeObjectAtIndex:index];
00376
00377 #if PLATFORM(DOM)
00378 CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement);
00379 #endif
00380
00381 if (anIndex > index)
00382 --anIndex;
00383
00384
00385 --count;
00386 }
00387 else
00388 {
00389
00390 [aSubview removeFromSuperview];
00391
00392
00393 [aSubview _setWindow:_window];
00394
00395
00396 [aSubview viewWillMoveToSuperview:self];
00397
00398
00399 aSubview._superview = self;
00400 }
00401
00402 if (anIndex === CPNotFound || anIndex >= count)
00403 {
00404 _subviews.push(aSubview);
00405
00406 #if PLATFORM(DOM)
00407
00408 CPDOMDisplayServerAppendChild(_DOMElement, aSubview._DOMElement);
00409 #endif
00410 }
00411 else
00412 {
00413 _subviews.splice(anIndex, 0, aSubview);
00414
00415 #if PLATFORM(DOM)
00416
00417 CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement);
00418 #endif
00419 }
00420
00421 [aSubview setNextResponder:self];
00422 [aSubview viewDidMoveToSuperview];
00423
00424 [self didAddSubview:aSubview];
00425 }
00426
00431 - (void)didAddSubview:(CPView)aSubview
00432 {
00433 }
00434
00439 - (void)removeFromSuperview
00440 {
00441 if (!_superview)
00442 return;
00443
00444
00445 [[self window] _dirtyKeyViewLoop];
00446
00447 [_superview willRemoveSubview:self];
00448
00449 [_superview._subviews removeObject:self];
00450
00451 #if PLATFORM(DOM)
00452 CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
00453 #endif
00454 _superview = nil;
00455
00456 [self _setWindow:nil];
00457 }
00458
00464 - (void)replaceSubview:(CPView)aSubview with:(CPView)aView
00465 {
00466 if (aSubview._superview != self)
00467 return;
00468
00469 var index = [_subviews indexOfObjectIdenticalTo:aSubview];
00470
00471 [aSubview removeFromSuperview];
00472
00473 [self _insertSubview:aView atIndex:index];
00474 }
00475
00476 - (void)setSubviews:(CPArray)newSubviews
00477 {
00478 if (!newSubviews)
00479 [CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
00480
00481
00482 if ([_subviews isEqual:newSubviews])
00483 return;
00484
00485
00486 if ([_subviews count] === 0)
00487 {
00488 var index = 0,
00489 count = [newSubviews count];
00490
00491 for (; index < count; ++index)
00492 [self addSubview:newSubviews[index]];
00493
00494 return;
00495 }
00496
00497
00498 if ([newSubviews count] === 0)
00499 {
00500 var count = [_subviews count];
00501
00502 while (count--)
00503 [_subviews[count] removeFromSuperview];
00504
00505 return;
00506 }
00507
00508
00509 var removedSubviews = [CPMutableSet setWithArray:_subviews];
00510
00511 [removedSubviews removeObjectsInArray:newSubviews];
00512 [removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
00513
00514
00515 var addedSubviews = [CPMutableSet setWithArray:newSubviews];
00516
00517 [addedSubviews removeObjectsInArray:_subviews];
00518
00519 var addedSubview = nil,
00520 addedSubviewEnumerator = [addedSubviews objectEnumerator];
00521
00522 while (addedSubview = [addedSubviewEnumerator nextObject])
00523 [self addSubview:addedSubview];
00524
00525
00526 if ([_subviews isEqual:newSubviews])
00527 return;
00528
00529 _subviews = [newSubviews copy];
00530
00531 #if PLATFORM(DOM)
00532 var index = 0,
00533 count = [_subviews count];
00534
00535 for (; index < count; ++index)
00536 {
00537 var subview = _subviews[index];
00538
00539 CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
00540 CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
00541 }
00542 #endif
00543 }
00544
00545
00546 - (void)_setWindow:(CPWindow)aWindow
00547 {
00548 if (_window === aWindow)
00549 return;
00550
00551 [[self window] _dirtyKeyViewLoop];
00552
00553
00554 if ([_window firstResponder] === self)
00555 [_window makeFirstResponder:nil];
00556
00557
00558 [self viewWillMoveToWindow:aWindow];
00559
00560
00561
00562 if (_registeredDraggedTypes)
00563 {
00564 [_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
00565 [aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
00566 }
00567
00568 _window = aWindow;
00569
00570 var count = [_subviews count];
00571
00572 while (count--)
00573 [_subviews[count] _setWindow:aWindow];
00574
00575 [self viewDidMoveToWindow];
00576
00577 [[self window] _dirtyKeyViewLoop];
00578 }
00579
00584 - (BOOL)isDescendantOf:(CPView)aView
00585 {
00586 var view = self;
00587
00588 do
00589 {
00590 if (view == aView)
00591 return YES;
00592 } while(view = [view superview])
00593
00594 return NO;
00595 }
00596
00600 - (void)viewDidMoveToSuperview
00601 {
00602
00603 [self setNeedsDisplay:YES];
00604 }
00605
00609 - (void)viewDidMoveToWindow
00610 {
00611 }
00612
00617 - (void)viewWillMoveToSuperview:(CPView)aView
00618 {
00619 }
00620
00625 - (void)viewWillMoveToWindow:(CPWindow)aWindow
00626 {
00627 }
00628
00633 - (void)willRemoveSubview:(CPView)aView
00634 {
00635 }
00636
00641 - (CPMenuItem)enclosingMenuItem
00642 {
00643 var view = self;
00644
00645 while (view && ![view isKindOfClass:[_CPMenuItemView class]])
00646 view = [view superview];
00647
00648 if (view)
00649 return view._menuItem;
00650
00651 return nil;
00652
00653
00654
00655
00656
00657
00658
00659 }
00660
00661 - (void)setTag:(CPInteger)aTag
00662 {
00663 _tag = aTag;
00664 }
00665
00666 - (CPInteger)tag
00667 {
00668 return _tag;
00669 }
00670
00671 - (CPView)viewWithTag:(CPInteger)aTag
00672 {
00673 if ([self tag] == aTag)
00674 return self;
00675
00676 var index = 0,
00677 count = _subviews.length;
00678
00679 for (; index < count; ++index)
00680 {
00681 var view = [_subviews[index] viewWithTag:aTag];
00682
00683 if (view)
00684 return view;
00685 }
00686
00687 return nil;
00688 }
00689
00694 - (BOOL)isFlipped
00695 {
00696 return YES;
00697 }
00698
00706 - (void)setFrame:(CGRect)aFrame
00707 {
00708 if (_CGRectEqualToRect(_frame, aFrame))
00709 return;
00710
00711 _inhibitFrameAndBoundsChangedNotifications = YES;
00712
00713 [self setFrameOrigin:aFrame.origin];
00714 [self setFrameSize:aFrame.size];
00715
00716 _inhibitFrameAndBoundsChangedNotifications = NO;
00717
00718 if (_postsFrameChangedNotifications)
00719 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00720 }
00721
00726 - (CGRect)frame
00727 {
00728 return _CGRectMakeCopy(_frame);
00729 }
00730
00731 - (CGPoint)frameOrigin
00732 {
00733 return _CGPointMakeCopy(_frame.origin);
00734 }
00735
00736 - (CGSize)frameSize
00737 {
00738 return _CGSizeMakeCopy(_frame.size);
00739 }
00740
00748 - (void)setCenter:(CGPoint)aPoint
00749 {
00750 [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)];
00751 }
00752
00757 - (CGPoint)center
00758 {
00759 return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y);
00760 }
00761
00769 - (void)setFrameOrigin:(CGPoint)aPoint
00770 {
00771 var origin = _frame.origin;
00772
00773 if (!aPoint || _CGPointEqualToPoint(origin, aPoint))
00774 return;
00775
00776 origin.x = aPoint.x;
00777 origin.y = aPoint.y;
00778
00779 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00780 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00781
00782 #if PLATFORM(DOM)
00783 var transform = _superview ? _superview._boundsTransform : NULL;
00784
00785 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
00786 #endif
00787 }
00788
00795 - (void)setFrameSize:(CGSize)aSize
00796 {
00797 var size = _frame.size;
00798
00799 if (!aSize || _CGSizeEqualToSize(size, aSize))
00800 return;
00801
00802 var oldSize = _CGSizeMakeCopy(size);
00803
00804 size.width = aSize.width;
00805 size.height = aSize.height;
00806
00807 if (YES)
00808 {
00809 _bounds.size.width = aSize.width;
00810 _bounds.size.height = aSize.height;
00811 }
00812
00813 if (_layer)
00814 [_layer _owningViewBoundsChanged];
00815
00816 if (_autoresizesSubviews)
00817 [self resizeSubviewsWithOldSize:oldSize];
00818
00819 [self setNeedsLayout];
00820 [self setNeedsDisplay:YES];
00821
00822 #if PLATFORM(DOM)
00823 CPDOMDisplayServerSetStyleSize(_DOMElement, size.width, size.height);
00824
00825 if (_DOMContentsElement)
00826 {
00827 CPDOMDisplayServerSetSize(_DOMContentsElement, size.width, size.height);
00828 CPDOMDisplayServerSetStyleSize(_DOMContentsElement, size.width, size.height);
00829 }
00830
00831 if (_backgroundType !== BackgroundTrivialColor)
00832 {
00833 var images = [[_backgroundColor patternImage] imageSlices];
00834
00835 if (_backgroundType === BackgroundVerticalThreePartImage)
00836 {
00837 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
00838 }
00839
00840 else if (_backgroundType === BackgroundHorizontalThreePartImage)
00841 {
00842 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
00843 }
00844
00845 else if (_backgroundType === BackgroundNinePartImage)
00846 {
00847 var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
00848 height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
00849
00850 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
00851 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
00852 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
00853 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
00854 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
00855 }
00856 }
00857 #endif
00858
00859 if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00860 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
00861 }
00862
00868 - (void)setBounds:(CGRect)bounds
00869 {
00870 if (_CGRectEqualToRect(_bounds, bounds))
00871 return;
00872
00873 _inhibitFrameAndBoundsChangedNotifications = YES;
00874
00875 [self setBoundsOrigin:bounds.origin];
00876 [self setBoundsSize:bounds.size];
00877
00878 _inhibitFrameAndBoundsChangedNotifications = NO;
00879
00880 if (_postsBoundsChangedNotifications)
00881 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00882 }
00883
00888 - (CGRect)bounds
00889 {
00890 return _CGRectMakeCopy(_bounds);
00891 }
00892
00893 - (CGPoint)boundsOrigin
00894 {
00895 return _CGPointMakeCopy(_bounds.origin);
00896 }
00897
00898 - (CGSize)boundsSize
00899 {
00900 return _CGSizeMakeCopy(_bounds.size);
00901 }
00902
00909 - (void)setBoundsOrigin:(CGPoint)aPoint
00910 {
00911 var origin = _bounds.origin;
00912
00913 if (_CGPointEqualToPoint(origin, aPoint))
00914 return;
00915
00916 origin.x = aPoint.x;
00917 origin.y = aPoint.y;
00918
00919 if (origin.x != 0 || origin.y != 0)
00920 {
00921 _boundsTransform = _CGAffineTransformMakeTranslation(-origin.x, -origin.y);
00922 _inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform);
00923 }
00924 else
00925 {
00926 _boundsTransform = nil;
00927 _inverseBoundsTransform = nil;
00928 }
00929
00930 #if PLATFORM(DOM)
00931 var index = _subviews.length;
00932
00933 while (index--)
00934 {
00935 var view = _subviews[index],
00936 origin = view._frame.origin;
00937
00938 CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y);
00939 }
00940 #endif
00941
00942 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00943 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00944 }
00945
00952 - (void)setBoundsSize:(CGSize)aSize
00953 {
00954 var size = _bounds.size;
00955
00956 if (_CGSizeEqualToSize(size, aSize))
00957 return;
00958
00959 var frameSize = _frame.size;
00960
00961 if (!_CGSizeEqualToSize(size, frameSize))
00962 {
00963 var origin = _bounds.origin;
00964
00965 origin.x /= size.width / frameSize.width;
00966 origin.y /= size.height / frameSize.height;
00967 }
00968
00969 size.width = aSize.width;
00970 size.height = aSize.height;
00971
00972 if (!_CGSizeEqualToSize(size, frameSize))
00973 {
00974 var origin = _bounds.origin;
00975
00976 origin.x *= size.width / frameSize.width;
00977 origin.y *= size.height / frameSize.height;
00978 }
00979
00980 if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
00981 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
00982 }
00983
00984
00989 - (void)resizeWithOldSuperviewSize:(CGSize)aSize
00990 {
00991 var mask = [self autoresizingMask];
00992
00993 if(mask == CPViewNotSizable)
00994 return;
00995
00996 var frame = _superview._frame,
00997 newFrame = _CGRectMakeCopy(_frame),
00998 dX = (_CGRectGetWidth(frame) - aSize.width) /
00999 (((mask & CPViewMinXMargin) ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
01000 dY = (_CGRectGetHeight(frame) - aSize.height) /
01001 ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0));
01002
01003 if (mask & CPViewMinXMargin)
01004 newFrame.origin.x += dX;
01005 if (mask & CPViewWidthSizable)
01006 newFrame.size.width += dX;
01007
01008 if (mask & CPViewMinYMargin)
01009 newFrame.origin.y += dY;
01010 if (mask & CPViewHeightSizable)
01011 newFrame.size.height += dY;
01012
01013 [self setFrame:newFrame];
01014 }
01015
01020 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
01021 {
01022 var count = _subviews.length;
01023
01024 while (count--)
01025 [_subviews[count] resizeWithOldSuperviewSize:aSize];
01026 }
01027
01035 - (void)setAutoresizesSubviews:(BOOL)aFlag
01036 {
01037 _autoresizesSubviews = !!aFlag;
01038 }
01039
01044 - (BOOL)autoresizesSubviews
01045 {
01046 return _autoresizesSubviews;
01047 }
01048
01053 - (void)setAutoresizingMask:(unsigned)aMask
01054 {
01055 _autoresizingMask = aMask;
01056 }
01057
01061 - (unsigned)autoresizingMask
01062 {
01063 return _autoresizingMask;
01064 }
01065
01066
01067
01071 - (BOOL)enterFullScreenMode
01072 {
01073 return [self enterFullScreenMode:nil withOptions:nil];
01074 }
01075
01081 - (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options
01082 {
01083 _fullScreenModeState = _CPViewFullScreenModeStateMake(self);
01084
01085 var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask];
01086
01087 [fullScreenWindow setLevel:CPScreenSaverWindowLevel];
01088 [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
01089
01090 var contentView = [fullScreenWindow contentView];
01091
01092 [contentView setBackgroundColor:[CPColor blackColor]];
01093 [contentView addSubview:self];
01094
01095 [self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
01096 [self setFrame:CGRectMakeCopy([contentView bounds])];
01097
01098 [fullScreenWindow makeKeyAndOrderFront:self];
01099
01100 [fullScreenWindow makeFirstResponder:self];
01101
01102 _isInFullScreenMode = YES;
01103
01104 return YES;
01105 }
01106
01110 - (void)exitFullScreenMode
01111 {
01112 [self exitFullScreenModeWithOptions:nil];
01113 }
01114
01119 - (void)exitFullScreenModeWithOptions:(CPDictionary)options
01120 {
01121 if (!_isInFullScreenMode)
01122 return;
01123
01124 _isInFullScreenMode = NO;
01125
01126 [self setFrame:_fullScreenModeState.frame];
01127 [self setAutoresizingMask:_fullScreenModeState.autoresizingMask];
01128 [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index];
01129
01130 [[self window] orderOut:self];
01131 }
01132
01136 - (BOOL)isInFullScreenMode
01137 {
01138 return _isInFullScreenMode;
01139 }
01140
01145 - (void)setHidden:(BOOL)aFlag
01146 {
01147 aFlag = !!aFlag;
01148
01149 if(_isHidden === aFlag)
01150 return;
01151
01152
01153
01154 _isHidden = aFlag;
01155 #if PLATFORM(DOM)
01156 _DOMElement.style.display = _isHidden ? "none" : "block";
01157 #endif
01158
01159 if (aFlag)
01160 {
01161 var view = [_window firstResponder];
01162
01163 if ([view isKindOfClass:[CPView class]])
01164 {
01165 do
01166 {
01167 if (self == view)
01168 {
01169 [_window makeFirstResponder:[self nextValidKeyView]];
01170 break;
01171 }
01172 }
01173 while (view = [view superview]);
01174 }
01175 }
01176 }
01177
01181 - (BOOL)isHidden
01182 {
01183 return _isHidden;
01184 }
01185
01191 - (void)setAlphaValue:(float)anAlphaValue
01192 {
01193 if (_opacity == anAlphaValue)
01194 return;
01195
01196 _opacity = anAlphaValue;
01197
01198 #if PLATFORM(DOM)
01199
01200 if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
01201 {
01202 if (anAlphaValue == 1.0)
01203 try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
01204 else
01205 _DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
01206 }
01207 else
01208 _DOMElement.style.opacity = anAlphaValue;
01209
01210 #endif
01211 }
01212
01217 - (float)alphaValue
01218 {
01219 return _opacity;
01220 }
01221
01226 - (BOOL)isHiddenOrHasHiddenAncestor
01227 {
01228 var view = self;
01229
01230 while (view && ![view isHidden])
01231 view = [view superview];
01232
01233 return view !== nil;
01234 }
01235
01241
01242 - (BOOL)acceptsFirstMouse:(CPEvent)anEvent
01243 {
01244 return YES;
01245 }
01246
01251 - (BOOL)hitTests
01252 {
01253 return _hitTests;
01254 }
01255
01260 - (void)setHitTests:(BOOL)shouldHitTest
01261 {
01262 _hitTests = !!shouldHitTest;
01263 }
01264
01270 - (CPView)hitTest:(CPPoint)aPoint
01271 {
01272 if(_isHidden || !_hitTests || !CPRectContainsPoint(_frame, aPoint))
01273 return nil;
01274
01275 var view = nil,
01276 i = _subviews.length,
01277 adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame));
01278
01279 if (_inverseBoundsTransform)
01280 adjustedPoint = _CGPointApplyAffineTransform(adjustedPoint, _inverseBoundsTransform);
01281
01282 while (i--)
01283 if (view = [_subviews[i] hitTest:adjustedPoint])
01284 return view;
01285
01286 return self;
01287 }
01288
01292 - (BOOL)needsPanelToBecomeKey
01293 {
01294 return NO;
01295 }
01296
01301 - (BOOL)mouseDownCanMoveWindow
01302 {
01303 return ![self isOpaque];
01304 }
01305
01306 - (void)mouseDown:(CPEvent)anEvent
01307 {
01308 if ([self mouseDownCanMoveWindow])
01309 [super mouseDown:anEvent];
01310 }
01311
01316 - (void)setBackgroundColor:(CPColor)aColor
01317 {
01318 if (_backgroundColor == aColor)
01319 return;
01320
01321 _backgroundColor = aColor;
01322
01323 #if PLATFORM(DOM)
01324 var patternImage = [_backgroundColor patternImage],
01325 amount = 0;
01326
01327 if ([patternImage isThreePartImage])
01328 {
01329 _backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
01330
01331 amount = 3 - _DOMImageParts.length;
01332 }
01333 else if ([patternImage isNinePartImage])
01334 {
01335 _backgroundType = BackgroundNinePartImage;
01336
01337 amount = 9 - _DOMImageParts.length;
01338 }
01339 else
01340 {
01341 _backgroundType = BackgroundTrivialColor;
01342
01343 amount = 0 - _DOMImageParts.length;
01344 }
01345
01346 if (amount > 0)
01347 while (amount--)
01348 {
01349 var DOMElement = DOMElementPrototype.cloneNode(false);
01350
01351 DOMElement.style.zIndex = -1000;
01352
01353 _DOMImageParts.push(DOMElement);
01354 _DOMElement.appendChild(DOMElement);
01355 }
01356 else
01357 {
01358 amount = -amount;
01359
01360 while (amount--)
01361 _DOMElement.removeChild(_DOMImageParts.pop());
01362 }
01363
01364 if (_backgroundType == BackgroundTrivialColor)
01365
01366
01367
01368 _DOMElement.style.background = _backgroundColor ? [_backgroundColor cssString] : "";
01369
01370 else
01371 {
01372 var slices = [patternImage imageSlices],
01373 count = MIN(_DOMImageParts.length, slices.length),
01374 frameSize = _frame.size;
01375
01376 while (count--)
01377 {
01378 var image = slices[count],
01379 size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero();
01380
01381 CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
01382
01383 _DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
01384 }
01385
01386 if (_backgroundType == BackgroundNinePartImage)
01387 {
01388 var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
01389 height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height;
01390
01391 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height);
01392 CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height);
01393 CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height);
01394 CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height);
01395 CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
01396
01397 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01398 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
01399 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
01400 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[3], NULL, 0.0, _DOMImageSizes[1].height);
01401 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[4], NULL, _DOMImageSizes[0].width, _DOMImageSizes[0].height);
01402 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[5], NULL, 0.0, _DOMImageSizes[1].height);
01403 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[6], NULL, 0.0, 0.0);
01404 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[7], NULL, _DOMImageSizes[6].width, 0.0);
01405 CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0);
01406 }
01407 else if (_backgroundType == BackgroundVerticalThreePartImage)
01408 {
01409 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
01410
01411 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01412 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height);
01413 CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0);
01414 }
01415 else if (_backgroundType == BackgroundHorizontalThreePartImage)
01416 {
01417 CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height);
01418
01419 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
01420 CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
01421 CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0);
01422 }
01423 }
01424 #endif
01425 }
01426
01430 - (CPColor)backgroundColor
01431 {
01432 return _backgroundColor;
01433 }
01434
01435
01442 - (CGPoint)convertPoint:(CGPoint)aPoint fromView:(CPView)aView
01443 {
01444 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(aView, self));
01445 }
01446
01453 - (CGPoint)convertPoint:(CGPoint)aPoint toView:(CPView)aView
01454 {
01455 return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, aView));
01456 }
01457
01464 - (CGSize)convertSize:(CGSize)aSize fromView:(CPView)aView
01465 {
01466 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(aView, self));
01467 }
01468
01475 - (CGSize)convertSize:(CGSize)aSize toView:(CPView)aView
01476 {
01477 return CGSizeApplyAffineTransform(aSize, _CPViewGetTransform(self, aView));
01478 }
01479
01486 - (CGRect)convertRect:(CGRect)aRect fromView:(CPView)aView
01487 {
01488 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(aView, self));
01489 }
01490
01497 - (CGRect)convertRect:(CGRect)aRect toView:(CPView)aView
01498 {
01499 return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, aView));
01500 }
01501
01514 - (void)setPostsFrameChangedNotifications:(BOOL)shouldPostFrameChangedNotifications
01515 {
01516 shouldPostFrameChangedNotifications = !!shouldPostFrameChangedNotifications;
01517
01518 if (_postsFrameChangedNotifications === shouldPostFrameChangedNotifications)
01519 return;
01520
01521 _postsFrameChangedNotifications = shouldPostFrameChangedNotifications;
01522
01523 if (_postsFrameChangedNotifications)
01524 [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
01525 }
01526
01530 - (BOOL)postsFrameChangedNotifications
01531 {
01532 return _postsFrameChangedNotifications;
01533 }
01534
01547 - (void)setPostsBoundsChangedNotifications:(BOOL)shouldPostBoundsChangedNotifications
01548 {
01549 shouldPostBoundsChangedNotifications = !!shouldPostBoundsChangedNotifications;
01550
01551 if (_postsBoundsChangedNotifications === shouldPostBoundsChangedNotifications)
01552 return;
01553
01554 _postsBoundsChangedNotifications = shouldPostBoundsChangedNotifications;
01555
01556 if (_postsBoundsChangedNotifications)
01557 [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
01558 }
01559
01565 - (BOOL)postsBoundsChangedNotifications
01566 {
01567 return _postsBoundsChangedNotifications;
01568 }
01569
01580 - (void)dragImage:(CPImage)anImage at:(CGPoint)aLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
01581 {
01582 [_window dragImage:anImage at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
01583 }
01584
01595 - (void)dragView:(CPView)aView at:(CPPoint)aLocation offset:(CPSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
01596 {
01597 [_window dragView:aView at:[self convertPoint:aLocation toView:nil] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
01598 }
01599
01604 - (void)registerForDraggedTypes:(CPArray)pasteboardTypes
01605 {
01606 if (!pasteboardTypes || ![pasteboardTypes count])
01607 return;
01608
01609 var theWindow = [self window];
01610
01611 [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
01612 [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
01613 [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
01614
01615 _registeredDraggedTypesArray = nil;
01616 }
01617
01622 - (CPArray)registeredDraggedTypes
01623 {
01624 if (!_registeredDraggedTypesArray)
01625 _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
01626
01627 return _registeredDraggedTypesArray;
01628 }
01629
01633 - (void)unregisterDraggedTypes
01634 {
01635 [[self window] _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
01636
01637 _registeredDraggedTypes = [CPSet set];
01638 _registeredDraggedTypesArray = [];
01639 }
01640
01645 - (void)drawRect:(CPRect)aRect
01646 {
01647
01648 }
01649
01650
01651
01655 - (void)setNeedsDisplay:(BOOL)aFlag
01656 {
01657 if (aFlag)
01658 [self setNeedsDisplayInRect:[self bounds]];
01659 }
01660
01665 - (void)setNeedsDisplayInRect:(CPRect)aRect
01666 {
01667 if (!(_viewClassFlags & CPViewHasCustomDrawRect))
01668 return;
01669
01670 if (_CGRectIsEmpty(aRect))
01671 return;
01672
01673 if (_dirtyRect && !_CGRectIsEmpty(_dirtyRect))
01674 _dirtyRect = CGRectUnion(aRect, _dirtyRect);
01675 else
01676 _dirtyRect = _CGRectMakeCopy(aRect);
01677
01678 _CPDisplayServerAddDisplayObject(self);
01679 }
01680
01681 - (BOOL)needsDisplay
01682 {
01683 return _dirtyRect && !_CGRectIsEmpty(_dirtyRect);
01684 }
01685
01689 - (void)displayIfNeeded
01690 {
01691 if ([self needsDisplay])
01692 [self displayRect:_dirtyRect];
01693 }
01694
01698 - (void)display
01699 {
01700 [self displayRect:[self visibleRect]];
01701 }
01702
01703 - (void)displayIfNeededInRect:(CGRect)aRect
01704 {
01705 if ([self needsDisplay])
01706 [self displayRect:aRect];
01707 }
01708
01713 - (void)displayRect:(CPRect)aRect
01714 {
01715 [self viewWillDraw];
01716
01717 [self displayRectIgnoringOpacity:aRect inContext:nil];
01718
01719 _dirtyRect = NULL;
01720 }
01721
01722 - (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext
01723 {
01724 [self lockFocus];
01725
01726 CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect);
01727
01728 [self drawRect:aRect];
01729 [self unlockFocus];
01730 }
01731
01732 - (void)viewWillDraw
01733 {
01734 }
01735
01739 - (void)lockFocus
01740 {
01741 if (!_graphicsContext)
01742 {
01743 var graphicsPort = CGBitmapGraphicsContextCreate();
01744
01745 _DOMContentsElement = graphicsPort.DOMElement;
01746
01747 _DOMContentsElement.style.zIndex = -100;
01748
01749 _DOMContentsElement.style.overflow = "hidden";
01750 _DOMContentsElement.style.position = "absolute";
01751 _DOMContentsElement.style.visibility = "visible";
01752
01753 _DOMContentsElement.width = ROUND(_CGRectGetWidth(_frame));
01754 _DOMContentsElement.height = ROUND(_CGRectGetHeight(_frame));
01755
01756 _DOMContentsElement.style.top = "0px";
01757 _DOMContentsElement.style.left = "0px";
01758 _DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
01759 _DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
01760
01761 #if PLATFORM(DOM)
01762 CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement);
01763 #endif
01764 _graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES];
01765 }
01766
01767 [CPGraphicsContext setCurrentContext:_graphicsContext];
01768
01769 CGContextSaveGState([_graphicsContext graphicsPort]);
01770 }
01771
01775 - (void)unlockFocus
01776 {
01777 CGContextRestoreGState([_graphicsContext graphicsPort]);
01778
01779 [CPGraphicsContext setCurrentContext:nil];
01780 }
01781
01782 - (void)setNeedsLayout
01783 {
01784 if (!(_viewClassFlags & CPViewHasCustomLayoutSubviews))
01785 return;
01786
01787 _needsLayout = YES;
01788
01789 _CPDisplayServerAddLayoutObject(self);
01790 }
01791
01792 - (void)layoutIfNeeded
01793 {
01794 if (_needsLayout)
01795 {
01796 _needsLayout = NO;
01797
01798 [self layoutSubviews];
01799 }
01800 }
01801
01802 - (void)layoutSubviews
01803 {
01804 }
01805
01809 - (BOOL)isOpaque
01810 {
01811 return NO;
01812 }
01813
01817 - (CGRect)visibleRect
01818 {
01819 if (!_superview)
01820 return _bounds;
01821
01822 return CGRectIntersection([self convertRect:[_superview visibleRect] fromView:_superview], _bounds);
01823 }
01824
01825
01826
01827 - (CPScrollView)_enclosingClipView
01828 {
01829 var superview = _superview,
01830 clipViewClass = [CPClipView class];
01831
01832 while(superview && ![superview isKindOfClass:clipViewClass])
01833 superview = superview._superview;
01834
01835 return superview;
01836 }
01837
01842 - (void)scrollPoint:(CGPoint)aPoint
01843 {
01844 var clipView = [self _enclosingClipView];
01845
01846 if (!clipView)
01847 return;
01848
01849 [clipView scrollToPoint:[self convertPoint:aPoint toView:clipView]];
01850 }
01851
01857 - (BOOL)scrollRectToVisible:(CGRect)aRect
01858 {
01859 var visibleRect = [self visibleRect];
01860
01861
01862 aRect = CGRectIntersection(aRect, _bounds);
01863
01864
01865 if (_CGRectIsEmpty(aRect) || CGRectContainsRect(visibleRect, aRect))
01866 return NO;
01867
01868 var enclosingClipView = [self _enclosingClipView];
01869
01870
01871 if (!enclosingClipView)
01872 return NO;
01873
01874 var scrollPoint = _CGPointMakeCopy(visibleRect.origin);
01875
01876
01877 if (_CGRectGetMinX(aRect) <= _CGRectGetMinX(visibleRect))
01878 scrollPoint.x = _CGRectGetMinX(aRect);
01879 else if (_CGRectGetMaxX(aRect) > _CGRectGetMaxX(visibleRect))
01880 scrollPoint.x += _CGRectGetMaxX(aRect) - _CGRectGetMaxX(visibleRect);
01881
01882 if (_CGRectGetMinY(aRect) <= _CGRectGetMinY(visibleRect))
01883 scrollPoint.y = CGRectGetMinY(aRect);
01884 else if (_CGRectGetMaxY(aRect) > _CGRectGetMaxY(visibleRect))
01885 scrollPoint.y += _CGRectGetMaxY(aRect) - _CGRectGetMaxY(visibleRect);
01886
01887 [enclosingClipView scrollToPoint:CGPointMake(scrollPoint.x, scrollPoint.y)];
01888
01889 return YES;
01890 }
01891
01892
01893
01894
01895 - (BOOL)autoscroll:(CPEvent)anEvent
01896 {
01897 return [[self superview] autoscroll:anEvent];
01898 }
01899
01906 - (CGRect)adjustScroll:(CGRect)proposedVisibleRect
01907 {
01908 return proposedVisibleRect;
01909 }
01910
01914 - (void)scrollRect:(CGRect)aRect by:(float)anAmount
01915 {
01916
01917 }
01918
01923 - (CPScrollView)enclosingScrollView
01924 {
01925 var superview = _superview,
01926 scrollViewClass = [CPScrollView class];
01927
01928 while(superview && ![superview isKindOfClass:scrollViewClass])
01929 superview = superview._superview;
01930
01931 return superview;
01932 }
01933
01939 - (void)scrollClipView:(CPClipView)aClipView toPoint:(CGPoint)aPoint
01940 {
01941 [aClipView scrollToPoint:aPoint];
01942 }
01943
01949 - (void)reflectScrolledClipView:(CPClipView)aClipView
01950 {
01951 }
01952
01953 @end
01954
01955 @implementation CPView (KeyView)
01956
01957 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
01958 {
01959 var count = [_subviews count];
01960
01961
01962 while (count--)
01963 if ([_subviews[count] performKeyEquivalent:anEvent])
01964 return YES;
01965
01966 return NO;
01967 }
01968
01969 - (BOOL)canBecomeKeyView
01970 {
01971 return [self acceptsFirstResponder] && ![self isHiddenOrHasHiddenAncestor];
01972 }
01973
01974 - (CPView)nextKeyView
01975 {
01976 return _nextKeyView;
01977 }
01978
01979 - (CPView)nextValidKeyView
01980 {
01981 var result = [self nextKeyView];
01982
01983 while (result && ![result canBecomeKeyView])
01984 result = [result nextKeyView];
01985
01986 return result;
01987 }
01988
01989 - (CPView)previousKeyView
01990 {
01991 return _previousKeyView;
01992 }
01993
01994 - (CPView)previousValidKeyView
01995 {
01996 var result = [self previousKeyView];
01997
01998 while (result && ![result canBecomeKeyView])
01999 result = [result previousKeyView];
02000
02001 return result;
02002 }
02003
02004 - (void)_setPreviousKeyView:(CPView)previous
02005 {
02006 _previousKeyView = previous;
02007 }
02008
02009 - (void)setNextKeyView:(CPView)next
02010 {
02011 _nextKeyView = next;
02012 [_nextKeyView _setPreviousKeyView:self];
02013 }
02014
02015 @end
02016
02017 @implementation CPView (CoreAnimationAdditions)
02018
02022 - (void)setLayer:(CALayer)aLayer
02023 {
02024 if (_layer == aLayer)
02025 return;
02026
02027 if (_layer)
02028 {
02029 _layer._owningView = nil;
02030 #if PLATFORM(DOM)
02031 _DOMElement.removeChild(_layer._DOMElement);
02032 #endif
02033 }
02034
02035 _layer = aLayer;
02036
02037 if (_layer)
02038 {
02039 var bounds = CGRectMakeCopy([self bounds]);
02040
02041 [_layer _setOwningView:self];
02042
02043 #if PLATFORM(DOM)
02044 _layer._DOMElement.style.zIndex = 100;
02045
02046 _DOMElement.appendChild(_layer._DOMElement);
02047 #endif
02048 }
02049 }
02050
02054 - (CALayer)layer
02055 {
02056 return _layer;
02057 }
02058
02063 - (void)setWantsLayer:(BOOL)aFlag
02064 {
02065 _wantsLayer = !!aFlag;
02066 }
02067
02072 - (BOOL)wantsLayer
02073 {
02074 return _wantsLayer;
02075 }
02076
02077 @end
02078
02079 @implementation CPView (Theming)
02080 #pragma mark Theme States
02081
02082 - (unsigned)themeState
02083 {
02084 return _themeState;
02085 }
02086
02087 - (BOOL)hasThemeState:(CPThemeState)aState
02088 {
02089 return !!(_themeState & ((typeof aState === "string") ? CPThemeState(aState) : aState));
02090 }
02091
02092 - (BOOL)setThemeState:(CPThemeState)aState
02093 {
02094 var newState = (typeof aState === "string") ? CPThemeState(aState) : aState;
02095
02096 if (_themeState & newState)
02097 return NO;
02098
02099 _themeState |= newState;
02100
02101 [self setNeedsLayout];
02102 [self setNeedsDisplay:YES];
02103
02104 return YES;
02105 }
02106
02107 - (BOOL)unsetThemeState:(CPThemeState)aState
02108 {
02109 var newState = ((typeof aState === "string") ? CPThemeState(aState) : aState);
02110
02111 if (!(_themeState & newState))
02112 return NO;
02113
02114 _themeState &= ~newState;
02115
02116 [self setNeedsLayout];
02117 [self setNeedsDisplay:YES];
02118
02119 return YES;
02120 }
02121
02122 #pragma mark Theme Attributes
02123
02124 + (CPString)themeClass
02125 {
02126 return nil;
02127 }
02128
02129 + (CPDictionary)themeAttributes
02130 {
02131 return nil;
02132 }
02133
02134 + (CPArray)_themeAttributes
02135 {
02136 if (!CachedThemeAttributes)
02137 CachedThemeAttributes = {};
02138
02139 var theClass = [self class],
02140 CPViewClass = [CPView class],
02141 attributes = [],
02142 nullValue = [CPNull null];
02143
02144 for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
02145 {
02146 var cachedAttributes = CachedThemeAttributes[class_getName(theClass)];
02147
02148 if (cachedAttributes)
02149 {
02150 attributes = attributes.length ? attributes.concat(cachedAttributes) : attributes;
02151 CachedThemeAttributes[[self className]] = attributes;
02152
02153 break;
02154 }
02155
02156 var attributeDictionary = [theClass themeAttributes];
02157
02158 if (!attributeDictionary)
02159 continue;
02160
02161 var attributeKeys = [attributeDictionary allKeys],
02162 attributeCount = attributeKeys.length;
02163
02164 while (attributeCount--)
02165 {
02166 var attributeName = attributeKeys[attributeCount],
02167 attributeValue = [attributeDictionary objectForKey:attributeName];
02168
02169 attributes.push(attributeValue === nullValue ? nil : attributeValue);
02170 attributes.push(attributeName);
02171 }
02172 }
02173
02174 return attributes;
02175 }
02176
02177 - (void)_loadThemeAttributes
02178 {
02179 var theClass = [self class],
02180 attributes = [theClass _themeAttributes],
02181 count = attributes.length;
02182
02183 if (!count)
02184 return;
02185
02186 var theme = [self theme],
02187 themeClass = [theClass themeClass];
02188
02189 _themeAttributes = {};
02190
02191 while (count--)
02192 {
02193 var attributeName = attributes[count--],
02194 attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]];
02195
02196 [attribute setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
02197
02198 _themeAttributes[attributeName] = attribute;
02199 }
02200 }
02201
02202 - (void)setTheme:(CPTheme)aTheme
02203 {
02204 if (_theme === aTheme)
02205 return;
02206
02207 _theme = aTheme;
02208
02209 [self viewDidChangeTheme];
02210 }
02211
02212 - (CPTheme)theme
02213 {
02214 return _theme;
02215 }
02216
02217 - (void)viewDidChangeTheme
02218 {
02219 if (!_themeAttributes)
02220 return;
02221
02222 var theme = [self theme],
02223 themeClass = [[self class] themeClass];
02224
02225 for (var attributeName in _themeAttributes)
02226 if (_themeAttributes.hasOwnProperty(attributeName))
02227 [_themeAttributes[attributeName] setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
02228
02229 [self setNeedsLayout];
02230 [self setNeedsDisplay:YES];
02231 }
02232
02233 - (CPDictionary)_themeAttributeDictionary
02234 {
02235 var dictionary = [CPDictionary dictionary];
02236
02237 if (_themeAttributes)
02238 {
02239 var theme = [self theme];
02240
02241 for (var attributeName in _themeAttributes)
02242 if (_themeAttributes.hasOwnProperty(attributeName))
02243 [dictionary setObject:_themeAttributes[attributeName] forKey:attributeName];
02244 }
02245
02246 return dictionary;
02247 }
02248
02249 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState
02250 {
02251 if (!_themeAttributes || !_themeAttributes[aName])
02252 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02253
02254 var currentValue = [self currentValueForThemeAttribute:aName];
02255
02256 [_themeAttributes[aName] setValue:aValue forState:aState];
02257
02258 if ([self currentValueForThemeAttribute:aName] === currentValue)
02259 return;
02260
02261 [self setNeedsDisplay:YES];
02262 [self setNeedsLayout];
02263 }
02264
02265 - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName
02266 {
02267 if (!_themeAttributes || !_themeAttributes[aName])
02268 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02269
02270 var currentValue = [self currentValueForThemeAttribute:aName];
02271
02272 [_themeAttributes[aName] setValue:aValue];
02273
02274 if ([self currentValueForThemeAttribute:aName] === currentValue)
02275 return;
02276
02277 [self setNeedsDisplay:YES];
02278 [self setNeedsLayout];
02279 }
02280
02281 - (id)valueForThemeAttribute:(CPString)aName inState:(CPThemeState)aState
02282 {
02283 if (!_themeAttributes || !_themeAttributes[aName])
02284 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02285
02286 return [_themeAttributes[aName] valueForState:aState];
02287 }
02288
02289 - (id)valueForThemeAttribute:(CPString)aName
02290 {
02291 if (!_themeAttributes || !_themeAttributes[aName])
02292 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02293
02294 return [_themeAttributes[aName] value];
02295 }
02296
02297 - (id)currentValueForThemeAttribute:(CPString)aName
02298 {
02299 if (!_themeAttributes || !_themeAttributes[aName])
02300 [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
02301
02302 return [_themeAttributes[aName] valueForState:_themeState];
02303 }
02304
02305 - (CPView)createEphemeralSubviewNamed:(CPString)aViewName
02306 {
02307 return nil;
02308 }
02309
02310 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
02311 {
02312 return _CGRectMakeZero();
02313 }
02314
02315 - (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
02316 positioned:(CPWindowOrderingMode)anOrderingMode
02317 relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
02318 {
02319 if (!_ephemeralSubviewsForNames)
02320 {
02321 _ephemeralSubviewsForNames = {};
02322 _ephemeralSubviews = [CPSet set];
02323 }
02324
02325 var frame = [self rectForEphemeralSubviewNamed:aViewName];
02326
02327 if (frame && !_CGRectIsEmpty(frame))
02328 {
02329 if (!_ephemeralSubviewsForNames[aViewName])
02330 {
02331 _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
02332
02333 [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
02334
02335 if (_ephemeralSubviewsForNames[aViewName])
02336 [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
02337 }
02338
02339 if (_ephemeralSubviewsForNames[aViewName])
02340 [_ephemeralSubviewsForNames[aViewName] setFrame:frame];
02341 }
02342 else if (_ephemeralSubviewsForNames[aViewName])
02343 {
02344 [_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
02345
02346 [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
02347 delete _ephemeralSubviewsForNames[aViewName];
02348 }
02349
02350 return _ephemeralSubviewsForNames[aViewName];
02351 }
02352
02353 @end
02354
02355 var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
02356 CPViewAutoresizesSubviewsKey = @"CPViewAutoresizesSubviews",
02357 CPViewBackgroundColorKey = @"CPViewBackgroundColor",
02358 CPViewBoundsKey = @"CPViewBoundsKey",
02359 CPViewFrameKey = @"CPViewFrameKey",
02360 CPViewHitTestsKey = @"CPViewHitTestsKey",
02361 CPViewIsHiddenKey = @"CPViewIsHiddenKey",
02362 CPViewOpacityKey = @"CPViewOpacityKey",
02363 CPViewSubviewsKey = @"CPViewSubviewsKey",
02364 CPViewSuperviewKey = @"CPViewSuperviewKey",
02365 CPViewTagKey = @"CPViewTagKey",
02366 CPViewThemeStateKey = @"CPViewThemeStateKey",
02367 CPViewWindowKey = @"CPViewWindowKey",
02368 CPViewNextKeyViewKey = @"CPViewNextKeyViewKey",
02369 CPViewPreviousKeyViewKey = @"CPViewPreviousKeyViewKey";
02370
02371 @implementation CPView (CPCoding)
02372
02378 - (id)initWithCoder:(CPCoder)aCoder
02379 {
02380
02381
02382
02383
02384 #if PLATFORM(DOM)
02385 _DOMElement = DOMElementPrototype.cloneNode(false);
02386 #endif
02387
02388
02389 _frame = [aCoder decodeRectForKey:CPViewFrameKey];
02390 _bounds = [aCoder decodeRectForKey:CPViewBoundsKey];
02391
02392 self = [super initWithCoder:aCoder];
02393
02394 if (self)
02395 {
02396
02397 _tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1;
02398
02399 _window = [aCoder decodeObjectForKey:CPViewWindowKey];
02400 _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || [];
02401 _superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
02402
02403
02404 _registeredDraggedTypes = [CPSet set];
02405 _registeredDraggedTypesArray = [];
02406
02407 _autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
02408 _autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
02409
02410 _hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey];
02411
02412
02413 #if PLATFORM(DOM)
02414 _DOMImageParts = [];
02415 _DOMImageSizes = [];
02416
02417 CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame));
02418 CPDOMDisplayServerSetStyleSize(_DOMElement, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame));
02419
02420 var index = 0,
02421 count = _subviews.length;
02422
02423 for (; index < count; ++index)
02424 {
02425 CPDOMDisplayServerAppendChild(_DOMElement, _subviews[index]._DOMElement);
02426
02427 }
02428 #endif
02429
02430 if ([aCoder containsValueForKey:CPViewIsHiddenKey])
02431 [self setHidden:[aCoder decodeBoolForKey:CPViewIsHiddenKey]];
02432 else
02433 _isHidden = NO;
02434
02435 if ([aCoder containsValueForKey:CPViewOpacityKey])
02436 [self setAlphaValue:[aCoder decodeIntForKey:CPViewOpacityKey]];
02437 else
02438 _opacity = 1.0;
02439
02440 [self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]];
02441
02442 [self setupViewFlags];
02443
02444 _theme = [CPTheme defaultTheme];
02445 _themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
02446 _themeAttributes = {};
02447
02448 var theClass = [self class],
02449 themeClass = [theClass themeClass],
02450 attributes = [theClass _themeAttributes],
02451 count = attributes.length;
02452
02453 while (count--)
02454 {
02455 var attributeName = attributes[count--];
02456
02457 _themeAttributes[attributeName] = CPThemeAttributeDecode(aCoder, attributeName, attributes[count], _theme, themeClass);
02458 }
02459
02460 [self setNeedsDisplay:YES];
02461 [self setNeedsLayout];
02462 }
02463
02464 return self;
02465 }
02466
02471 - (void)encodeWithCoder:(CPCoder)aCoder
02472 {
02473 [super encodeWithCoder:aCoder];
02474
02475 if (_tag !== -1)
02476 [aCoder encodeInt:_tag forKey:CPViewTagKey];
02477
02478 [aCoder encodeRect:_frame forKey:CPViewFrameKey];
02479 [aCoder encodeRect:_bounds forKey:CPViewBoundsKey];
02480
02481
02482 if (_window !== nil)
02483 [aCoder encodeConditionalObject:_window forKey:CPViewWindowKey];
02484
02485 var count = [_subviews count],
02486 encodedSubviews = _subviews;
02487
02488 if (count > 0 && [_ephemeralSubviews count] > 0)
02489 {
02490 encodedSubviews = [encodedSubviews copy];
02491
02492 while (count--)
02493 if ([_ephemeralSubviews containsObject:encodedSubviews[count]])
02494 encodedSubviews.splice(count, 1);
02495 }
02496
02497 if (encodedSubviews.length > 0)
02498 [aCoder encodeObject:encodedSubviews forKey:CPViewSubviewsKey];
02499
02500
02501 if (_superview !== nil)
02502 [aCoder encodeConditionalObject:_superview forKey:CPViewSuperviewKey];
02503
02504 if (_autoresizingMask !== CPViewNotSizable)
02505 [aCoder encodeInt:_autoresizingMask forKey:CPViewAutoresizingMaskKey];
02506
02507 if (!_autoresizesSubviews)
02508 [aCoder encodeBool:_autoresizesSubviews forKey:CPViewAutoresizesSubviewsKey];
02509
02510 if (_backgroundColor !== nil)
02511 [aCoder encodeObject:_backgroundColor forKey:CPViewBackgroundColorKey];
02512
02513 if (_hitTests !== YES)
02514 [aCoder encodeBool:_hitTests forKey:CPViewHitTestsKey];
02515
02516 if (_opacity !== 1.0)
02517 [aCoder encodeFloat:_opacity forKey:CPViewOpacityKey];
02518
02519 if (_isHidden)
02520 [aCoder encodeBool:_isHidden forKey:CPViewIsHiddenKey];
02521
02522 var nextKeyView = [self nextKeyView];
02523
02524 if (nextKeyView !== nil)
02525 [aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey];
02526
02527 var previousKeyView = [self previousKeyView];
02528
02529 if (previousKeyView !== nil)
02530 [aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
02531
02532 [aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey];
02533
02534 for (var attributeName in _themeAttributes)
02535 if (_themeAttributes.hasOwnProperty(attributeName))
02536 CPThemeAttributeEncode(aCoder, _themeAttributes[attributeName]);
02537 }
02538
02539 @end
02540
02541 var _CPViewFullScreenModeStateMake = function(aView)
02542 {
02543 var superview = aView._superview;
02544
02545 return { autoresizingMask:aView._autoresizingMask, frame:CGRectMakeCopy(aView._frame), index:(superview ? [superview._subviews indexOfObjectIdenticalTo:aView] : 0), superview:superview };
02546 }
02547
02548 var _CPViewGetTransform = function( fromView, toView)
02549 {
02550 var transform = CGAffineTransformMakeIdentity(),
02551 sameWindow = YES,
02552 fromWindow = nil,
02553 toWindow = nil;
02554
02555 if (fromView)
02556 {
02557 var view = fromView;
02558
02559
02560
02561
02562 while (view && view != toView)
02563 {
02564 var frame = view._frame;
02565
02566 transform.tx += _CGRectGetMinX(frame);
02567 transform.ty += _CGRectGetMinY(frame);
02568
02569 if (view._boundsTransform)
02570 {
02571 _CGAffineTransformConcatTo(transform, view._boundsTransform, transform);
02572 }
02573
02574 view = view._superview;
02575 }
02576
02577
02578 if (view === toView)
02579 return transform;
02580
02581 else if (fromView && toView)
02582 {
02583 fromWindow = [fromView window];
02584 toWindow = [toView window];
02585
02586 if (fromWindow && toWindow && fromWindow !== toWindow)
02587 {
02588 sameWindow = NO;
02589
02590 var frame = [fromWindow frame];
02591
02592 transform.tx += _CGRectGetMinX(frame);
02593 transform.ty += _CGRectGetMinY(frame);
02594 }
02595 }
02596 }
02597
02598
02599 var view = toView;
02600
02601 while (view)
02602 {
02603 var frame = view._frame;
02604
02605 transform.tx -= _CGRectGetMinX(frame);
02606 transform.ty -= _CGRectGetMinY(frame);
02607
02608 if (view._boundsTransform)
02609 {
02610 _CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform);
02611 }
02612
02613 view = view._superview;
02614 }
02615
02616 if (!sameWindow)
02617 {
02618 var frame = [toWindow frame];
02619
02620 transform.tx -= _CGRectGetMinX(frame);
02621 transform.ty -= _CGRectGetMinY(frame);
02622 }
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642 return transform;
02643 }