diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index c1f8a677e..fae5232eb 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1169,7 +1169,7 @@ CPTexturedBackgroundWindowMask if (_hasShadow && !_shadowView) { - _shadowView = [[_CPShadowWindowView alloc] initWithFrame:CGRectMakeZero()]; + _shadowView = [[_CPShadowWindowView alloc] initWithFrame:CGRectMakeZero()]; [_shadowView setWindowView:_windowView]; [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; @@ -2473,7 +2473,6 @@ CPTexturedBackgroundWindowMask return CPWindowResizeTime; } -/* @ignore */ - (void)_setAttachedSheetFrameOrigin { // Position the sheet above the contentRect. @@ -2487,7 +2486,7 @@ CPTexturedBackgroundWindowMask [attachedSheet setFrame:sheetFrame display:YES animate:NO]; } -/* @ignore +/* Starting point for sheet session, called from CPApplication beginSheet: */ - (void)_attachSheet:(CPWindow)aSheet modalDelegate:(id)aModalDelegate @@ -2503,13 +2502,13 @@ CPTexturedBackgroundWindowMask var sheetFrame = [aSheet frame]; _sheetContext = {"sheet": aSheet, "modalDelegate": aModalDelegate, "endSelector": aDidEndSelector, - "contextInfo": aContextInfo, "frame": _CGRectMakeCopy(sheetFrame), "returnCode": -1, + "contextInfo": aContextInfo, "returnCode": -1, "opened": NO}; [self _attachSheetWindow]; } -/* @ignore +/* Called to animate the sheet in. The timer seems to solve a bug where sheets would be partially animated under certain conditions. */ @@ -2525,7 +2524,7 @@ CPTexturedBackgroundWindowMask repeats:NO]; } -/* @ignore +/* Called to end the sheet. Note that orderOut: is needed to animate the sheet out, as in Cocoa. The sheet isn't completely gone until _cleanupSheetWindow gets called. */ @@ -2546,7 +2545,7 @@ CPTexturedBackgroundWindowMask } } -/* @ignore +/* Called to animate the sheet out. If called while animating in, schedules an animate out at completion */ @@ -2562,26 +2561,24 @@ CPTexturedBackgroundWindowMask repeats:NO]; } -/* @ignore +/* Called to cleanup sheet, when we are definitely done with it */ - (void)_cleanupSheetWindow { var sheet = _sheetContext["sheet"], - lastFrame = _sheetContext["frame"], deferDidEnd = _sheetContext["deferDidEndSelector"]; - [sheet setFrame:lastFrame]; - [self _restoreMasksForView:[sheet contentView]]; - - // if the parent window is modal, the sheet started its own modal session + // If the parent window is modal, the sheet started its own modal session if (sheet._isModal) [CPApp stopModal]; - // restore the state of window before it was sheetified + [self _removeClipForSheet:sheet]; + + // Restore the state of window before it was sheetified [sheet._windowView _enableSheet:NO]; - // close it + // Close it sheet._isSheet = NO; [sheet orderOut:self]; @@ -2594,7 +2591,7 @@ CPTexturedBackgroundWindowMask returnCode = _sheetContext["returnCode"], contextInfo = _sheetContext["contextInfo"]; - // context must be destroyed, since didEnd might want to attach another sheet + // Context must be destroyed, since didEnd might want to attach another sheet _sheetContext = nil; sheet._parentView = nil; @@ -2622,31 +2619,20 @@ CPTexturedBackgroundWindowMask repeats:NO]; } -/* @ignore */ - (void)_sheetShouldAnimateIn:(CPTimer)timer { - // can't open sheet while opening or closing animation is going on + // Can't open sheet while opening or closing animation is going on if (_sheetContext["isOpening"] || _sheetContext["isClosing"]) return; - var sheet = _sheetContext["sheet"], - sheetFrame = [sheet frame], - frame = [self frame]; - - [self _setUpMasksForView:[sheet contentView]]; - + var sheet = _sheetContext["sheet"]; sheet._isSheet = YES; sheet._parentView = self; - var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2), - originy = frame.origin.y + [_contentView frame].origin.y, - startFrame = _CGRectMake(originx, originy, sheetFrame.size.width, 0), - endFrame = _CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height); - [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; - // if sheet is attached to a modal window, the sheet runs + // If sheet is attached to a modal window, the sheet runs // as if itself and the parent window are modal sheet._isModal = NO; @@ -2656,7 +2642,17 @@ CPTexturedBackgroundWindowMask sheet._isModal = YES; } + // The sheet starts hidden just above the top of a clip rect + var sheetFrame = [sheet frame], + sheetShadowFrame = sheet._hasShadow ? [sheet._shadowView frame] : sheetFrame, + frame = [self frame], + originX = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2), + startFrame = _CGRectMake(originX, -sheetShadowFrame.size.height, sheetFrame.size.width, sheetFrame.size.height), + endFrame = _CGRectMake(originX, 0, sheetFrame.size.width, sheetFrame.size.height); + [sheet orderFront:self]; + + [self _clipSheet:sheet]; [sheet setFrame:startFrame display:YES animate:NO]; _sheetContext["opened"] = YES; @@ -2671,16 +2667,11 @@ CPTexturedBackgroundWindowMask [sheet makeKeyWindow]; } -/* @ignore */ - (void)_sheetShouldAnimateOut:(CPTimer)timer { - var sheet = _sheetContext["sheet"], - startFrame = [sheet frame], - endFrame = _CGRectMakeCopy(startFrame); - if (_sheetContext["isOpening"]) { - // allow sheet to be closed while opening, it will close when animate in completes + // Allow sheet to be closed while opening, it will close when animate in completes _sheetContext["shouldClose"] = YES; return; } @@ -2689,14 +2680,20 @@ CPTexturedBackgroundWindowMask return; _sheetContext["opened"] = NO; - _sheetContext["frame"] = startFrame; _sheetContext["isClosing"] = YES; - // the parent window can be orderedOut to disable the sheet animate out, as in Cocoa + // The parent window can be orderedOut to disable the sheet animate out, as in Cocoa if ([self isVisible]) { - endFrame.size.height = 0; - [self _setUpMasksForView:[sheet contentView]]; + var sheet = _sheetContext["sheet"], + sheetFrame = [sheet frame], + fullHeight = sheet._hasShadow ? [sheet._shadowView frame].size.height : sheetFrame.size.height, + endFrame = _CGRectMakeCopy(sheetFrame); + + [sheet setFrameOrigin:_CGPointMake(sheetFrame.origin.x, 0)]; + [self _clipSheet:sheet]; + + endFrame.origin.y = -fullHeight; [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn]; } else @@ -2705,7 +2702,6 @@ CPTexturedBackgroundWindowMask } } -/* @ignore */ - (void)_sheetAnimationDidEnd:(CPTimer)timer { var sheet = _sheetContext["sheet"]; @@ -2715,12 +2711,11 @@ CPTexturedBackgroundWindowMask if (_sheetContext["opened"] === YES) { - // sheet is open and completely visible - [self _restoreMasksForView:[sheet contentView]]; - // we wanted to close the sheet while it animated in, do that now if (_sheetContext["shouldClose"] === YES) [self _detachSheetWindow]; + else + [self _removeClipForSheet:sheet]; } else { @@ -2729,36 +2724,17 @@ CPTexturedBackgroundWindowMask } } -- (void)_setUpMasksForView:(CPView)aView +- (void)_clipSheet:(CPWindow)aSheet { - var views = [aView subviews]; + var clipRect = [_platformWindow contentBounds]; + clipRect.origin.y = [self frame].origin.y + [[self contentView] frame].origin.y; - [views addObject:aView]; - - for (var i = 0, count = [views count]; i < count; i++) - { - var view = [views objectAtIndex:i], - mask = [view autoresizingMask], - maskToAdd = (mask & CPViewMinYMargin) ? 128 : CPViewMinYMargin; - - [view setAutoresizingMask:(mask | maskToAdd)]; - } + [[_platformWindow layerAtLevel:_level create:NO] clipWindow:aSheet toRect:clipRect]; } -- (void)_restoreMasksForView:(CPView)aView +- (void)_removeClipForSheet:(CPWindow)aSheet { - var views = [aView subviews]; - - [views addObject:aView]; - - for (var i = 0, count = [views count]; i < count; i++) - { - var view = [views objectAtIndex:i], - mask = [view autoresizingMask], - maskToRemove = (mask & 128) ? 128 : CPViewMinYMargin; - - [view setAutoresizingMask:(mask & (~ maskToRemove))]; - } + [[_platformWindow layerAtLevel:_level create:NO] removeClipForWindow:aSheet]; } /*! diff --git a/AppKit/Platform/DOM/CPDOMWindowLayer.j b/AppKit/Platform/DOM/CPDOMWindowLayer.j index 926074a3d..4336d60c8 100644 --- a/AppKit/Platform/DOM/CPDOMWindowLayer.j +++ b/AppKit/Platform/DOM/CPDOMWindowLayer.j @@ -130,4 +130,67 @@ 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