PageRenderTime 75ms CodeModel.GetById 35ms app.highlight 15ms RepoModel.GetById 2ms app.codeStats 1ms

/AppKit/CPView.j

http://github.com/cacaodev/cappuccino
Unknown | 3784 lines | 3031 code | 753 blank | 0 comment | 0 complexity | 189fe62a410f5929b22f78688dde7a7e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * CPView.j
   3 * AppKit
   4 *
   5 * Created by Francisco Tolmasky.
   6 * Copyright 2008, 280 North, Inc.
   7 *
   8 * This library is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU Lesser General Public
  10 * License as published by the Free Software Foundation; either
  11 * version 2.1 of the License, or (at your option) any later version.
  12 *
  13 * This library is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16 * Lesser General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU Lesser General Public
  19 * License along with this library; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21 */
  22
  23@import <Foundation/CPArray.j>
  24@import <Foundation/CPObjJRuntime.j>
  25@import <Foundation/CPSet.j>
  26
  27@import "CGAffineTransform.j"
  28@import "CGGeometry.j"
  29@import "CPColor.j"
  30@import "CPGraphicsContext.j"
  31@import "CPResponder.j"
  32@import "CPTheme.j"
  33@import "CPWindow_Constants.j"
  34@import "_CPDisplayServer.j"
  35
  36@class _CPToolTip
  37@class CPWindow
  38@class _CPMenuItemView
  39@class CPPlatformWindow
  40@class CPMenu
  41@class CPClipView
  42@class CPScrollView
  43@class CALayer
  44
  45@global appkit_tag_dom_elements
  46
  47@typedef _CPViewFullScreenModeState
  48
  49#if PLATFORM(DOM)
  50
  51if (typeof(appkit_tag_dom_elements) !== "undefined" && appkit_tag_dom_elements)
  52{
  53    AppKitTagDOMElement = function(owner, element)
  54    {
  55        element.setAttribute("data-cappuccino-view", [owner className]);
  56        element.setAttribute("data-cappuccino-uid", [owner UID]);
  57    }
  58}
  59else
  60{
  61    AppKitTagDOMElement = function(owner, element)
  62    {
  63       // By default, do nothing.
  64    }
  65}
  66
  67#endif
  68
  69/*
  70    @global
  71    @group CPViewAutoresizingMasks
  72    The default resizingMask, the view will not resize or reposition itself.
  73*/
  74CPViewNotSizable    = 0;
  75/*
  76    @global
  77    @group CPViewAutoresizingMasks
  78    Allow for flexible space on the left hand side of the view.
  79*/
  80CPViewMinXMargin    = 1;
  81/*
  82    @global
  83    @group CPViewAutoresizingMasks
  84    The view should grow and shrink horizontally with its parent view.
  85*/
  86CPViewWidthSizable  = 2;
  87/*
  88    @global
  89    @group CPViewAutoresizingMasks
  90    Allow for flexible space to the right hand side of the view.
  91*/
  92CPViewMaxXMargin    = 4;
  93/*
  94    @global
  95    @group CPViewAutoresizingMasks
  96    Allow for flexible space above the view.
  97*/
  98CPViewMinYMargin    = 8;
  99/*
 100    @global
 101    @group CPViewAutoresizingMasks
 102    The view should grow and shrink vertically with its parent view.
 103*/
 104CPViewHeightSizable = 16;
 105/*
 106    @global
 107    @group CPViewAutoresizingMasks
 108    Allow for flexible space below the view.
 109*/
 110CPViewMaxYMargin    = 32;
 111
 112CPViewBoundsDidChangeNotification   = @"CPViewBoundsDidChangeNotification";
 113CPViewFrameDidChangeNotification    = @"CPViewFrameDidChangeNotification";
 114
 115var CachedNotificationCenter    = nil,
 116    CachedThemeAttributes       = nil;
 117
 118#if PLATFORM(DOM)
 119var DOMElementPrototype         = nil,
 120
 121    BackgroundTrivialColor              = 0,
 122    BackgroundVerticalThreePartImage    = 1,
 123    BackgroundHorizontalThreePartImage  = 2,
 124    BackgroundNinePartImage             = 3,
 125    BackgroundTransparentColor          = 4;
 126#endif
 127
 128var CPViewFlags                     = { },
 129    CPViewHasCustomDrawRect         = 1 << 0,
 130    CPViewHasCustomLayoutSubviews   = 1 << 1;
 131
 132
 133/*!
 134    @ingroup appkit
 135    @class CPView
 136
 137    <p>CPView is a class which provides facilities for drawing
 138    in a window and receiving events. It is the superclass of many of the visual
 139    elements of the GUI.</p>
 140
 141    <p>In order to display itself, a view must be placed in a window (represented by an
 142    CPWindow object). Within the window is a hierarchy of CPViews,
 143    headed by the window's content view. Every other view in a window is a descendant
 144    of this view.</p>
 145
 146    <p>Subclasses can override \c -drawRect: in order to implement their
 147    appearance. Other methods of CPView and CPResponder can
 148    also be overridden to handle user generated events.
 149*/
 150@implementation CPView : CPResponder
 151{
 152    CPWindow            _window;
 153
 154    CPView              _superview;
 155    CPArray             _subviews;
 156
 157    CPGraphicsContext   _graphicsContext;
 158
 159    int                 _tag;
 160    CPString            _identifier @accessors(property=identifier);
 161
 162    CGRect              _frame;
 163    CGRect              _bounds;
 164    CGAffineTransform   _boundsTransform;
 165    CGAffineTransform   _inverseBoundsTransform;
 166
 167    CPSet               _registeredDraggedTypes;
 168    CPArray             _registeredDraggedTypesArray;
 169
 170    BOOL                _isHidden;
 171    BOOL                _hitTests;
 172    BOOL                _clipsToBounds;
 173
 174    BOOL                _postsFrameChangedNotifications;
 175    BOOL                _postsBoundsChangedNotifications;
 176    BOOL                _inhibitFrameAndBoundsChangedNotifications;
 177    BOOL                _inLiveResize;
 178    BOOL                _isSuperviewAClipView;
 179
 180#if PLATFORM(DOM)
 181    DOMElement          _DOMElement;
 182    DOMElement          _DOMContentsElement;
 183
 184    CPArray             _DOMImageParts;
 185    CPArray             _DOMImageSizes;
 186
 187    unsigned            _backgroundType;
 188#endif
 189
 190    CGRect              _dirtyRect;
 191
 192    float               _opacity;
 193    CPColor             _backgroundColor;
 194
 195    BOOL                _autoresizesSubviews;
 196    unsigned            _autoresizingMask;
 197
 198    CALayer             _layer;
 199    BOOL                _wantsLayer;
 200
 201    // Full Screen State
 202    BOOL                _isInFullScreenMode;
 203
 204    _CPViewFullScreenModeState  _fullScreenModeState;
 205
 206    // Zoom Support
 207    BOOL                _isScaled;
 208    CGSize              _hierarchyScaleSize;
 209    CGSize              _scaleSize;
 210
 211    // Layout Support
 212    BOOL                _needsLayout;
 213    JSObject            _ephemeralSubviews;
 214
 215    // Theming Support
 216    CPTheme             _theme;
 217    CPString            _themeClass;
 218    JSObject            _themeAttributes;
 219    unsigned            _themeState;
 220
 221    JSObject            _ephemeralSubviewsForNames;
 222    CPSet               _ephereralSubviews;
 223
 224    // Key View Support
 225    CPView              _nextKeyView;
 226    CPView              _previousKeyView;
 227
 228    unsigned            _viewClassFlags;
 229
 230    // ToolTips
 231    CPString            _toolTip    @accessors(getter=toolTip);
 232    Function            _toolTipFunctionIn;
 233    Function            _toolTipFunctionOut;
 234    BOOL                _toolTipInstalled;
 235
 236    BOOL                _isObserving;
 237}
 238
 239/*
 240    Private method for Objective-J.
 241    @ignore
 242*/
 243+ (void)initialize
 244{
 245    if (self !== [CPView class])
 246        return;
 247
 248#if PLATFORM(DOM)
 249    DOMElementPrototype =  document.createElement("div");
 250
 251    var style = DOMElementPrototype.style;
 252
 253    style.overflow = "hidden";
 254    style.position = "absolute";
 255    style.visibility = "visible";
 256    style.zIndex = 0;
 257#endif
 258
 259    CachedNotificationCenter = [CPNotificationCenter defaultCenter];
 260}
 261
 262+ (Class)_binderClassForBinding:(CPString)aBinding
 263{
 264    if ([aBinding hasPrefix:CPHiddenBinding])
 265        return [CPMultipleValueOrBinding class];
 266
 267    return [super _binderClassForBinding:aBinding];
 268}
 269
 270- (void)_setupViewFlags
 271{
 272    var theClass = [self class],
 273        classUID = [theClass UID];
 274
 275    if (CPViewFlags[classUID] === undefined)
 276    {
 277        var flags = 0;
 278
 279        if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)])
 280            flags |= CPViewHasCustomDrawRect;
 281
 282        if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)])
 283            flags |= CPViewHasCustomLayoutSubviews;
 284
 285        CPViewFlags[classUID] = flags;
 286    }
 287
 288    _viewClassFlags = CPViewFlags[classUID];
 289}
 290
 291- (void)_setupToolTipHandlers
 292{
 293    _toolTipInstalled = NO;
 294    _toolTipFunctionIn = function(e) { [_CPToolTip scheduleToolTipForView:self]; }
 295    _toolTipFunctionOut = function(e) { [_CPToolTip invalidateCurrentToolTipIfNeeded]; };
 296}
 297
 298+ (CPSet)keyPathsForValuesAffectingFrame
 299{
 300    return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
 301}
 302
 303+ (CPSet)keyPathsForValuesAffectingBounds
 304{
 305    return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
 306}
 307
 308+ (CPMenu)defaultMenu
 309{
 310    return nil;
 311}
 312
 313- (id)init
 314{
 315    return [self initWithFrame:CGRectMakeZero()];
 316}
 317
 318/*!
 319    Initializes the receiver for usage with the specified bounding rectangle
 320    @return the initialized view
 321*/
 322- (id)initWithFrame:(CGRect)aFrame
 323{
 324    self = [super init];
 325
 326    if (self)
 327    {
 328        var width = CGRectGetWidth(aFrame),
 329            height = CGRectGetHeight(aFrame);
 330
 331        _subviews = [];
 332        _registeredDraggedTypes = [CPSet set];
 333        _registeredDraggedTypesArray = [];
 334
 335        _tag = -1;
 336
 337        _frame = CGRectMakeCopy(aFrame);
 338        _bounds = CGRectMake(0.0, 0.0, width, height);
 339
 340        _autoresizingMask = CPViewNotSizable;
 341        _autoresizesSubviews = YES;
 342        _clipsToBounds = YES;
 343
 344        _opacity = 1.0;
 345        _isHidden = NO;
 346        _hitTests = YES;
 347
 348        _hierarchyScaleSize = CGSizeMake(1.0 , 1.0);
 349        _scaleSize = CGSizeMake(1.0, 1.0);
 350        _isScaled = NO;
 351
 352        _theme = [CPTheme defaultTheme];
 353        _themeState = CPThemeStateNormal;
 354
 355#if PLATFORM(DOM)
 356        _DOMElement = DOMElementPrototype.cloneNode(false);
 357        AppKitTagDOMElement(self, _DOMElement);
 358
 359        CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, CGRectGetMinX(aFrame), CGRectGetMinY(aFrame));
 360        CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
 361
 362        _DOMImageParts = [];
 363        _DOMImageSizes = [];
 364#endif
 365
 366        [self _setupToolTipHandlers];
 367        [self _setupViewFlags];
 368
 369        [self _loadThemeAttributes];
 370    }
 371
 372    return self;
 373}
 374
 375
 376/*!
 377    Sets the tooltip for the receiver.
 378
 379    @param aToolTip the tooltip
 380*/
 381- (void)setToolTip:(CPString)aToolTip
 382{
 383    if (_toolTip == aToolTip)
 384        return;
 385
 386    if (aToolTip && ![aToolTip isKindOfClass:CPString])
 387        aToolTip = [aToolTip description];
 388
 389    _toolTip = aToolTip;
 390
 391    if (_toolTip)
 392        [self _installToolTipEventHandlers];
 393    else
 394        [self _uninstallToolTipEventHandlers];
 395}
 396
 397/*! @ignore
 398
 399    Install the handlers for the tooltip
 400*/
 401- (void)_installToolTipEventHandlers
 402{
 403    if (_toolTipInstalled)
 404        return;
 405
 406#if PLATFORM(DOM)
 407    if (_DOMElement.addEventListener)
 408    {
 409        _DOMElement.addEventListener("mouseover", _toolTipFunctionIn, YES);
 410        _DOMElement.addEventListener("keypress", _toolTipFunctionOut, YES);
 411        _DOMElement.addEventListener("mouseout", _toolTipFunctionOut, YES);
 412    }
 413    else if (_DOMElement.attachEvent)
 414    {
 415        _DOMElement.attachEvent("onmouseover", _toolTipFunctionIn);
 416        _DOMElement.attachEvent("onkeypress", _toolTipFunctionOut);
 417        _DOMElement.attachEvent("onmouseout", _toolTipFunctionOut);
 418    }
 419#endif
 420
 421    _toolTipInstalled = YES;
 422}
 423
 424/*! @ignore
 425
 426    Uninstall the handlers for the tooltip
 427*/
 428- (void)_uninstallToolTipEventHandlers
 429{
 430    if (!_toolTipInstalled)
 431        return;
 432
 433#if PLATFORM(DOM)
 434    if (_DOMElement.removeEventListener)
 435    {
 436        _DOMElement.removeEventListener("mouseover", _toolTipFunctionIn, YES);
 437        _DOMElement.removeEventListener("keypress", _toolTipFunctionOut, YES);
 438        _DOMElement.removeEventListener("mouseout", _toolTipFunctionOut, YES);
 439    }
 440    else if (_DOMElement.detachEvent)
 441    {
 442        _DOMElement.detachEvent("onmouseover", _toolTipFunctionIn);
 443        _DOMElement.detachEvent("onkeypress", _toolTipFunctionOut);
 444        _DOMElement.detachEvent("onmouseout", _toolTipFunctionOut);
 445    }
 446#endif
 447
 448    _toolTipInstalled = NO;
 449}
 450
 451/*!
 452    Returns the container view of the receiver
 453    @return the receiver's containing view
 454*/
 455- (CPView)superview
 456{
 457    return _superview;
 458}
 459
 460/*!
 461    Returns an array of all the views contained as direct children of the receiver
 462    @return an array of CPViews
 463*/
 464- (CPArray)subviews
 465{
 466    return [_subviews copy];
 467}
 468
 469/*!
 470    Returns the window containing this receiver
 471*/
 472- (CPWindow)window
 473{
 474    return _window;
 475}
 476
 477/*!
 478    Makes the argument a subview of the receiver.
 479    @param aSubview the CPView to make a subview
 480*/
 481- (void)addSubview:(CPView)aSubview
 482{
 483    [self _insertSubview:aSubview atIndex:CPNotFound];
 484}
 485
 486/*!
 487    Makes \c aSubview a subview of the receiver. It is positioned relative to \c anotherView
 488    @param aSubview the view to add as a subview
 489    @param anOrderingMode specifies \c aSubview's ordering relative to \c anotherView
 490    @param anotherView \c aSubview will be positioned relative to this argument
 491*/
 492- (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView
 493{
 494    var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound;
 495
 496    // In other words, if no view, then either all the way at the bottom or all the way at the top.
 497    if (index === CPNotFound)
 498        index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0;
 499
 500    // else, if we have a view, above if above.
 501    else if (anOrderingMode === CPWindowAbove)
 502        ++index;
 503
 504    [self _insertSubview:aSubview atIndex:index];
 505}
 506
 507/* @ignore */
 508- (void)_insertSubview:(CPView)aSubview atIndex:(int)anIndex
 509{
 510    if (aSubview === self)
 511        [CPException raise:CPInvalidArgumentException reason:"can't add a view as a subview of itself"];
 512#if DEBUG
 513    if (!aSubview._superview && _subviews.indexOf(aSubview) !== CPNotFound)
 514        [CPException raise:CPInvalidArgumentException reason:"can't insert a subview in duplicate (probably partially decoded)"];
 515#endif
 516
 517    // Notify the subview that it will be moving.
 518    [aSubview viewWillMoveToSuperview:self];
 519
 520    // We will have to adjust the z-index of all views starting at this index.
 521    var count = _subviews.length,
 522        lastWindow;
 523
 524    // Dirty the key view loop, in case the window wants to auto recalculate it
 525    [[self window] _dirtyKeyViewLoop];
 526
 527    // If this is already one of our subviews, remove it.
 528    if (aSubview._superview == self)
 529    {
 530        var index = [_subviews indexOfObjectIdenticalTo:aSubview];
 531
 532        // FIXME: should this be anIndex >= count? (last one)
 533        if (index === anIndex || index === count - 1 && anIndex === count)
 534            return;
 535
 536        [_subviews removeObjectAtIndex:index];
 537
 538#if PLATFORM(DOM)
 539        CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement);
 540#endif
 541
 542        if (anIndex > index)
 543            --anIndex;
 544
 545        //We've effectively made the subviews array shorter, so represent that.
 546        --count;
 547    }
 548    else
 549    {
 550        var superview = aSubview._superview;
 551
 552        lastWindow = [superview window];
 553
 554        // Remove the view from its previous superview.
 555        [aSubview _removeFromSuperview];
 556
 557        // Set ourselves as the superview.
 558        aSubview._superview = self;
 559    }
 560
 561    if (anIndex === CPNotFound || anIndex >= count)
 562    {
 563        _subviews.push(aSubview);
 564
 565#if PLATFORM(DOM)
 566        // Attach the actual node.
 567        CPDOMDisplayServerAppendChild(_DOMElement, aSubview._DOMElement);
 568#endif
 569    }
 570    else
 571    {
 572        _subviews.splice(anIndex, 0, aSubview);
 573
 574#if PLATFORM(DOM)
 575        // Attach the actual node.
 576        CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement);
 577#endif
 578    }
 579
 580    [aSubview setNextResponder:self];
 581    [aSubview _scaleSizeUnitSquareToSize:[self _hierarchyScaleSize]];
 582
 583    // If the subview is not hidden and one of its ancestors is hidden,
 584    // notify the subview that it is now hidden.
 585    if (![aSubview isHidden] && [self isHiddenOrHasHiddenAncestor])
 586        [aSubview _notifyViewDidHide];
 587
 588    [aSubview viewDidMoveToSuperview];
 589
 590    // Set the subview's window to our own.
 591    if (_window)
 592        [aSubview _setWindow:_window];
 593
 594    if (!_window && lastWindow)
 595        [aSubview _setWindow:nil];
 596
 597    // This method might be called before we are fully unarchived, in which case the theme state isn't set up yet
 598    // and none of the below matters anyhow.
 599    if (_themeState)
 600    {
 601        if ([self hasThemeState:CPThemeStateFirstResponder])
 602            [aSubview _notifyViewDidBecomeFirstResponder];
 603        else
 604            [aSubview _notifyViewDidResignFirstResponder];
 605
 606        if ([self hasThemeState:CPThemeStateKeyWindow])
 607            [aSubview _notifyWindowDidBecomeKey];
 608        else
 609            [aSubview _notifyWindowDidResignKey];
 610    }
 611
 612    [self didAddSubview:aSubview];
 613}
 614
 615/*!
 616    Called when the receiver has added \c aSubview to it's child views.
 617    @param aSubview the view that was added
 618*/
 619- (void)didAddSubview:(CPView)aSubview
 620{
 621}
 622
 623/*!
 624    Removes the receiver from it's container view and window.
 625    Does nothing if there's no container view.
 626*/
 627- (void)removeFromSuperview
 628{
 629    var superview = _superview;
 630
 631    [self viewWillMoveToSuperview:nil];
 632    [self _removeFromSuperview];
 633    [self viewDidMoveToSuperview];
 634
 635    if (superview)
 636        [self _setWindow:nil];
 637}
 638
 639- (void)_removeFromSuperview
 640{
 641    if (!_superview)
 642        return;
 643
 644    // Dirty the key view loop, in case the window wants to auto recalculate it
 645    [[self window] _dirtyKeyViewLoop];
 646
 647    [_superview willRemoveSubview:self];
 648
 649    [_superview._subviews removeObjectIdenticalTo:self];
 650
 651#if PLATFORM(DOM)
 652    CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
 653#endif
 654
 655    // If the view is not hidden and one of its ancestors is hidden,
 656    // notify the view that it is now unhidden.
 657    if (!_isHidden && [_superview isHiddenOrHasHiddenAncestor])
 658        [self _notifyViewDidUnhide];
 659
 660    [self _notifyWindowDidResignKey];
 661    [self _notifyViewDidResignFirstResponder];
 662
 663    _superview = nil;
 664}
 665
 666/*!
 667    Replaces the specified child view with another view
 668    @param aSubview the view to replace
 669    @param aView the replacement view
 670*/
 671- (void)replaceSubview:(CPView)aSubview with:(CPView)aView
 672{
 673    if (aSubview._superview !== self || aSubview === aView)
 674        return;
 675
 676    var index = [_subviews indexOfObjectIdenticalTo:aSubview];
 677
 678    [self _insertSubview:aView atIndex:index];
 679
 680    [aSubview removeFromSuperview];
 681}
 682
 683- (void)setSubviews:(CPArray)newSubviews
 684{
 685    if (!newSubviews)
 686        [CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
 687
 688    // Trivial Case 0: Same array somehow
 689    if ([_subviews isEqual:newSubviews])
 690        return;
 691
 692    // Trivial Case 1: No current subviews, simply add all new subviews.
 693    if ([_subviews count] === 0)
 694    {
 695        var index = 0,
 696            count = [newSubviews count];
 697
 698        for (; index < count; ++index)
 699            [self addSubview:newSubviews[index]];
 700
 701        return;
 702    }
 703
 704    // Trivial Case 2: No new subviews, simply remove all current subviews.
 705    if ([newSubviews count] === 0)
 706    {
 707        var count = [_subviews count];
 708
 709        while (count--)
 710            [_subviews[count] removeFromSuperview];
 711
 712        return;
 713    }
 714
 715    // Find out the views that were removed.
 716    var removedSubviews = [CPMutableSet setWithArray:_subviews];
 717
 718    [removedSubviews removeObjectsInArray:newSubviews];
 719    [removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 720
 721    // Find out which views need to be added.
 722    var addedSubviews = [CPMutableSet setWithArray:newSubviews];
 723
 724    [addedSubviews removeObjectsInArray:_subviews];
 725
 726    var addedSubview = nil,
 727        addedSubviewEnumerator = [addedSubviews objectEnumerator];
 728
 729    while ((addedSubview = [addedSubviewEnumerator nextObject]) !== nil)
 730        [self addSubview:addedSubview];
 731
 732    // If the order is fine, no need to reorder.
 733    if ([_subviews isEqual:newSubviews])
 734        return;
 735
 736    _subviews = [newSubviews copy];
 737
 738#if PLATFORM(DOM)
 739    var index = 0,
 740        count = [_subviews count];
 741
 742    for (; index < count; ++index)
 743    {
 744        var subview = _subviews[index];
 745
 746        CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
 747        CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
 748    }
 749#endif
 750}
 751
 752/* @ignore */
 753- (void)_setWindow:(CPWindow)aWindow
 754{
 755    [[self window] _dirtyKeyViewLoop];
 756
 757    // Clear out first responder if we're the first responder and leaving.
 758    if ([_window firstResponder] === self && _window != aWindow)
 759        [_window makeFirstResponder:nil];
 760
 761    // Notify the view and its subviews
 762    [self viewWillMoveToWindow:aWindow];
 763
 764    // Unregister the drag events from the current window and register
 765    // them in the new window.
 766    if (_registeredDraggedTypes)
 767    {
 768        [_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
 769        [aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
 770    }
 771
 772    _window = aWindow;
 773
 774    var count = [_subviews count];
 775
 776    while (count--)
 777        [_subviews[count] _setWindow:aWindow];
 778
 779    if ([_window isKeyWindow])
 780        [self setThemeState:CPThemeStateKeyWindow];
 781    else
 782        [self unsetThemeState:CPThemeStateKeyWindow];
 783
 784    [self viewDidMoveToWindow];
 785
 786    [[self window] _dirtyKeyViewLoop];
 787}
 788
 789/*!
 790    Returns \c YES if the receiver is, or is a descendant of, \c aView.
 791    @param aView the view to test for ancestry
 792*/
 793- (BOOL)isDescendantOf:(CPView)aView
 794{
 795    var view = self;
 796
 797    do
 798    {
 799        if (view == aView)
 800            return YES;
 801    } while(view = [view superview])
 802
 803    return NO;
 804}
 805
 806/*!
 807    Called when the receiver's superview has changed.
 808*/
 809- (void)viewDidMoveToSuperview
 810{
 811//    if (_graphicsContext)
 812        [self setNeedsDisplay:YES];
 813}
 814
 815/*!
 816    Called when the receiver has been moved to a new CPWindow.
 817*/
 818- (void)viewDidMoveToWindow
 819{
 820}
 821
 822/*!
 823    Called when the receiver is about to be moved to a new view.
 824    @param aView the view to which the receiver will be moved
 825*/
 826- (void)viewWillMoveToSuperview:(CPView)aView
 827{
 828    _isSuperviewAClipView = [aView isKindOfClass:[CPClipView class]];
 829
 830    [self _removeObservers];
 831
 832    if (aView)
 833        [self _addObservers];
 834}
 835
 836/*!
 837    Called when the receiver is about to be moved to a new window.
 838    @param aWindow the window to which the receiver will be moved.
 839*/
 840- (void)viewWillMoveToWindow:(CPWindow)aWindow
 841{
 842}
 843
 844/*!
 845    Called when the receiver is about to remove one of its subviews.
 846    @param aView the view that will be removed
 847*/
 848- (void)willRemoveSubview:(CPView)aView
 849{
 850}
 851
 852- (void)_removeObservers
 853{
 854    if (!_isObserving)
 855        return;
 856
 857    var count = [_subviews count];
 858
 859    while (count--)
 860        [_subviews[count] _removeObservers];
 861
 862    _isObserving = NO;
 863}
 864
 865- (void)_addObservers
 866{
 867    if (_isObserving)
 868        return;
 869
 870    var count = [_subviews count];
 871
 872    while (count--)
 873        [_subviews[count] _addObservers];
 874
 875    _isObserving = YES;
 876}
 877
 878/*!
 879    Returns the menu item containing the receiver or one of its ancestor views.
 880    @return a menu item, or \c nil if the view or one of its ancestors wasn't found
 881*/
 882- (CPMenuItem)enclosingMenuItem
 883{
 884    var view = self;
 885
 886    while (view && ![view isKindOfClass:[_CPMenuItemView class]])
 887        view = [view superview];
 888
 889    if (view)
 890        return view._menuItem;
 891
 892    return nil;
 893/*    var view = self,
 894        enclosingMenuItem = _enclosingMenuItem;
 895
 896    while (!enclosingMenuItem && (view = view._enclosingMenuItem))
 897        view = [view superview];
 898
 899    return enclosingMenuItem;*/
 900}
 901
 902- (void)setTag:(CPInteger)aTag
 903{
 904    _tag = aTag;
 905}
 906
 907- (CPInteger)tag
 908{
 909    return _tag;
 910}
 911
 912- (CPView)viewWithTag:(CPInteger)aTag
 913{
 914    if ([self tag] == aTag)
 915        return self;
 916
 917    var index = 0,
 918        count = _subviews.length;
 919
 920    for (; index < count; ++index)
 921    {
 922        var view = [_subviews[index] viewWithTag:aTag];
 923
 924        if (view)
 925            return view;
 926    }
 927
 928    return nil;
 929}
 930
 931/*!
 932    Returns whether the view is flipped.
 933    @return \c YES if the view is flipped. \c NO, otherwise.
 934*/
 935- (BOOL)isFlipped
 936{
 937    return YES;
 938}
 939
 940/*!
 941    Sets the frame size of the receiver to the dimensions and origin of the provided rectangle in the coordinate system
 942    of the superview. The method also posts a CPViewFrameDidChangeNotification to the notification
 943    center if the receiver is configured to do so. If the frame is the same as the current frame, the method simply
 944    returns (and no notification is posted).
 945    @param aFrame the rectangle specifying the new origin and size  of the receiver
 946*/
 947- (void)setFrame:(CGRect)aFrame
 948{
 949    if (CGRectEqualToRect(_frame, aFrame))
 950        return;
 951
 952    _inhibitFrameAndBoundsChangedNotifications = YES;
 953
 954    [self setFrameOrigin:aFrame.origin];
 955    [self setFrameSize:aFrame.size];
 956
 957    _inhibitFrameAndBoundsChangedNotifications = NO;
 958
 959    if (_postsFrameChangedNotifications)
 960        [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
 961
 962    if (_isSuperviewAClipView)
 963        [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
 964}
 965
 966/*!
 967    Returns the receiver's frame.
 968    @return a copy of the receiver's frame
 969*/
 970- (CGRect)frame
 971{
 972    return CGRectMakeCopy(_frame);
 973}
 974
 975- (CGPoint)frameOrigin
 976{
 977    return CGPointMakeCopy(_frame.origin);
 978}
 979
 980- (CGSize)frameSize
 981{
 982    return CGSizeMakeCopy(_frame.size);
 983}
 984
 985/*!
 986    Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system.
 987    The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver
 988    is configured to do so. If the specified origin is the same as the frame's current origin, the method will
 989    simply return (and no notification will be posted).
 990    @param aPoint the new origin point
 991*/
 992- (void)setCenter:(CGPoint)aPoint
 993{
 994    [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)];
 995}
 996
 997/*!
 998    Returns the center of the receiver's frame in the superview's coordinate system.
 999    @return CGPoint the center point of the receiver's frame
1000*/
1001- (CGPoint)center
1002{
1003    return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y);
1004}
1005
1006/*!
1007    Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system.
1008    The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver
1009    is configured to do so. If the specified origin is the same as the frame's current origin, the method will
1010    simply return (and no notification will be posted).
1011    @param aPoint the new origin point
1012*/
1013- (void)setFrameOrigin:(CGPoint)aPoint
1014{
1015    var origin = _frame.origin;
1016
1017    if (!aPoint || CGPointEqualToPoint(origin, aPoint))
1018        return;
1019
1020    origin.x = aPoint.x;
1021    origin.y = aPoint.y;
1022
1023    if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
1024        [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
1025
1026    if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
1027        [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
1028
1029#if PLATFORM(DOM)
1030    var transform = _superview ? _superview._boundsTransform : NULL;
1031
1032    CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
1033#endif
1034}
1035
1036/*!
1037    Sets the receiver's frame size. If \c aSize is the same as the frame's current dimensions, this
1038    method simply returns. The method posts a CPViewFrameDidChangeNotification to the
1039    default notification center if the receiver is configured to do so.
1040    @param aSize the new size for the frame
1041*/
1042- (void)setFrameSize:(CGSize)aSize
1043{
1044    var size = _frame.size;
1045
1046    if (!aSize || CGSizeEqualToSize(size, aSize))
1047        return;
1048
1049    var oldSize = CGSizeMakeCopy(size);
1050
1051    size.width = aSize.width;
1052    size.height = aSize.height;
1053
1054    if (YES)
1055    {
1056        _bounds.size.width = aSize.width * 1 / _scaleSize.width;
1057        _bounds.size.height = aSize.height * 1 / _scaleSize.height;
1058    }
1059
1060    if (_layer)
1061        [_layer _owningViewBoundsChanged];
1062
1063    if (_autoresizesSubviews)
1064        [self resizeSubviewsWithOldSize:oldSize];
1065
1066    [self setNeedsLayout];
1067    [self setNeedsDisplay:YES];
1068
1069#if PLATFORM(DOM)
1070    [self _setDisplayServerSetStyleSize:size];
1071
1072    if (_DOMContentsElement)
1073    {
1074        CPDOMDisplayServerSetSize(_DOMContentsElement, size.width, size.height);
1075        CPDOMDisplayServerSetStyleSize(_DOMContentsElement, size.width, size.height);
1076    }
1077
1078    if (_backgroundType !== BackgroundTrivialColor)
1079    {
1080        if (_backgroundType === BackgroundTransparentColor)
1081        {
1082            CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
1083        }
1084        else
1085        {
1086            var images = [[_backgroundColor patternImage] imageSlices],
1087                partIndex = 0,
1088                frameSize = aSize;
1089
1090            if (_backgroundType === BackgroundVerticalThreePartImage)
1091            {
1092                var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0,
1093                    bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0;
1094
1095                // Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed.
1096                if (top)
1097                {
1098                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", top + "px");
1099                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, top);
1100                    partIndex++;
1101                }
1102                if (_DOMImageSizes[1])
1103                {
1104                    var height = frameSize.height - top - bottom;
1105
1106                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", height + "px");
1107                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, size.height - top - bottom);
1108                    partIndex++;
1109                }
1110                if (bottom)
1111                {
1112                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", bottom + "px");
1113                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, bottom);
1114                }
1115            }
1116            else if (_backgroundType === BackgroundHorizontalThreePartImage)
1117            {
1118                var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
1119                    right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0;
1120
1121                // Make sure to repeat the left and right pieces vertically if they're not the exact height needed.
1122                if (left)
1123                {
1124                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], left + "px", frameSize.height + "px");
1125                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], left, size.height);
1126                    partIndex++;
1127                }
1128                if (_DOMImageSizes[1])
1129                {
1130                    var width = (frameSize.width - left - right);
1131
1132                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], width + "px", frameSize.height + "px");
1133                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width - left - right, size.height);
1134                    partIndex++;
1135                }
1136                if (right)
1137                {
1138                    CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], right + "px", frameSize.height + "px");
1139                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], right, size.height);
1140                }
1141            }
1142            else if (_backgroundType === BackgroundNinePartImage)
1143            {
1144                var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
1145                    right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0,
1146                    top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0,
1147                    bottom = _DOMImageSizes[6] ? _DOMImageSizes[6].height : 0,
1148                    width = size.width - left - right,
1149                    height = size.height - top - bottom;
1150
1151                if (_DOMImageSizes[0])
1152                    partIndex++;
1153                if (_DOMImageSizes[1])
1154                {
1155                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, top);
1156                    partIndex++;
1157                }
1158                if (_DOMImageSizes[2])
1159                    partIndex++;
1160                if (_DOMImageSizes[3])
1161                {
1162                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[3].width, height);
1163                    partIndex++;
1164                }
1165                if (_DOMImageSizes[4])
1166                {
1167                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, height);
1168                    partIndex++;
1169                }
1170                if (_DOMImageSizes[5])
1171                {
1172                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[5].width, height);
1173                    partIndex++;
1174                }
1175                if (_DOMImageSizes[6])
1176                    partIndex++;
1177                if (_DOMImageSizes[7])
1178                {
1179                    CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, _DOMImageSizes[7].height);
1180                }
1181            }
1182        }
1183    }
1184#endif
1185
1186    if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
1187        [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
1188
1189    if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
1190        [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
1191}
1192
1193/*!
1194    This method is used to set the width and height of the _DOMElement. It cares about the scale of the view.
1195    When scaling, for instance with a size (0.5, 0.5), the bounds of the view will be multiply by 2. It's why we multiply by the inverse of the scaling.
1196    The view will finally keep the same proportion for the user on the screen.
1197*/
1198- (void)_setDisplayServerSetStyleSize:(CGSize)aSize
1199{
1200#if PLATFORM(DOM)
1201    var scale = [self scaleSize];
1202    CPDOMDisplayServerSetStyleSize(_DOMElement, aSize.width * 1 / scale.width, aSize.height * 1 / scale.height);
1203#endif
1204}
1205
1206/*!
1207    Sets the receiver's bounds. The bounds define the size and location of the receiver inside it's frame. Posts a
1208    CPViewBoundsDidChangeNotification to the default notification center if the receiver is configured to do so.
1209    @param bounds the new bounds
1210*/
1211- (void)setBounds:(CGRect)bounds
1212{
1213    if (CGRectEqualToRect(_bounds, bounds))
1214        return;
1215
1216    _inhibitFrameAndBoundsChangedNotifications = YES;
1217
1218    [self setBoundsOrigin:bounds.origin];
1219    [self setBoundsSize:bounds.size];
1220
1221    _inhibitFrameAndBoundsChangedNotifications = NO;
1222
1223    if (_postsBoundsChangedNotifications)
1224        [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
1225
1226    if (_isSuperviewAClipView)
1227        [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
1228}
1229
1230/*!
1231    Returns the receiver's bounds. The bounds define the size
1232    and location of the receiver inside its frame.
1233*/
1234- (CGRect)bounds
1235{
1236    return CGRectMakeCopy(_bounds);
1237}
1238
1239- (CGPoint)boundsOrigin
1240{
1241    return CGPointMakeCopy(_bounds.origin);
1242}
1243
1244- (CGSize)boundsSize
1245{
1246    return CGSizeMakeCopy(_bounds.size);
1247}
1248
1249/*!
1250    Sets the location of the receiver inside its frame. The method
1251    posts a CPViewBoundsDidChangeNotification to the
1252    default notification center if the receiver is configured to do so.
1253    @param aPoint the new location for the receiver
1254*/
1255- (void)setBoundsOrigin:(CGPoint)aPoint
1256{
1257    var origin = _bounds.origin;
1258
1259    if (CGPointEqualToPoint(origin, aPoint))
1260        return;
1261
1262    origin.x = aPoint.x;
1263    origin.y = aPoint.y;
1264
1265    if (origin.x != 0 || origin.y != 0)
1266    {
1267        _boundsTransform = CGAffineTransformMakeTranslation(-origin.x, -origin.y);
1268        _inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform);
1269    }
1270    else
1271    {
1272        _boundsTransform = nil;
1273        _inverseBoundsTransform = nil;
1274    }
1275
1276#if PLATFORM(DOM)
1277    var index = _subviews.length;
1278
1279    while (index--)
1280    {
1281        var view = _subviews[index],
1282            origin = view._frame.origin;
1283
1284        CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y);
1285    }
1286#endif
1287
1288    if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
1289        [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
1290
1291    if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
1292        [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
1293}
1294
1295/*!
1296    Sets the receiver's size inside its frame. The method posts a
1297    CPViewBoundsDidChangeNotification to the default
1298    notification center if the receiver is configured to do so.
1299    @param aSize the new size for the receiver
1300*/
1301- (void)setBoundsSize:(CGSize)aSize
1302{
1303    var size = _bounds.size;
1304
1305    if (CGSizeEqualToSize(size, aSize))
1306        return;
1307
1308    var frameSize = _frame.size;
1309
1310    if (!CGSizeEqualToSize(size, frameSize))
1311    {
1312        var origin = _bounds.origin;
1313
1314        origin.x /= size.width / frameSize.width;
1315        origin.y /= size.height / frameSize.height;
1316    }
1317
1318    size.width = aSize.width;
1319    size.height = aSize.height;
1320
1321    if (!CGSizeEqualToSize(size, frameSize))
1322    {
1323        var origin = _bounds.origin;
1324
1325        origin.x *= size.width / frameSize.width;
1326        origin.y *= size.height / frameSize.height;
1327    }
1328
1329    if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
1330        [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
1331
1332    if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
1333        [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
1334}
1335
1336
1337/*!
1338    Notifies subviews that the superview changed size.
1339    @param aSize the size of the old superview
1340*/
1341- (void)resizeWithOldSuperviewSize:(CGSize)aSize
1342{
1343    var mask = [self autoresizingMask];
1344
1345    if (mask == CPViewNotSizable)
1346        return;
1347
1348    var frame = _superview._frame,
1349        newFrame = CGRectMakeCopy(_frame),
1350        dX = frame.size.width - aSize.width,
1351        dY = frame.size.height - aSize.height,
1352        evenFractionX = 1.0 / ((mask & CPViewMinXMargin ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
1353        evenFractionY = 1.0 / ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0)),
1354        baseX = (mask & CPViewMinXMargin    ? _frame.origin.x : 0) +
1355                (mask & CPViewWidthSizable  ? _frame.size.width : 0) +
1356                (mask & CPViewMaxXMargin    ? aSize.width - _frame.size.width - _frame.origin.x : 0),
1357        baseY = (mask & CPViewMinYMargin    ? _frame.origin.y : 0) +
1358                (mask & CPViewHeightSizable ? _frame.size.height : 0) +
1359                (mask & CPViewMaxYMargin    ? aSize.height - _frame.size.height - _frame.origin.y : 0);
1360
1361    if (mask & CPViewMinXMargin)
1362        newFrame.origin.x += dX * (baseX > 0 ? _frame.origin.x / baseX : evenFractionX);
1363
1364    if (mask & CPViewWidthSizable)
1365        newFrame.size.width += dX * (baseX > 0 ? _frame.size.width / baseX : evenFractionX);
1366
1367    if (mask & CPViewMinYMargin)
1368        newFrame.origin.y += dY * (baseY > 0 ? _frame.origin.y / baseY : evenFractionY);
1369
1370    if (mask & CPViewHeightSizable)
1371        newFrame.size.height += dY * (baseY > 0 ? _frame.size.height / baseY : evenFractionY);
1372
1373    [self setFrame:newFrame];
1374}
1375
1376/*!
1377    Initiates \c -superviewSizeChanged: messages to subviews.
1378    @param aSize the size for the subviews
1379*/
1380- (void)resizeSubviewsWithOldSize:(CGSize)aSize
1381{
1382    var count = _subviews.length;
1383
1384    while (count--)
1385        [_subviews[count] resizeWithOldSuperviewSize:aSize];
1386}
1387
1388/*!
1389    Specifies whether the receiver view should automatically resize its
1390    subviews when its \c -setFrameSize: method receives a change.
1391    @param aFlag If \c YES, then subviews will automatically be resized
1392    when this view is resized. \c NO means the views will not
1393    be resized automatically.
1394*/
1395- (void)setAutoresizesSubviews:(BOOL)aFlag
1396{
1397    _autoresizesSubviews = !!aFlag;
1398}
1399
1400/*!
1401    Reports whether the receiver automatically resizes its subviews when its frame size changes.
1402    @return \c YES means it resizes its subviews on a frame size change.
1403*/
1404- (BOOL)autoresizesSubviews
1405{
1406    return _autoresizesSubviews;
1407}
1408
1409/*!
1410    Determines automatic resizing behavior.
1411    @param aMask a bit mask with options
1412*/
1413- (void)setAutoresizingMask:(unsigned)aMask
1414{
1415    _autoresizingMask = aMask;
1416}
1417
1418/*!
1419    Returns the bit mask options for resizing behavior
1420*/
1421- (unsigned)autoresizingMask
1422{
1423    return _autoresizingMask;
1424}
1425
1426// Fullscreen Mode
1427
1428/*!
1429    Puts the receiver into full screen mode.
1430*/
1431- (BOOL)enterFullScreenMode
1432{
1433    return [self enterFullScreenMode:nil withOptions:nil];
1434}
1435
1436/*!
1437    Puts the receiver into full screen mode.
1438    @param aScreen the that should be used
1439    @param options configuration options
1440*/
1441- (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options
1442{
1443    _fullScreenModeState = _CPViewFullScreenModeStateMake(self);
1444
1445    var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask];
1446
1447    [fullScreenWindow setLevel:CPScreenSaverWindowLevel];
1448    [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1449
1450    var contentView = [fullScreenWindow contentView];
1451
1452    [contentView setBackgroundColor:[CPColor blackColor]];
1453    [contentView addSubview:self];
1454
1455    [self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
1456    [self setFrame:CGRectMakeCopy([contentView bounds])];
1457
1458    [fullScreenWindow makeKeyAndOrderFront:self];
1459
1460    [fullScreenWindow makeFirstResponder:self];
1461
1462    _isInFullScreenMode = YES;
1463
1464    return YES;
1465}
1466
1467/*!
1468    The receiver should exit full screen mode.
1469*/
1470- (void)exitFullScreenMode
1471{
1472    [self exitFullScreenModeWithOptions:nil];
1473}
1474
1475/*!
1476    The receiver should exit full screen mode.
1477    @param options configurations options
1478*/
1479- (void)exitFullScreenModeWithOptions:(CPDictionary)options
1480{
1481    if (!_isInFullScreenMode)
1482        return;
1483
1484    _isInFullScreenMode = NO;
1485
1486    [self setFrame:_fullScreenModeState.frame];
1487    [self setAutoresizingMask:_fullScreenModeState.autoresizingMask];
1488    [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index];
1489
1490    [[self window] orderOut:self];
1491}
1492
1493/*!
1494    Returns \c YES if the receiver is currently in full screen mode.
1495*/
1496- (BOOL)isInFullScreenMode
1497{
1498    return _isInFullScreenMode;
1499}
1500
1501/*!
1502    Sets whether the receiver should be hidden.
1503    @param aFlag \c YES makes the receiver hidden.
1504*/
1505- (void)setHidden:(BOOL)aFlag
1506{
1507    aFlag = !!aFlag;
1508
1509    if (_isHidden === aFlag)
1510        return;
1511
1512//  FIXME: Should we return to visibility?  This breaks in FireFox, Opera, and IE.
1513//    _DOMElement.style.visibility = (_isHidden = aFlag) ? "hidden" : "visible";
1514    _isHidden = aFlag;
1515
1516#if PLATFORM(DOM)
1517    _DOMElement.style.display = _isHidden ? "none" : "block";
1518#endif
1519
1520    if (aFlag)
1521    {
1522        var view = [_window firstResponder];
1523
1524        if ([view isKindOfClass:[CPView class]])
1525        {
1526            do
1527            {
1528               if (self == view)
1529               {
1530                  [_window makeFirstResponder:[self nextValidKeyView]];
1531                  break;
1532               }
1533            }
1534            while (view = [view superview]);
1535        }
1536
1537        [self _notifyViewDidHide];
1538    }
1539    else
1540    {
1541        [self setNeedsDisplay:YES];
1542        [self _notifyViewDidUnhide];
1543    }
1544}
1545
1546- (void)_notifyViewDidHide
1547{
1548    [self viewDidHide];
1549
1550    var count = [_subviews count];
1551
1552    while (count--)
1553        [_subviews[count] _notifyViewDidHide];
1554}
1555
1556- (void)_notifyViewDidUnhide
1557{
1558    [self viewDidUnhide];
1559
1560    var count = [_subviews count];
1561
1562    while (count--)
1563        [_subviews[count] _notifyViewDidUnhide];
1564}
1565
1566/*!
1567    Returns \c YES if the receiver is hidden.
1568*/
1569- (BOOL)isHidden
1570{
1571    return _isHidden;
1572}
1573
1574- (void)setClipsToBounds:(BOOL)shouldClip
1575{
1576    if (_clipsToBounds === shouldClip)
1577        return;
1578
1579    _clipsToBounds = shouldClip;
1580
1581#if PLATFORM(DOM)
1582    _DOMElement.style.overflow = _clipsToBounds ? "hidden" :  "visible";
1583#endif
1584}
1585
1586- (BOOL)clipsToBounds
1587{
1588    return _clipsToBounds;
1589}
1590
1591/*!
1592    Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is
1593    completely transparent and 1.0 is completely opaque.
1594    @param anAlphaValue an alpha value ranging from 0.0 to 1.0.
1595*/
1596- (void)setAlphaValue:(float)anAlphaValue
1597{
1598    if (_opacity == anAlphaValue)
1599        return;
1600
1601    _opacity = anAlphaValue;
1602
1603#if PLATFORM(DOM)
1604
1605    if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
1606    {
1607        if (anAlphaValue === 1.0)
1608            try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
1609        else
1610            _DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
1611    }
1612    else
1613        _DOMElement.style.opacity = anAlphaValue;
1614
1615#endif
1616}
1617
1618/*!
1619    Returns the alpha value of the receiver. Ranges from 0.0 to
1620    1.0, where 0.0 is completely transparent and 1.0 is completely opaque.
1621*/
1622- (float)alphaValue
1623{
1624    return _opacity;
1625}
1626
1627/*!
1628    Returns \c YES if the receiver is hidden, or one
1629    of it's ancestor views is hidden. \c NO, otherwise.
1630*/
1631- (BOOL)isHiddenOrHasHiddenAncestor
1632{
1633    var view = self;
1634
1635    while (view && ![view isHidden])
1636        view = [view superview];
1637
1638    return view !== nil;
1639}
1640
1641/*!
1642    Returns YES if the view is not hidden, has no hidden ancestor and doesn't belong to a hidden window.
1643*/
1644- (BOOL)_isVisible
1645{
1646    return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible];
1647}
1648
1649/*!
1650    Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
1651    e.g. when this view becomes hidden due to a setHidden:YES message to
1652    itself or to one of its superviews.
1653
1654    Note: in the current implementation, viewDidHide may be called multiple
1655    times if additional superviews are hidden, even if
1656    isHiddenOrHasHiddenAncestor was already YES.
1657*/
1658- (void)viewDidHide
1659{
1660
1661}
1662
1663/*!
1664    Called when the return value of isHiddenOrHasHiddenAncestor becomes NO,
1665    e.g. when this view stops being hidden due to a setHidden:NO message to
1666    itself or to one of its superviews.
1667
1668    Note: in the current implementation, viewDidUnhide may be called multiple
1669    times if additional superviews are unhidden, even if
1670    isHiddenOrHasHiddenAncestor was already NO.
1671*/
1672- (void)viewDidUnhide
1673{
1674
1675}
1676
1677/*!
1678    Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.<br/>
1679    Returns \c NO by default.
1680    @return \c YES, if the view object accepts first mouse-down event. \c NO, otherwise.
1681*/
1682- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
1683{
1684    return NO;
1685}
1686
1687/*!
1688    Returns whether or not the view responds to hit tests.
1689    @return \c YES if this view listens to \c -hitTest messages, \c NO otherwise.
1690*/
1691- (BOOL)hitTests
1692{
1693    return _hitTests;
1694}
1695
1696/*!
1697    Set whether or not the view should respond to hit tests.
1698    @param shouldHitTest should be \c YES if this view should respond to hit tests, \c NO otherwise.
1699*/
1700- (void)setHitTests:(BOOL)shouldHitTest
1701{
1702    _hitTests = !!shouldHitTest;
1703}
1704
1705/*!
1706    Tests whether a point is contained within this view, or one of its subviews.
1707    @param aPoint the point to test
1708    @return returns the containing view, or nil if the point is not contained
1709*/
1710- (CPView)hitTest:(CGPoint)aPoint
1711{
1712    if (_isHidden || !_hitTests)
1713        return nil;
1714
1715    var frame = _frame,
1716        sizeScale = [self _hierarchyScaleSize];
1717
1718    if (_isScaled)
1719        frame = CGRectApplyAffineTransform(_frame, CGAffineTransformMakeScale([_superview _hierarchyScaleSize].width, [_superview _hierarchyScaleSize].height));
1720    else
1721        frame = CGRectApplyAffineTransform(_frame, CGAffineTransformMakeScale(sizeScale.width, sizeScale.height));
1722
1723    if (!CGRectContainsPoint(frame, aPoint))
1724        return nil;
1725
1726    var view = nil,
1727        i = _subviews.length,
1728        adjustedPoint = CGPointMake(aPoint.x - CGRectGetMinX(frame), aPoint.y - CGRectGetMinY(frame));
1729
1730    if (_inverseBoundsTransform)
1731    {
1732        var affineTransform = CGAffineTransformMakeCopy(_inverseBoundsTransform);
1733
1734        if (_isScaled)
1735        {
1736            affineTransform.tx *= [_superview _hierarchyScaleSize].width;
1737            affineTransform.ty *= [_superview _hierarchyScaleSize].height;
1738        }
1739        else
1740        {
1741            affineTransform.tx *= sizeScale.width;
1742            affineTransform.ty *= sizeScale.height;
1743        }
1744
1745        adjustedPoint = CGPointApplyAffineTransform(adjustedPoint, affineTransform);
1746    }
1747
1748
1749    while (i--)
1750        if (view = [_subviews[i] hitTest:adjustedPoint])
1751            return view;
1752
1753    return self;
1754}
1755
1756/*!
1757    Returns \c YES if this view requires a panel to become key. Normally only text fields, so this returns \c NO.
1758*/
1759- (BOOL)needsPanelToBecomeKey
1760{
1761    return NO;
1762}
1763
1764/*!
1765    Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
1766    default implementation returns \c NO if the view is opaque.
1767*/
1768- (BOOL)mouseDownCanMoveWindow
1769{
1770    return ![self isOpaque];
1771}
1772
1773- (void)mouseDown:(C…

Large files files are truncated, but you can click here to view the full file