mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-05 02:13:40 +00:00
Previously sheet animation was performed by sizing the sheet from zero to full height when animating in, and then back to zero height when animating out. This caused problems with the resize algorithms, which are not designed to deal with sizing from zero. Analyzing Cocoa behavior revealed that sheets slide in and out with no resizing. With this commit, a general purpose mechanism for clipping a window to a rect was added to CPDOMWindowLayer. Clipping was put in CPDOMWindowLayer because that is the class that deals with windows at the global level. CPWindow uses the clipping mechanism to slide the sheet in and out, thus avoiding all resizing problems. Fixes #1840
197 lines
5.6 KiB
Plaintext
197 lines
5.6 KiB
Plaintext
/*
|
|
* CPDOMWindowLayer.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/CPObject.j>
|
|
|
|
|
|
@implementation CPDOMWindowLayer : CPObject
|
|
{
|
|
int _level;
|
|
CPArray _windows;
|
|
DOMElement _DOMElement;
|
|
}
|
|
|
|
- (id)initWithLevel:(int)aLevel
|
|
{
|
|
self = [super init];
|
|
|
|
if (self)
|
|
{
|
|
_level = aLevel;
|
|
|
|
_windows = [];
|
|
|
|
_DOMElement = document.createElement("div");
|
|
_DOMElement.style.position = "absolute";
|
|
_DOMElement.style.top = "0px";
|
|
_DOMElement.style.left = "0px";
|
|
_DOMElement.style.width = "1px";
|
|
_DOMElement.style.height = "1px";
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (int)level
|
|
{
|
|
return _level;
|
|
}
|
|
|
|
- (void)removeWindow:(CPWindow)aWindow
|
|
{
|
|
if (!aWindow._isVisible)
|
|
return;
|
|
|
|
var index = aWindow._index,
|
|
count = _windows.length - 1;
|
|
|
|
CPDOMDisplayServerRemoveChild(_DOMElement, aWindow._DOMElement);
|
|
|
|
[_windows removeObjectAtIndex:aWindow._index];
|
|
|
|
for (; index < count; ++index)
|
|
{
|
|
_windows[index]._index = index;
|
|
_windows[index]._DOMElement.style.zIndex = index;
|
|
}
|
|
|
|
aWindow._isVisible = NO;
|
|
}
|
|
|
|
- (void)insertWindow:(CPWindow)aWindow atIndex:(unsigned)anIndex
|
|
{
|
|
// We will have to adjust the z-index of all windows starting at this index.
|
|
var count = [_windows count],
|
|
zIndex = (anIndex === CPNotFound ? count : anIndex),
|
|
isVisible = aWindow._isVisible;
|
|
|
|
// If the window is already a resident of this layer, remove it.
|
|
if (isVisible)
|
|
{
|
|
// Adjust the z-index to start at the window being inserted
|
|
zIndex = MIN(zIndex, aWindow._index);
|
|
|
|
// If the window being inserted is below the insertion index,
|
|
// the index will be one less after we remove the window below.
|
|
if (aWindow._index < anIndex)
|
|
--anIndex;
|
|
|
|
[_windows removeObjectAtIndex:aWindow._index];
|
|
}
|
|
else
|
|
++count;
|
|
|
|
if (anIndex === CPNotFound || anIndex >= count)
|
|
[_windows addObject:aWindow];
|
|
else
|
|
[_windows insertObject:aWindow atIndex:anIndex];
|
|
|
|
// Adjust all the affected z-indexes.
|
|
for (; zIndex < count; ++zIndex)
|
|
{
|
|
_windows[zIndex]._index = zIndex;
|
|
_windows[zIndex]._DOMElement.style.zIndex = zIndex;
|
|
}
|
|
|
|
// If the window is not already a resident of this layer, add it.
|
|
if (aWindow._DOMElement.parentNode !== _DOMElement)
|
|
{
|
|
CPDOMDisplayServerAppendChild(_DOMElement, aWindow._DOMElement);
|
|
|
|
aWindow._isVisible = YES;
|
|
|
|
if ([aWindow isFullPlatformWindow])
|
|
[aWindow setFrame:[aWindow._platformWindow usableContentFrame]];
|
|
}
|
|
}
|
|
|
|
- (CPArray)orderedWindows
|
|
{
|
|
return _windows;
|
|
}
|
|
|
|
/*!
|
|
Places \c aWindow within an element that clips it to the global rect \c clipRect.
|
|
|
|
NOTE: This is only meant for temporary usage during animation and should be balanced
|
|
with a call to removeClipForWindow:. No attempt is made to make the clipping element follow
|
|
changes to the window.
|
|
*/
|
|
- (void)clipWindow:(CPWindow)aWindow toRect:(CGRect)clipRect
|
|
{
|
|
// First check to see if the window is already clipped.
|
|
// If so, just update its rect.
|
|
var windowElement = aWindow._DOMElement,
|
|
clip = windowElement.parentNode,
|
|
style = clip.style,
|
|
isClipped = style.className === "cpwindowclip";
|
|
|
|
if (!isClipped)
|
|
{
|
|
clip = document.createElement("div");
|
|
|
|
style = clip.style;
|
|
style.className = "cpwindowclip";
|
|
style.position = "absolute";
|
|
style.overflow = "hidden";
|
|
}
|
|
|
|
style.left = clipRect.origin.x + "px";
|
|
style.top = clipRect.origin.y + "px";
|
|
style.width = clipRect.size.width + "px";
|
|
style.height = clipRect.size.height + "px";
|
|
|
|
if (!isClipped)
|
|
{
|
|
// Replace the window with the clip element, then put it inside the clip
|
|
var parent = windowElement.parentNode;
|
|
CPDOMDisplayServerInsertBefore(parent, clip, windowElement);
|
|
CPDOMDisplayServerRemoveChild(parent, windowElement);
|
|
CPDOMDisplayServerAppendChild(clip, windowElement);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Unclips a window that was previously clipped with clipWindow:toWindow:.
|
|
If the window was not clipped, a warning is logged.
|
|
*/
|
|
- (void)removeClipForWindow:(CPWindow)aWindow
|
|
{
|
|
var windowElement = aWindow._DOMElement,
|
|
clip = windowElement.parentNode;
|
|
|
|
if (clip.style.className === "cpwindowclip")
|
|
{
|
|
var parent = clip.parentNode;
|
|
|
|
CPDOMDisplayServerRemoveChild(clip, windowElement);
|
|
[aWindow setFrameOrigin:_CGPointMake([aWindow frame].origin.x, clip.offsetTop)];
|
|
CPDOMDisplayServerInsertBefore(parent, windowElement, clip);
|
|
CPDOMDisplayServerRemoveChild(parent, clip);
|
|
}
|
|
else
|
|
CPLog.warn("%s %s was not previously clipped via clipWindow:toWindow:", _cmd, [aWindow description]);
|
|
}
|
|
|
|
@end
|