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