/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 are truncated click here to view the full file
- /*
- * CPView.j
- * AppKit
- *
- * Created by Francisco Tolmasky.
- * Copyright 2008, 280 North, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- @import <Foundation/CPArray.j>
- @import <Foundation/CPObjJRuntime.j>
- @import <Foundation/CPSet.j>
- @import "CGAffineTransform.j"
- @import "CGGeometry.j"
- @import "CPColor.j"
- @import "CPGraphicsContext.j"
- @import "CPResponder.j"
- @import "CPTheme.j"
- @import "CPWindow_Constants.j"
- @import "_CPDisplayServer.j"
- @class _CPToolTip
- @class CPWindow
- @class _CPMenuItemView
- @class CPPlatformWindow
- @class CPMenu
- @class CPClipView
- @class CPScrollView
- @class CALayer
- @global appkit_tag_dom_elements
- @typedef _CPViewFullScreenModeState
- #if PLATFORM(DOM)
- if (typeof(appkit_tag_dom_elements) !== "undefined" && appkit_tag_dom_elements)
- {
- AppKitTagDOMElement = function(owner, element)
- {
- element.setAttribute("data-cappuccino-view", [owner className]);
- element.setAttribute("data-cappuccino-uid", [owner UID]);
- }
- }
- else
- {
- AppKitTagDOMElement = function(owner, element)
- {
- // By default, do nothing.
- }
- }
- #endif
- /*
- @global
- @group CPViewAutoresizingMasks
- The default resizingMask, the view will not resize or reposition itself.
- */
- CPViewNotSizable = 0;
- /*
- @global
- @group CPViewAutoresizingMasks
- Allow for flexible space on the left hand side of the view.
- */
- CPViewMinXMargin = 1;
- /*
- @global
- @group CPViewAutoresizingMasks
- The view should grow and shrink horizontally with its parent view.
- */
- CPViewWidthSizable = 2;
- /*
- @global
- @group CPViewAutoresizingMasks
- Allow for flexible space to the right hand side of the view.
- */
- CPViewMaxXMargin = 4;
- /*
- @global
- @group CPViewAutoresizingMasks
- Allow for flexible space above the view.
- */
- CPViewMinYMargin = 8;
- /*
- @global
- @group CPViewAutoresizingMasks
- The view should grow and shrink vertically with its parent view.
- */
- CPViewHeightSizable = 16;
- /*
- @global
- @group CPViewAutoresizingMasks
- Allow for flexible space below the view.
- */
- CPViewMaxYMargin = 32;
- CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification";
- CPViewFrameDidChangeNotification = @"CPViewFrameDidChangeNotification";
- var CachedNotificationCenter = nil,
- CachedThemeAttributes = nil;
- #if PLATFORM(DOM)
- var DOMElementPrototype = nil,
- BackgroundTrivialColor = 0,
- BackgroundVerticalThreePartImage = 1,
- BackgroundHorizontalThreePartImage = 2,
- BackgroundNinePartImage = 3,
- BackgroundTransparentColor = 4;
- #endif
- var CPViewFlags = { },
- CPViewHasCustomDrawRect = 1 << 0,
- CPViewHasCustomLayoutSubviews = 1 << 1;
- /*!
- @ingroup appkit
- @class CPView
- <p>CPView is a class which provides facilities for drawing
- in a window and receiving events. It is the superclass of many of the visual
- elements of the GUI.</p>
- <p>In order to display itself, a view must be placed in a window (represented by an
- CPWindow object). Within the window is a hierarchy of CPViews,
- headed by the window's content view. Every other view in a window is a descendant
- of this view.</p>
- <p>Subclasses can override \c -drawRect: in order to implement their
- appearance. Other methods of CPView and CPResponder can
- also be overridden to handle user generated events.
- */
- @implementation CPView : CPResponder
- {
- CPWindow _window;
- CPView _superview;
- CPArray _subviews;
- CPGraphicsContext _graphicsContext;
- int _tag;
- CPString _identifier @accessors(property=identifier);
- CGRect _frame;
- CGRect _bounds;
- CGAffineTransform _boundsTransform;
- CGAffineTransform _inverseBoundsTransform;
- CPSet _registeredDraggedTypes;
- CPArray _registeredDraggedTypesArray;
- BOOL _isHidden;
- BOOL _hitTests;
- BOOL _clipsToBounds;
- BOOL _postsFrameChangedNotifications;
- BOOL _postsBoundsChangedNotifications;
- BOOL _inhibitFrameAndBoundsChangedNotifications;
- BOOL _inLiveResize;
- BOOL _isSuperviewAClipView;
- #if PLATFORM(DOM)
- DOMElement _DOMElement;
- DOMElement _DOMContentsElement;
- CPArray _DOMImageParts;
- CPArray _DOMImageSizes;
- unsigned _backgroundType;
- #endif
- CGRect _dirtyRect;
- float _opacity;
- CPColor _backgroundColor;
- BOOL _autoresizesSubviews;
- unsigned _autoresizingMask;
- CALayer _layer;
- BOOL _wantsLayer;
- // Full Screen State
- BOOL _isInFullScreenMode;
- _CPViewFullScreenModeState _fullScreenModeState;
- // Zoom Support
- BOOL _isScaled;
- CGSize _hierarchyScaleSize;
- CGSize _scaleSize;
- // Layout Support
- BOOL _needsLayout;
- JSObject _ephemeralSubviews;
- // Theming Support
- CPTheme _theme;
- CPString _themeClass;
- JSObject _themeAttributes;
- unsigned _themeState;
- JSObject _ephemeralSubviewsForNames;
- CPSet _ephereralSubviews;
- // Key View Support
- CPView _nextKeyView;
- CPView _previousKeyView;
- unsigned _viewClassFlags;
- // ToolTips
- CPString _toolTip @accessors(getter=toolTip);
- Function _toolTipFunctionIn;
- Function _toolTipFunctionOut;
- BOOL _toolTipInstalled;
- BOOL _isObserving;
- }
- /*
- Private method for Objective-J.
- @ignore
- */
- + (void)initialize
- {
- if (self !== [CPView class])
- return;
- #if PLATFORM(DOM)
- DOMElementPrototype = document.createElement("div");
- var style = DOMElementPrototype.style;
- style.overflow = "hidden";
- style.position = "absolute";
- style.visibility = "visible";
- style.zIndex = 0;
- #endif
- CachedNotificationCenter = [CPNotificationCenter defaultCenter];
- }
- + (Class)_binderClassForBinding:(CPString)aBinding
- {
- if ([aBinding hasPrefix:CPHiddenBinding])
- return [CPMultipleValueOrBinding class];
- return [super _binderClassForBinding:aBinding];
- }
- - (void)_setupViewFlags
- {
- var theClass = [self class],
- classUID = [theClass UID];
- if (CPViewFlags[classUID] === undefined)
- {
- var flags = 0;
- if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)])
- flags |= CPViewHasCustomDrawRect;
- if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)])
- flags |= CPViewHasCustomLayoutSubviews;
- CPViewFlags[classUID] = flags;
- }
- _viewClassFlags = CPViewFlags[classUID];
- }
- - (void)_setupToolTipHandlers
- {
- _toolTipInstalled = NO;
- _toolTipFunctionIn = function(e) { [_CPToolTip scheduleToolTipForView:self]; }
- _toolTipFunctionOut = function(e) { [_CPToolTip invalidateCurrentToolTipIfNeeded]; };
- }
- + (CPSet)keyPathsForValuesAffectingFrame
- {
- return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
- }
- + (CPSet)keyPathsForValuesAffectingBounds
- {
- return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
- }
- + (CPMenu)defaultMenu
- {
- return nil;
- }
- - (id)init
- {
- return [self initWithFrame:CGRectMakeZero()];
- }
- /*!
- Initializes the receiver for usage with the specified bounding rectangle
- @return the initialized view
- */
- - (id)initWithFrame:(CGRect)aFrame
- {
- self = [super init];
- if (self)
- {
- var width = CGRectGetWidth(aFrame),
- height = CGRectGetHeight(aFrame);
- _subviews = [];
- _registeredDraggedTypes = [CPSet set];
- _registeredDraggedTypesArray = [];
- _tag = -1;
- _frame = CGRectMakeCopy(aFrame);
- _bounds = CGRectMake(0.0, 0.0, width, height);
- _autoresizingMask = CPViewNotSizable;
- _autoresizesSubviews = YES;
- _clipsToBounds = YES;
- _opacity = 1.0;
- _isHidden = NO;
- _hitTests = YES;
- _hierarchyScaleSize = CGSizeMake(1.0 , 1.0);
- _scaleSize = CGSizeMake(1.0, 1.0);
- _isScaled = NO;
- _theme = [CPTheme defaultTheme];
- _themeState = CPThemeStateNormal;
- #if PLATFORM(DOM)
- _DOMElement = DOMElementPrototype.cloneNode(false);
- AppKitTagDOMElement(self, _DOMElement);
- CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, CGRectGetMinX(aFrame), CGRectGetMinY(aFrame));
- CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
- _DOMImageParts = [];
- _DOMImageSizes = [];
- #endif
- [self _setupToolTipHandlers];
- [self _setupViewFlags];
- [self _loadThemeAttributes];
- }
- return self;
- }
- /*!
- Sets the tooltip for the receiver.
- @param aToolTip the tooltip
- */
- - (void)setToolTip:(CPString)aToolTip
- {
- if (_toolTip == aToolTip)
- return;
- if (aToolTip && ![aToolTip isKindOfClass:CPString])
- aToolTip = [aToolTip description];
- _toolTip = aToolTip;
- if (_toolTip)
- [self _installToolTipEventHandlers];
- else
- [self _uninstallToolTipEventHandlers];
- }
- /*! @ignore
- Install the handlers for the tooltip
- */
- - (void)_installToolTipEventHandlers
- {
- if (_toolTipInstalled)
- return;
- #if PLATFORM(DOM)
- if (_DOMElement.addEventListener)
- {
- _DOMElement.addEventListener("mouseover", _toolTipFunctionIn, YES);
- _DOMElement.addEventListener("keypress", _toolTipFunctionOut, YES);
- _DOMElement.addEventListener("mouseout", _toolTipFunctionOut, YES);
- }
- else if (_DOMElement.attachEvent)
- {
- _DOMElement.attachEvent("onmouseover", _toolTipFunctionIn);
- _DOMElement.attachEvent("onkeypress", _toolTipFunctionOut);
- _DOMElement.attachEvent("onmouseout", _toolTipFunctionOut);
- }
- #endif
- _toolTipInstalled = YES;
- }
- /*! @ignore
- Uninstall the handlers for the tooltip
- */
- - (void)_uninstallToolTipEventHandlers
- {
- if (!_toolTipInstalled)
- return;
- #if PLATFORM(DOM)
- if (_DOMElement.removeEventListener)
- {
- _DOMElement.removeEventListener("mouseover", _toolTipFunctionIn, YES);
- _DOMElement.removeEventListener("keypress", _toolTipFunctionOut, YES);
- _DOMElement.removeEventListener("mouseout", _toolTipFunctionOut, YES);
- }
- else if (_DOMElement.detachEvent)
- {
- _DOMElement.detachEvent("onmouseover", _toolTipFunctionIn);
- _DOMElement.detachEvent("onkeypress", _toolTipFunctionOut);
- _DOMElement.detachEvent("onmouseout", _toolTipFunctionOut);
- }
- #endif
- _toolTipInstalled = NO;
- }
- /*!
- Returns the container view of the receiver
- @return the receiver's containing view
- */
- - (CPView)superview
- {
- return _superview;
- }
- /*!
- Returns an array of all the views contained as direct children of the receiver
- @return an array of CPViews
- */
- - (CPArray)subviews
- {
- return [_subviews copy];
- }
- /*!
- Returns the window containing this receiver
- */
- - (CPWindow)window
- {
- return _window;
- }
- /*!
- Makes the argument a subview of the receiver.
- @param aSubview the CPView to make a subview
- */
- - (void)addSubview:(CPView)aSubview
- {
- [self _insertSubview:aSubview atIndex:CPNotFound];
- }
- /*!
- Makes \c aSubview a subview of the receiver. It is positioned relative to \c anotherView
- @param aSubview the view to add as a subview
- @param anOrderingMode specifies \c aSubview's ordering relative to \c anotherView
- @param anotherView \c aSubview will be positioned relative to this argument
- */
- - (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView
- {
- var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound;
- // In other words, if no view, then either all the way at the bottom or all the way at the top.
- if (index === CPNotFound)
- index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0;
- // else, if we have a view, above if above.
- else if (anOrderingMode === CPWindowAbove)
- ++index;
- [self _insertSubview:aSubview atIndex:index];
- }
- /* @ignore */
- - (void)_insertSubview:(CPView)aSubview atIndex:(int)anIndex
- {
- if (aSubview === self)
- [CPException raise:CPInvalidArgumentException reason:"can't add a view as a subview of itself"];
- #if DEBUG
- if (!aSubview._superview && _subviews.indexOf(aSubview) !== CPNotFound)
- [CPException raise:CPInvalidArgumentException reason:"can't insert a subview in duplicate (probably partially decoded)"];
- #endif
- // Notify the subview that it will be moving.
- [aSubview viewWillMoveToSuperview:self];
- // We will have to adjust the z-index of all views starting at this index.
- var count = _subviews.length,
- lastWindow;
- // Dirty the key view loop, in case the window wants to auto recalculate it
- [[self window] _dirtyKeyViewLoop];
- // If this is already one of our subviews, remove it.
- if (aSubview._superview == self)
- {
- var index = [_subviews indexOfObjectIdenticalTo:aSubview];
- // FIXME: should this be anIndex >= count? (last one)
- if (index === anIndex || index === count - 1 && anIndex === count)
- return;
- [_subviews removeObjectAtIndex:index];
- #if PLATFORM(DOM)
- CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement);
- #endif
- if (anIndex > index)
- --anIndex;
- //We've effectively made the subviews array shorter, so represent that.
- --count;
- }
- else
- {
- var superview = aSubview._superview;
- lastWindow = [superview window];
- // Remove the view from its previous superview.
- [aSubview _removeFromSuperview];
- // Set ourselves as the superview.
- aSubview._superview = self;
- }
- if (anIndex === CPNotFound || anIndex >= count)
- {
- _subviews.push(aSubview);
- #if PLATFORM(DOM)
- // Attach the actual node.
- CPDOMDisplayServerAppendChild(_DOMElement, aSubview._DOMElement);
- #endif
- }
- else
- {
- _subviews.splice(anIndex, 0, aSubview);
- #if PLATFORM(DOM)
- // Attach the actual node.
- CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement);
- #endif
- }
- [aSubview setNextResponder:self];
- [aSubview _scaleSizeUnitSquareToSize:[self _hierarchyScaleSize]];
- // If the subview is not hidden and one of its ancestors is hidden,
- // notify the subview that it is now hidden.
- if (![aSubview isHidden] && [self isHiddenOrHasHiddenAncestor])
- [aSubview _notifyViewDidHide];
- [aSubview viewDidMoveToSuperview];
- // Set the subview's window to our own.
- if (_window)
- [aSubview _setWindow:_window];
- if (!_window && lastWindow)
- [aSubview _setWindow:nil];
- // This method might be called before we are fully unarchived, in which case the theme state isn't set up yet
- // and none of the below matters anyhow.
- if (_themeState)
- {
- if ([self hasThemeState:CPThemeStateFirstResponder])
- [aSubview _notifyViewDidBecomeFirstResponder];
- else
- [aSubview _notifyViewDidResignFirstResponder];
- if ([self hasThemeState:CPThemeStateKeyWindow])
- [aSubview _notifyWindowDidBecomeKey];
- else
- [aSubview _notifyWindowDidResignKey];
- }
- [self didAddSubview:aSubview];
- }
- /*!
- Called when the receiver has added \c aSubview to it's child views.
- @param aSubview the view that was added
- */
- - (void)didAddSubview:(CPView)aSubview
- {
- }
- /*!
- Removes the receiver from it's container view and window.
- Does nothing if there's no container view.
- */
- - (void)removeFromSuperview
- {
- var superview = _superview;
- [self viewWillMoveToSuperview:nil];
- [self _removeFromSuperview];
- [self viewDidMoveToSuperview];
- if (superview)
- [self _setWindow:nil];
- }
- - (void)_removeFromSuperview
- {
- if (!_superview)
- return;
- // Dirty the key view loop, in case the window wants to auto recalculate it
- [[self window] _dirtyKeyViewLoop];
- [_superview willRemoveSubview:self];
- [_superview._subviews removeObjectIdenticalTo:self];
- #if PLATFORM(DOM)
- CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
- #endif
- // If the view is not hidden and one of its ancestors is hidden,
- // notify the view that it is now unhidden.
- if (!_isHidden && [_superview isHiddenOrHasHiddenAncestor])
- [self _notifyViewDidUnhide];
- [self _notifyWindowDidResignKey];
- [self _notifyViewDidResignFirstResponder];
- _superview = nil;
- }
- /*!
- Replaces the specified child view with another view
- @param aSubview the view to replace
- @param aView the replacement view
- */
- - (void)replaceSubview:(CPView)aSubview with:(CPView)aView
- {
- if (aSubview._superview !== self || aSubview === aView)
- return;
- var index = [_subviews indexOfObjectIdenticalTo:aSubview];
- [self _insertSubview:aView atIndex:index];
- [aSubview removeFromSuperview];
- }
- - (void)setSubviews:(CPArray)newSubviews
- {
- if (!newSubviews)
- [CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
- // Trivial Case 0: Same array somehow
- if ([_subviews isEqual:newSubviews])
- return;
- // Trivial Case 1: No current subviews, simply add all new subviews.
- if ([_subviews count] === 0)
- {
- var index = 0,
- count = [newSubviews count];
- for (; index < count; ++index)
- [self addSubview:newSubviews[index]];
- return;
- }
- // Trivial Case 2: No new subviews, simply remove all current subviews.
- if ([newSubviews count] === 0)
- {
- var count = [_subviews count];
- while (count--)
- [_subviews[count] removeFromSuperview];
- return;
- }
- // Find out the views that were removed.
- var removedSubviews = [CPMutableSet setWithArray:_subviews];
- [removedSubviews removeObjectsInArray:newSubviews];
- [removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
- // Find out which views need to be added.
- var addedSubviews = [CPMutableSet setWithArray:newSubviews];
- [addedSubviews removeObjectsInArray:_subviews];
- var addedSubview = nil,
- addedSubviewEnumerator = [addedSubviews objectEnumerator];
- while ((addedSubview = [addedSubviewEnumerator nextObject]) !== nil)
- [self addSubview:addedSubview];
- // If the order is fine, no need to reorder.
- if ([_subviews isEqual:newSubviews])
- return;
- _subviews = [newSubviews copy];
- #if PLATFORM(DOM)
- var index = 0,
- count = [_subviews count];
- for (; index < count; ++index)
- {
- var subview = _subviews[index];
- CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
- CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
- }
- #endif
- }
- /* @ignore */
- - (void)_setWindow:(CPWindow)aWindow
- {
- [[self window] _dirtyKeyViewLoop];
- // Clear out first responder if we're the first responder and leaving.
- if ([_window firstResponder] === self && _window != aWindow)
- [_window makeFirstResponder:nil];
- // Notify the view and its subviews
- [self viewWillMoveToWindow:aWindow];
- // Unregister the drag events from the current window and register
- // them in the new window.
- if (_registeredDraggedTypes)
- {
- [_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
- [aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
- }
- _window = aWindow;
- var count = [_subviews count];
- while (count--)
- [_subviews[count] _setWindow:aWindow];
- if ([_window isKeyWindow])
- [self setThemeState:CPThemeStateKeyWindow];
- else
- [self unsetThemeState:CPThemeStateKeyWindow];
- [self viewDidMoveToWindow];
- [[self window] _dirtyKeyViewLoop];
- }
- /*!
- Returns \c YES if the receiver is, or is a descendant of, \c aView.
- @param aView the view to test for ancestry
- */
- - (BOOL)isDescendantOf:(CPView)aView
- {
- var view = self;
- do
- {
- if (view == aView)
- return YES;
- } while(view = [view superview])
- return NO;
- }
- /*!
- Called when the receiver's superview has changed.
- */
- - (void)viewDidMoveToSuperview
- {
- // if (_graphicsContext)
- [self setNeedsDisplay:YES];
- }
- /*!
- Called when the receiver has been moved to a new CPWindow.
- */
- - (void)viewDidMoveToWindow
- {
- }
- /*!
- Called when the receiver is about to be moved to a new view.
- @param aView the view to which the receiver will be moved
- */
- - (void)viewWillMoveToSuperview:(CPView)aView
- {
- _isSuperviewAClipView = [aView isKindOfClass:[CPClipView class]];
- [self _removeObservers];
- if (aView)
- [self _addObservers];
- }
- /*!
- Called when the receiver is about to be moved to a new window.
- @param aWindow the window to which the receiver will be moved.
- */
- - (void)viewWillMoveToWindow:(CPWindow)aWindow
- {
- }
- /*!
- Called when the receiver is about to remove one of its subviews.
- @param aView the view that will be removed
- */
- - (void)willRemoveSubview:(CPView)aView
- {
- }
- - (void)_removeObservers
- {
- if (!_isObserving)
- return;
- var count = [_subviews count];
- while (count--)
- [_subviews[count] _removeObservers];
- _isObserving = NO;
- }
- - (void)_addObservers
- {
- if (_isObserving)
- return;
- var count = [_subviews count];
- while (count--)
- [_subviews[count] _addObservers];
- _isObserving = YES;
- }
- /*!
- Returns the menu item containing the receiver or one of its ancestor views.
- @return a menu item, or \c nil if the view or one of its ancestors wasn't found
- */
- - (CPMenuItem)enclosingMenuItem
- {
- var view = self;
- while (view && ![view isKindOfClass:[_CPMenuItemView class]])
- view = [view superview];
- if (view)
- return view._menuItem;
- return nil;
- /* var view = self,
- enclosingMenuItem = _enclosingMenuItem;
- while (!enclosingMenuItem && (view = view._enclosingMenuItem))
- view = [view superview];
- return enclosingMenuItem;*/
- }
- - (void)setTag:(CPInteger)aTag
- {
- _tag = aTag;
- }
- - (CPInteger)tag
- {
- return _tag;
- }
- - (CPView)viewWithTag:(CPInteger)aTag
- {
- if ([self tag] == aTag)
- return self;
- var index = 0,
- count = _subviews.length;
- for (; index < count; ++index)
- {
- var view = [_subviews[index] viewWithTag:aTag];
- if (view)
- return view;
- }
- return nil;
- }
- /*!
- Returns whether the view is flipped.
- @return \c YES if the view is flipped. \c NO, otherwise.
- */
- - (BOOL)isFlipped
- {
- return YES;
- }
- /*!
- Sets the frame size of the receiver to the dimensions and origin of the provided rectangle in the coordinate system
- of the superview. The method also posts a CPViewFrameDidChangeNotification to the notification
- center if the receiver is configured to do so. If the frame is the same as the current frame, the method simply
- returns (and no notification is posted).
- @param aFrame the rectangle specifying the new origin and size of the receiver
- */
- - (void)setFrame:(CGRect)aFrame
- {
- if (CGRectEqualToRect(_frame, aFrame))
- return;
- _inhibitFrameAndBoundsChangedNotifications = YES;
- [self setFrameOrigin:aFrame.origin];
- [self setFrameSize:aFrame.size];
- _inhibitFrameAndBoundsChangedNotifications = NO;
- if (_postsFrameChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
- if (_isSuperviewAClipView)
- [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
- }
- /*!
- Returns the receiver's frame.
- @return a copy of the receiver's frame
- */
- - (CGRect)frame
- {
- return CGRectMakeCopy(_frame);
- }
- - (CGPoint)frameOrigin
- {
- return CGPointMakeCopy(_frame.origin);
- }
- - (CGSize)frameSize
- {
- return CGSizeMakeCopy(_frame.size);
- }
- /*!
- Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system.
- The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver
- is configured to do so. If the specified origin is the same as the frame's current origin, the method will
- simply return (and no notification will be posted).
- @param aPoint the new origin point
- */
- - (void)setCenter:(CGPoint)aPoint
- {
- [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)];
- }
- /*!
- Returns the center of the receiver's frame in the superview's coordinate system.
- @return CGPoint the center point of the receiver's frame
- */
- - (CGPoint)center
- {
- return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y);
- }
- /*!
- Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system.
- The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver
- is configured to do so. If the specified origin is the same as the frame's current origin, the method will
- simply return (and no notification will be posted).
- @param aPoint the new origin point
- */
- - (void)setFrameOrigin:(CGPoint)aPoint
- {
- var origin = _frame.origin;
- if (!aPoint || CGPointEqualToPoint(origin, aPoint))
- return;
- origin.x = aPoint.x;
- origin.y = aPoint.y;
- if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
- if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
- [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
- #if PLATFORM(DOM)
- var transform = _superview ? _superview._boundsTransform : NULL;
- CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
- #endif
- }
- /*!
- Sets the receiver's frame size. If \c aSize is the same as the frame's current dimensions, this
- method simply returns. The method posts a CPViewFrameDidChangeNotification to the
- default notification center if the receiver is configured to do so.
- @param aSize the new size for the frame
- */
- - (void)setFrameSize:(CGSize)aSize
- {
- var size = _frame.size;
- if (!aSize || CGSizeEqualToSize(size, aSize))
- return;
- var oldSize = CGSizeMakeCopy(size);
- size.width = aSize.width;
- size.height = aSize.height;
- if (YES)
- {
- _bounds.size.width = aSize.width * 1 / _scaleSize.width;
- _bounds.size.height = aSize.height * 1 / _scaleSize.height;
- }
- if (_layer)
- [_layer _owningViewBoundsChanged];
- if (_autoresizesSubviews)
- [self resizeSubviewsWithOldSize:oldSize];
- [self setNeedsLayout];
- [self setNeedsDisplay:YES];
- #if PLATFORM(DOM)
- [self _setDisplayServerSetStyleSize:size];
- if (_DOMContentsElement)
- {
- CPDOMDisplayServerSetSize(_DOMContentsElement, size.width, size.height);
- CPDOMDisplayServerSetStyleSize(_DOMContentsElement, size.width, size.height);
- }
- if (_backgroundType !== BackgroundTrivialColor)
- {
- if (_backgroundType === BackgroundTransparentColor)
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
- }
- else
- {
- var images = [[_backgroundColor patternImage] imageSlices],
- partIndex = 0,
- frameSize = aSize;
- if (_backgroundType === BackgroundVerticalThreePartImage)
- {
- var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0,
- bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0;
- // Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed.
- if (top)
- {
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", top + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, top);
- partIndex++;
- }
- if (_DOMImageSizes[1])
- {
- var height = frameSize.height - top - bottom;
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", height + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, size.height - top - bottom);
- partIndex++;
- }
- if (bottom)
- {
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], frameSize.width + "px", bottom + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, bottom);
- }
- }
- else if (_backgroundType === BackgroundHorizontalThreePartImage)
- {
- var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
- right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0;
- // Make sure to repeat the left and right pieces vertically if they're not the exact height needed.
- if (left)
- {
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], left + "px", frameSize.height + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], left, size.height);
- partIndex++;
- }
- if (_DOMImageSizes[1])
- {
- var width = (frameSize.width - left - right);
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], width + "px", frameSize.height + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width - left - right, size.height);
- partIndex++;
- }
- if (right)
- {
- CPDOMDisplayServerSetStyleBackgroundSize(_DOMImageParts[partIndex], right + "px", frameSize.height + "px");
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], right, size.height);
- }
- }
- else if (_backgroundType === BackgroundNinePartImage)
- {
- var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
- right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0,
- top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0,
- bottom = _DOMImageSizes[6] ? _DOMImageSizes[6].height : 0,
- width = size.width - left - right,
- height = size.height - top - bottom;
- if (_DOMImageSizes[0])
- partIndex++;
- if (_DOMImageSizes[1])
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, top);
- partIndex++;
- }
- if (_DOMImageSizes[2])
- partIndex++;
- if (_DOMImageSizes[3])
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[3].width, height);
- partIndex++;
- }
- if (_DOMImageSizes[4])
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, height);
- partIndex++;
- }
- if (_DOMImageSizes[5])
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[5].width, height);
- partIndex++;
- }
- if (_DOMImageSizes[6])
- partIndex++;
- if (_DOMImageSizes[7])
- {
- CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, _DOMImageSizes[7].height);
- }
- }
- }
- }
- #endif
- if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
- if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
- [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
- }
- /*!
- This method is used to set the width and height of the _DOMElement. It cares about the scale of the view.
- 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.
- The view will finally keep the same proportion for the user on the screen.
- */
- - (void)_setDisplayServerSetStyleSize:(CGSize)aSize
- {
- #if PLATFORM(DOM)
- var scale = [self scaleSize];
- CPDOMDisplayServerSetStyleSize(_DOMElement, aSize.width * 1 / scale.width, aSize.height * 1 / scale.height);
- #endif
- }
- /*!
- Sets the receiver's bounds. The bounds define the size and location of the receiver inside it's frame. Posts a
- CPViewBoundsDidChangeNotification to the default notification center if the receiver is configured to do so.
- @param bounds the new bounds
- */
- - (void)setBounds:(CGRect)bounds
- {
- if (CGRectEqualToRect(_bounds, bounds))
- return;
- _inhibitFrameAndBoundsChangedNotifications = YES;
- [self setBoundsOrigin:bounds.origin];
- [self setBoundsSize:bounds.size];
- _inhibitFrameAndBoundsChangedNotifications = NO;
- if (_postsBoundsChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
- if (_isSuperviewAClipView)
- [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
- }
- /*!
- Returns the receiver's bounds. The bounds define the size
- and location of the receiver inside its frame.
- */
- - (CGRect)bounds
- {
- return CGRectMakeCopy(_bounds);
- }
- - (CGPoint)boundsOrigin
- {
- return CGPointMakeCopy(_bounds.origin);
- }
- - (CGSize)boundsSize
- {
- return CGSizeMakeCopy(_bounds.size);
- }
- /*!
- Sets the location of the receiver inside its frame. The method
- posts a CPViewBoundsDidChangeNotification to the
- default notification center if the receiver is configured to do so.
- @param aPoint the new location for the receiver
- */
- - (void)setBoundsOrigin:(CGPoint)aPoint
- {
- var origin = _bounds.origin;
- if (CGPointEqualToPoint(origin, aPoint))
- return;
- origin.x = aPoint.x;
- origin.y = aPoint.y;
- if (origin.x != 0 || origin.y != 0)
- {
- _boundsTransform = CGAffineTransformMakeTranslation(-origin.x, -origin.y);
- _inverseBoundsTransform = CGAffineTransformInvert(_boundsTransform);
- }
- else
- {
- _boundsTransform = nil;
- _inverseBoundsTransform = nil;
- }
- #if PLATFORM(DOM)
- var index = _subviews.length;
- while (index--)
- {
- var view = _subviews[index],
- origin = view._frame.origin;
- CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y);
- }
- #endif
- if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
- if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
- [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
- }
- /*!
- Sets the receiver's size inside its frame. The method posts a
- CPViewBoundsDidChangeNotification to the default
- notification center if the receiver is configured to do so.
- @param aSize the new size for the receiver
- */
- - (void)setBoundsSize:(CGSize)aSize
- {
- var size = _bounds.size;
- if (CGSizeEqualToSize(size, aSize))
- return;
- var frameSize = _frame.size;
- if (!CGSizeEqualToSize(size, frameSize))
- {
- var origin = _bounds.origin;
- origin.x /= size.width / frameSize.width;
- origin.y /= size.height / frameSize.height;
- }
- size.width = aSize.width;
- size.height = aSize.height;
- if (!CGSizeEqualToSize(size, frameSize))
- {
- var origin = _bounds.origin;
- origin.x *= size.width / frameSize.width;
- origin.y *= size.height / frameSize.height;
- }
- if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
- [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self];
- if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
- [[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
- }
- /*!
- Notifies subviews that the superview changed size.
- @param aSize the size of the old superview
- */
- - (void)resizeWithOldSuperviewSize:(CGSize)aSize
- {
- var mask = [self autoresizingMask];
- if (mask == CPViewNotSizable)
- return;
- var frame = _superview._frame,
- newFrame = CGRectMakeCopy(_frame),
- dX = frame.size.width - aSize.width,
- dY = frame.size.height - aSize.height,
- evenFractionX = 1.0 / ((mask & CPViewMinXMargin ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
- evenFractionY = 1.0 / ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0)),
- baseX = (mask & CPViewMinXMargin ? _frame.origin.x : 0) +
- (mask & CPViewWidthSizable ? _frame.size.width : 0) +
- (mask & CPViewMaxXMargin ? aSize.width - _frame.size.width - _frame.origin.x : 0),
- baseY = (mask & CPViewMinYMargin ? _frame.origin.y : 0) +
- (mask & CPViewHeightSizable ? _frame.size.height : 0) +
- (mask & CPViewMaxYMargin ? aSize.height - _frame.size.height - _frame.origin.y : 0);
- if (mask & CPViewMinXMargin)
- newFrame.origin.x += dX * (baseX > 0 ? _frame.origin.x / baseX : evenFractionX);
- if (mask & CPViewWidthSizable)
- newFrame.size.width += dX * (baseX > 0 ? _frame.size.width / baseX : evenFractionX);
- if (mask & CPViewMinYMargin)
- newFrame.origin.y += dY * (baseY > 0 ? _frame.origin.y / baseY : evenFractionY);
- if (mask & CPViewHeightSizable)
- newFrame.size.height += dY * (baseY > 0 ? _frame.size.height / baseY : evenFractionY);
- [self setFrame:newFrame];
- }
- /*!
- Initiates \c -superviewSizeChanged: messages to subviews.
- @param aSize the size for the subviews
- */
- - (void)resizeSubviewsWithOldSize:(CGSize)aSize
- {
- var count = _subviews.length;
- while (count--)
- [_subviews[count] resizeWithOldSuperviewSize:aSize];
- }
- /*!
- Specifies whether the receiver view should automatically resize its
- subviews when its \c -setFrameSize: method receives a change.
- @param aFlag If \c YES, then subviews will automatically be resized
- when this view is resized. \c NO means the views will not
- be resized automatically.
- */
- - (void)setAutoresizesSubviews:(BOOL)aFlag
- {
- _autoresizesSubviews = !!aFlag;
- }
- /*!
- Reports whether the receiver automatically resizes its subviews when its frame size changes.
- @return \c YES means it resizes its subviews on a frame size change.
- */
- - (BOOL)autoresizesSubviews
- {
- return _autoresizesSubviews;
- }
- /*!
- Determines automatic resizing behavior.
- @param aMask a bit mask with options
- */
- - (void)setAutoresizingMask:(unsigned)aMask
- {
- _autoresizingMask = aMask;
- }
- /*!
- Returns the bit mask options for resizing behavior
- */
- - (unsigned)autoresizingMask
- {
- return _autoresizingMask;
- }
- // Fullscreen Mode
- /*!
- Puts the receiver into full screen mode.
- */
- - (BOOL)enterFullScreenMode
- {
- return [self enterFullScreenMode:nil withOptions:nil];
- }
- /*!
- Puts the receiver into full screen mode.
- @param aScreen the that should be used
- @param options configuration options
- */
- - (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options
- {
- _fullScreenModeState = _CPViewFullScreenModeStateMake(self);
- var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask];
- [fullScreenWindow setLevel:CPScreenSaverWindowLevel];
- [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
- var contentView = [fullScreenWindow contentView];
- [contentView setBackgroundColor:[CPColor blackColor]];
- [contentView addSubview:self];
- [self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
- [self setFrame:CGRectMakeCopy([contentView bounds])];
- [fullScreenWindow makeKeyAndOrderFront:self];
- [fullScreenWindow makeFirstResponder:self];
- _isInFullScreenMode = YES;
- return YES;
- }
- /*!
- The receiver should exit full screen mode.
- */
- - (void)exitFullScreenMode
- {
- [self exitFullScreenModeWithOptions:nil];
- }
- /*!
- The receiver should exit full screen mode.
- @param options configurations options
- */
- - (void)exitFullScreenModeWithOptions:(CPDictionary)options
- {
- if (!_isInFullScreenMode)
- return;
- _isInFullScreenMode = NO;
- [self setFrame:_fullScreenModeState.frame];
- [self setAutoresizingMask:_fullScreenModeState.autoresizingMask];
- [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index];
- [[self window] orderOut:self];
- }
- /*!
- Returns \c YES if the receiver is currently in full screen mode.
- */
- - (BOOL)isInFullScreenMode
- {
- return _isInFullScreenMode;
- }
- /*!
- Sets whether the receiver should be hidden.
- @param aFlag \c YES makes the receiver hidden.
- */
- - (void)setHidden:(BOOL)aFlag
- {
- aFlag = !!aFlag;
- if (_isHidden === aFlag)
- return;
- // FIXME: Should we return to visibility? This breaks in FireFox, Opera, and IE.
- // _DOMElement.style.visibility = (_isHidden = aFlag) ? "hidden" : "visible";
- _isHidden = aFlag;
- #if PLATFORM(DOM)
- _DOMElement.style.display = _isHidden ? "none" : "block";
- #endif
- if (aFlag)
- {
- var view = [_window firstResponder];
- if ([view isKindOfClass:[CPView class]])
- {
- do
- {
- if (self == view)
- {
- [_window makeFirstResponder:[self nextValidKeyView]];
- break;
- }
- }
- while (view = [view superview]);
- }
- [self _notifyViewDidHide];
- }
- else
- {
- [self setNeedsDisplay:YES];
- [self _notifyViewDidUnhide];
- }
- }
- - (void)_notifyViewDidHide
- {
- [self viewDidHide];
- var count = [_subviews count];
- while (count--)
- [_subviews[count] _notifyViewDidHide];
- }
- - (void)_notifyViewDidUnhide
- {
- [self viewDidUnhide];
- var count = [_subviews count];
- while (count--)
- [_subviews[count] _notifyViewDidUnhide];
- }
- /*!
- Returns \c YES if the receiver is hidden.
- */
- - (BOOL)isHidden
- {
- return _isHidden;
- }
- - (void)setClipsToBounds:(BOOL)shouldClip
- {
- if (_clipsToBounds === shouldClip)
- return;
- _clipsToBounds = shouldClip;
- #if PLATFORM(DOM)
- _DOMElement.style.overflow = _clipsToBounds ? "hidden" : "visible";
- #endif
- }
- - (BOOL)clipsToBounds
- {
- return _clipsToBounds;
- }
- /*!
- Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is
- completely transparent and 1.0 is completely opaque.
- @param anAlphaValue an alpha value ranging from 0.0 to 1.0.
- */
- - (void)setAlphaValue:(float)anAlphaValue
- {
- if (_opacity == anAlphaValue)
- return;
- _opacity = anAlphaValue;
- #if PLATFORM(DOM)
- if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
- {
- if (anAlphaValue === 1.0)
- try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
- else
- _DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
- }
- else
- _DOMElement.style.opacity = anAlphaValue;
- #endif
- }
- /*!
- Returns the alpha value of the receiver. Ranges from 0.0 to
- 1.0, where 0.0 is completely transparent and 1.0 is completely opaque.
- */
- - (float)alphaValue
- {
- return _opacity;
- }
- /*!
- Returns \c YES if the receiver is hidden, or one
- of it's ancestor views is hidden. \c NO, otherwise.
- */
- - (BOOL)isHiddenOrHasHiddenAncestor
- {
- var view = self;
- while (view && ![view isHidden])
- view = [view superview];
- return view !== nil;
- }
- /*!
- Returns YES if the view is not hidden, has no hidden ancestor and doesn't belong to a hidden window.
- */
- - (BOOL)_isVisible
- {
- return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible];
- }
- /*!
- Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
- e.g. when this view becomes hidden due to a setHidden:YES message to
- itself or to one of its superviews.
- Note: in the current implementation, viewDidHide may be called multiple
- times if additional superviews are hidden, even if
- isHiddenOrHasHiddenAncestor was already YES.
- */
- - (void)viewDidHide
- {
- }
- /*!
- Called when the return value of isHiddenOrHasHiddenAncestor becomes NO,
- e.g. when this view stops being hidden due to a setHidden:NO message to
- itself or to one of its superviews.
- Note: in the current implementation, viewDidUnhide may be called multiple
- times if additional superviews are unhidden, even if
- isHiddenOrHasHiddenAncestor was already NO.
- */
- - (void)viewDidUnhide
- {
- }
- /*!
- Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.<br/>
- Returns \c NO by default.
- @return \c YES, if the view object accepts first mouse-down event. \c NO, otherwise.
- */
- - (BOOL)acceptsFirstMouse:(CPEvent)anEvent
- {
- return NO;
- }
- /*!
- Returns whether or not the view responds to hit tests.
- @return \c YES if this view listens to \c -hitTest messages, \c NO otherwise.
- */
- - (BOOL)hitTests
- {
- return _hitTests;
- }
- /*!
- Set whether or not the view should respond to hit tests.
- @param shouldHitTest should be \c YES if this view should respond to hit tests, \c NO otherwise.
- */
- - (void)setHitTests:(BOOL)shouldHitTest
- {
- _hitTests = !!shouldHitTest;
- }
- /*!
- Tests whether a point is contained within this view, or one of its subviews.
- @param aPoint the point to test
- @return returns the containing view, or nil if the point is not contained
- */
- - (CPView)hitTest:(CGPoint)aPoint
- {
- if (_isHidden || !_hitTests)
- return nil;
- var frame = _frame,
- sizeScale = [self _hierarchyScaleSize];
- if (_isScaled)
- frame = CGRectApplyAffineTransform(_frame, CGAffineTransformMakeScale([_superview _hierarchyScaleSize].width, [_superview _hierarchyScaleSize].height));
- else
- frame = CGRectApplyAffineTransform(_frame, CGAffineTransformMakeScale(sizeScale.width, sizeScale.height));
- if (!CGRectContainsPoint(frame, aPoint))
- return nil;
- var view = nil,
- i = _subviews.length,
- adjustedPoint = CGPointMake(aPoint.x - CGRectGetMinX(frame), aPoint.y - CGRectGetMinY(frame));
- if (_inverseBoundsTransform)
- {
- var affineTransform = CGAffineTransformMakeCopy(_inverseBoundsTransform);
- if (_isScaled)
- {
- affineTransform.tx *= [_superview _hierarchyScaleSize].width;
- affineTransform.ty *= [_superview _hierarchyScaleSize].height;
- }
- else
- {
- affineTransform.tx *= sizeScale.width;
- affineTransform.ty *= sizeScale.height;
- }
- adjustedPoint = CGPointApplyAffineTransform(adjustedPoint, affineTransform);
- }
- while (i--)
- if (view = [_subviews[i] hitTest:adjustedPoint])
- return view;
- return self;
- }
- /*!
- Returns \c YES if this view requires a panel to become key. Normally only text fields, so this returns \c NO.
- */
- - (BOOL)needsPanelToBecomeKey
- {
- return NO;
- }
- /*!
- Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
- default implementation returns \c NO if the view is opaque.
- */
- - (BOOL)mouseDownCanMoveWindow
- {
- return ![self isOpaque];
- }
- - (void)mouseDown:(C…