/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

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