Files
cappuccino/AppKit/CPWindow/_CPWindowView.j
T

972 lines
31 KiB
Plaintext

/*
* _CPWindowView.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 "CPImageView.j"
@import "CPView.j"
@import "CPWindow_Constants.j"
@class CPCursor
@class CPMenu
@class CPPlatformWindow
@global CPApp
var _CPWindowViewCornerResizeRectWidth = 10,
_CPWindowViewMinContentHeight = 2,
_CPWindowViewResizeRegionNone = -1,
_CPWindowViewResizeRegionTopLeft = 0,
_CPWindowViewResizeRegionTop = 1,
_CPWindowViewResizeRegionTopRight = 2,
_CPWindowViewResizeRegionRight = 3,
_CPWindowViewResizeRegionBottomRight = 4,
_CPWindowViewResizeRegionBottom = 5,
_CPWindowViewResizeRegionBottomLeft = 6,
_CPWindowViewResizeRegionLeft = 7;
_CPWindowViewResizeSlop = 3;
@implementation _CPWindowView : CPView
{
unsigned _styleMask;
CPImageView _resizeIndicator;
CGSize _resizeIndicatorOffset;
CPView _toolbarView;
CGSize _toolbarOffset;
// BOOL _isAnimatingToolbar;
CGRect _cachedFrame;
int _resizeRegion;
CGPoint _mouseDraggedPoint;
CGRect _cachedScreenFrame;
CPView _sheetShadowView;
}
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
return CGRectMakeCopy(aFrameRect);
}
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
return CGRectMakeCopy(aContentRect);
}
+ (CPString)defaultThemeClass
{
return "window";
}
+ (CPDictionary)themeAttributes
{
return @{
@"title-bar-height": 25,
@"shadow-inset": CGInsetMakeZero(),
@"shadow-distance": 5,
@"window-shadow-color": [CPColor clearColor],
@"size-indicator": CGSizeMakeZero(),
@"resize-indicator": [CPNull null],
@"attached-sheet-shadow-color": [CPColor blackColor],
@"shadow-height": 8,
@"close-image-origin": [CPNull null],
@"close-image-size": [CPNull null],
@"close-image": [CPNull null],
@"close-active-image": [CPNull null],
@"bezel-color": [CPNull null],
@"title-text-color": [CPColor blackColor],
@"title-font": [CPFont systemFontOfSize:CPFontCurrentSystemSize],
@"title-text-shadow-color": [CPNull null],
@"title-text-shadow-offset": CGSizeMakeZero(),
@"title-alignment": CPCenterTextAlignment,
@"title-line-break-mode": CPLineBreakByTruncatingTail,
@"title-vertical-alignment": CPTopVerticalTextAlignment,
};
}
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
var contentRect = [[self class] contentRectForFrameRect:aFrameRect],
theToolbar = [[self window] toolbar];
if ([theToolbar isVisible])
{
var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
contentRect.origin.y += toolbarHeight;
contentRect.size.height -= toolbarHeight;
}
return contentRect;
}
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
var frameRect = [[self class] frameRectForContentRect:aContentRect],
theToolbar = [[self window] toolbar];
if ([theToolbar isVisible])
{
var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
frameRect.origin.y -= toolbarHeight;
frameRect.size.height += toolbarHeight;
}
return frameRect;
}
- (id)initWithFrame:(CGRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame];
if (self)
{
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMakeZero();
_toolbarOffset = CGSizeMakeZero();
}
return self;
}
- (void)setDocumentEdited:(BOOL)isEdited
{
}
- (void)setTitle:(CPString)aTitle
{
}
- (CPView)hitTest:(CGPoint)locationInWindow
{
var region = [self resizeRegionForPoint:[_window convertBaseToGlobal:locationInWindow]];
if (region !== _CPWindowViewResizeRegionNone)
return self;
else
return [super hitTest:locationInWindow];
}
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
{
return YES;
}
- (void)mouseDown:(CPEvent)anEvent
{
var theWindow = [self window],
couldResize = _styleMask & CPResizableWindowMask && ![theWindow isFullPlatformWindow];
couldResize = couldResize && (
(CPWindowResizeStyle === CPWindowResizeStyleModern) ||
((CPWindowResizeStyle === CPWindowResizeStyleLegacy) && _resizeIndicator));
if (couldResize)
{
var theWindow = [self window],
windowFrame = [theWindow frame],
shouldResize = NO;
if (CPWindowResizeStyle === CPWindowResizeStyleModern)
{
var globalPoint = [theWindow convertBaseToGlobal:[anEvent locationInWindow]];
_resizeRegion = [self resizeRegionForPoint:globalPoint];
shouldResize = _resizeRegion !== _CPWindowViewResizeRegionNone;
}
else
{
// Extend the resize frame to the edge of the window frame
var resizeFrame = [_resizeIndicator frame];
resizeFrame.size.width = CGRectGetWidth(windowFrame) - CGRectGetMinX(resizeFrame);
resizeFrame.size.height = CGRectGetHeight(windowFrame) - CGRectGetMinY(resizeFrame);
var localPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
shouldResize = CGRectContainsPoint(resizeFrame, localPoint);
// When in legacy mode, the only possible resize region is lower right
_resizeRegion = shouldResize ? _CPWindowViewResizeRegionBottomRight : _CPWindowViewResizeRegionNone;
}
if (shouldResize)
return [self trackResizeWithEvent:anEvent];
}
if ([self couldBeMoveEvent:anEvent])
[self trackMoveWithEvent:anEvent];
else
[super mouseDown:anEvent];
}
- (BOOL)couldBeMoveEvent:(CPEvent)anEvent
{
var theWindow = [self window];
return [theWindow isMovable] && [theWindow isMovableByWindowBackground];
}
/*
aPoint should be in global coordinates
*/
- (int)resizeRegionForPoint:(CGPoint)aPoint
{
/*
If the window is fixed width (minSize.width === maxSize.width), there
are 2 possible resize rects: top and bottom.
If the window is fixed height (minSize.height === maxSize.height), there
are 2 possible resize rects: left and right.
Otherwise there are 8 possible resize rects, 1 for each side and 1 for each corner.
The four corner rects are the same size, and the top/bottom and left/right
rects are the same size. So to save calculations, we can just create
3 rects and move them around to do hit testing. Start with the corners
and then do left/right and top/bottom.
NOTE: If the window is a sheet, the top is never eligible for resizing.
*/
var wind = [self window],
frame = [wind frame],
rect,
minSize = [wind minSize],
maxSize = [wind maxSize],
isFixedWidth = minSize.width === maxSize.width,
isFixedHeight = minSize.height === maxSize.height,
isSheet = wind._isSheet;
if (isFixedWidth)
{
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
frame.origin.y - _CPWindowViewResizeSlop,
frame.size.width + (_CPWindowViewResizeSlop * 2),
_CPWindowViewResizeSlop * 2);
if (CGRectContainsPoint(rect, aPoint))
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTop;
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionBottom;
}
else if (isFixedHeight)
{
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
frame.origin.y - _CPWindowViewResizeSlop,
_CPWindowViewResizeSlop * 2,
frame.size.height + (_CPWindowViewResizeSlop * 2));
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionLeft;
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionRight;
}
else
{
rect = CGRectMake(frame.origin.x - _CPWindowViewResizeSlop,
frame.origin.y - _CPWindowViewResizeSlop,
_CPWindowViewCornerResizeRectWidth + _CPWindowViewResizeSlop,
_CPWindowViewCornerResizeRectWidth + _CPWindowViewResizeSlop);
if (CGRectContainsPoint(rect, aPoint))
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTopLeft;
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewCornerResizeRectWidth;
if (CGRectContainsPoint(rect, aPoint))
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTopRight;
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewCornerResizeRectWidth;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionBottomRight;
rect.origin.x = frame.origin.x - _CPWindowViewResizeSlop;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionBottomLeft;
rect = CGRectMake(rect.origin.x,
frame.origin.y + _CPWindowViewCornerResizeRectWidth,
_CPWindowViewResizeSlop * 2,
CGRectGetHeight(frame) - (_CPWindowViewCornerResizeRectWidth * 2));
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionLeft;
rect.origin.x = CGRectGetMaxX(frame) - _CPWindowViewResizeSlop;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionRight;
rect = CGRectMake(frame.origin.x + _CPWindowViewCornerResizeRectWidth,
frame.origin.y - _CPWindowViewResizeSlop,
CGRectGetWidth(frame) - (_CPWindowViewCornerResizeRectWidth * 2),
_CPWindowViewResizeSlop * 2);
if (CGRectContainsPoint(rect, aPoint))
return isSheet ? _CPWindowViewResizeRegionNone : _CPWindowViewResizeRegionTop;
rect.origin.y = CGRectGetMaxY(frame) - _CPWindowViewResizeSlop;
if (CGRectContainsPoint(rect, aPoint))
return _CPWindowViewResizeRegionBottom;
}
return _CPWindowViewResizeRegionNone;
}
/*
aPoint is in window coordinates
*/
- (void)setCursorForLocation:(CGPoint)aPoint resizing:(BOOL)isResizing
{
var theWindow = [self window];
if ([theWindow isFullPlatformWindow] ||
!(_styleMask & CPResizableWindowMask) ||
(CPWindowResizeStyle !== CPWindowResizeStyleModern))
return;
var globalPoint = [theWindow convertBaseToGlobal:aPoint],
resizeRegion = isResizing ? _resizeRegion : [self resizeRegionForPoint:globalPoint],
minSize = nil,
maxSize = nil,
frameSize;
if (resizeRegion !== _CPWindowViewResizeRegionNone)
{
minSize = [theWindow minSize];
maxSize = [theWindow maxSize];
frameSize = [theWindow frame].size;
}
switch (resizeRegion)
{
case _CPWindowViewResizeRegionTopLeft:
if (minSize && CGSizeEqualToSize(frameSize, minSize))
[[CPCursor resizeNorthwestCursor] set];
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
[[CPCursor resizeSoutheastCursor] set];
else
[[CPCursor resizeNorthwestSoutheastCursor] set];
break;
case _CPWindowViewResizeRegionTop:
if (minSize && (frameSize.height === minSize.height))
[[CPCursor resizeUpCursor] set];
else if (maxSize && (frameSize.height === maxSize.height))
[[CPCursor resizeDownCursor] set];
else if ([CPMenu menuBarVisible] && (CGRectGetMinY([theWindow frame]) <= [CPMenu menuBarHeight]))
[[CPCursor resizeDownCursor] set];
else
[[CPCursor resizeNorthSouthCursor] set];
break;
case _CPWindowViewResizeRegionTopRight:
if (minSize && CGSizeEqualToSize(frameSize, minSize))
[[CPCursor resizeNortheastCursor] set];
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
[[CPCursor resizeSouthwestCursor] set];
else
[[CPCursor resizeNortheastSouthwestCursor] set];
break;
case _CPWindowViewResizeRegionRight:
if (minSize && (frameSize.width === minSize.width))
[[CPCursor resizeRightCursor] set];
else if (maxSize && (frameSize.width === maxSize.width))
[[CPCursor resizeLeftCursor] set];
else
[[CPCursor resizeEastWestCursor] set];
break;
case _CPWindowViewResizeRegionBottomRight:
if (minSize && CGSizeEqualToSize(frameSize, minSize))
[[CPCursor resizeSoutheastCursor] set];
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
[[CPCursor resizeNorthwestCursor] set];
else
[[CPCursor resizeNorthwestSoutheastCursor] set];
break;
case _CPWindowViewResizeRegionBottom:
if (minSize && (frameSize.height === minSize.height))
[[CPCursor resizeDownCursor] set];
else if (maxSize && (frameSize.height === maxSize.height))
[[CPCursor resizeUpCursor] set];
else
[[CPCursor resizeNorthSouthCursor] set];
break;
case _CPWindowViewResizeRegionBottomLeft:
if (minSize && CGSizeEqualToSize(frameSize, minSize))
[[CPCursor resizeSouthwestCursor] set];
else if (maxSize && CGSizeEqualToSize(frameSize, maxSize))
[[CPCursor resizeNortheastCursor] set];
else
[[CPCursor resizeNortheastSouthwestCursor] set];
break;
case _CPWindowViewResizeRegionLeft:
if (minSize && (frameSize.width === minSize.width))
[[CPCursor resizeLeftCursor] set];
else if (maxSize && (frameSize.width === maxSize.width))
[[CPCursor resizeRightCursor] set];
else
[[CPCursor resizeEastWestCursor] set];
break;
default:
[[CPCursor arrowCursor] set];
}
}
- (void)trackResizeWithEvent:(CPEvent)anEvent
{
var type = [anEvent type];
if (type === CPLeftMouseUp)
{
_cachedScreenFrame = nil;
return;
}
var location = [anEvent locationInWindow],
theWindow = [self window],
globalLocation = [theWindow convertBaseToGlobal:location],
frame = [theWindow frame];
if (type === CPLeftMouseDown)
{
_mouseDraggedPoint = CGPointMake(globalLocation.x, globalLocation.y);
_cachedFrame = CGRectMakeCopy(frame);
_cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
}
else if (type === CPLeftMouseDragged)
{
var deltaX = globalLocation.x - _mouseDraggedPoint.x,
deltaY = globalLocation.y - _mouseDraggedPoint.y,
startX = CGRectGetMinX(_cachedFrame),
startY = CGRectGetMinY(_cachedFrame),
startWidth = CGRectGetWidth(_cachedFrame),
startHeight = CGRectGetHeight(_cachedFrame),
newX,
newY,
newWidth,
newHeight,
resizeMinSize = [self _minimumResizeSize],
minSize = [theWindow minSize],
maxSize = [theWindow maxSize];
minSize = CGSizeMake(MAX(minSize.width, resizeMinSize.width), MAX(minSize.height, resizeMinSize.height));
// If it's a sheet, horizontal resizing is symmetrical, so the movement is effectively doubled
if (theWindow._isSheet)
deltaX *= 2;
// Calculate x and width first
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionTopLeft:
case _CPWindowViewResizeRegionLeft:
case _CPWindowViewResizeRegionBottomLeft:
// If it is shrinking from the left edge, the maximum distance it can move
// is the distance between the original width and the min width.
if (deltaX > 0)
deltaX = MIN(startWidth - minSize.width, deltaX);
// If it is growing from the left edge, the maximum distance it can move
// is the distance between the original width and the max width.
else if (deltaX < 0)
deltaX = -MIN(maxSize.width - startWidth, ABS(deltaX));
if (theWindow._isSheet)
deltaX = FLOOR(deltaX / 2);
newX = startX + deltaX;
// Pin the left edge to the usable screen left edge
var pinnedX = MAX(newX, CGRectGetMinX(_cachedScreenFrame));
if (pinnedX !== newX)
{
deltaX += pinnedX - newX;
newX = pinnedX;
}
// When resizing from the left, we change the origin and the width
if (theWindow._isSheet)
deltaX *= 2;
newWidth = startWidth - deltaX;
break;
case _CPWindowViewResizeRegionTopRight:
case _CPWindowViewResizeRegionRight:
case _CPWindowViewResizeRegionBottomRight:
// If it is growing from the right edge, the maximum distance it can move
// is the distance between the original width and the max width.
if (deltaX > 0)
deltaX = MIN(maxSize.width - startWidth, deltaX);
// If it is shrinking from the right edge, the maximum distance it can move
// is the distance between the original width and the min width.
else if (deltaX < 0)
deltaX = -MIN(startWidth - minSize.width, ABS(deltaX));
if (theWindow._isSheet)
deltaX = FLOOR(deltaX / 2);
// Pin the right edge to the usable screen right edge
var newMaxX = startX + startWidth + deltaX,
pinnedX = MIN(newMaxX, CGRectGetMaxX(_cachedScreenFrame));
if (pinnedX !== newMaxX)
deltaX += pinnedX - newMaxX;
if (theWindow._isSheet)
{
newWidth = startWidth + (deltaX * 2);
newX = startX - FLOOR((newWidth - startWidth) / 2);
}
else
{
newWidth = startWidth + deltaX;
newX = startX;
}
break;
default:
newX = startX;
newWidth = startWidth;
}
// Now calculate y and height
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionTopLeft:
case _CPWindowViewResizeRegionTop:
case _CPWindowViewResizeRegionTopRight:
// If it is shrinking from the top edge, the maximum distance it can move
// is the distance between the original height and the min height.
if (deltaY > 0)
deltaY = MIN(startHeight - minSize.height, deltaY);
// If it is growing from the top edge, the maximum distance it can move
// is the distance between the original height and the max height.
else if (deltaY < 0)
deltaY = -MIN(maxSize.height - startHeight, ABS(deltaY));
newY = startY + deltaY;
// Pin the top edge to the usable screen top edge
var pinnedY = MAX(newY, CGRectGetMinY(_cachedScreenFrame));
if (pinnedY !== newY)
{
deltaY += pinnedY - newY;
newY = pinnedY;
}
// When resizing from the top, change the origin and the height
newHeight = startHeight - deltaY;
break;
case _CPWindowViewResizeRegionBottomLeft:
case _CPWindowViewResizeRegionBottom:
case _CPWindowViewResizeRegionBottomRight:
// If it is growing from the bottom edge, the maximum distance it can move
// is the distance between the original height and the max height.
if (deltaY > 0)
deltaY = MIN(maxSize.height - startHeight, deltaY);
// If it is shrinking from the bottom edge, the maximum distance it can move
// is the distance between the original height and the min height.
else if (deltaY < 0)
deltaY = -MIN(startHeight - minSize.height, ABS(deltaY));
newY = startY;
// Pin the bottom edge to the usable screen bottom edge
var newMaxY = startY + startHeight + deltaY,
pinnedY = MIN(newMaxY, CGRectGetMaxY(_cachedScreenFrame));
if (pinnedY !== newMaxY)
deltaY += pinnedY - newMaxY;
// When resizing from the bottom, change only the height
newHeight = startHeight + deltaY;
break;
default:
newY = startY;
newHeight = startHeight;
}
// When resizing, we always constrain to the usable screen.
frame = CGRectMake(newX, newY, newWidth, newHeight);
var constrainedFrame = [theWindow _constrainOriginOfFrame:frame],
dx = constrainedFrame.origin.x - frame.origin.x,
dy = constrainedFrame.origin.y - frame.origin.y;
// When resizing from the left or top, we adjust the origin and size.
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionBottomLeft:
case _CPWindowViewResizeRegionLeft:
case _CPWindowViewResizeRegionTopLeft:
case _CPWindowViewResizeRegionTop:
case _CPWindowViewResizeRegionTopRight:
frame.origin = constrainedFrame.origin;
frame.size.width -= dx;
frame.size.height -= dy;
}
// When resizing from the right or bottom, we only adjust the size.
switch (_resizeRegion)
{
case _CPWindowViewResizeRegionTopRight:
case _CPWindowViewResizeRegionRight:
case _CPWindowViewResizeRegionBottomRight:
case _CPWindowViewResizeRegionBottom:
frame.size.width += dx;
frame.size.height += dy;
}
[theWindow _setFrame:frame display:YES animate:NO constrainWidth:NO constrainHeight:NO];
[self setCursorForLocation:location resizing:YES];
}
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)trackMoveWithEvent:(CPEvent)anEvent
{
var theWindow = [self window];
if (![theWindow isMovable])
return;
var type = [anEvent type];
if (type === CPLeftMouseUp)
{
return;
}
else if (type === CPLeftMouseDown)
{
_mouseDraggedPoint = [theWindow convertBaseToGlobal:[anEvent locationInWindow]];
_cachedFrame = CGRectMakeCopy([theWindow frame]);
}
else if (type === CPLeftMouseDragged)
{
var theWindow = [self window],
location = [theWindow convertBaseToGlobal:[anEvent locationInWindow]],
deltaX = location.x - _mouseDraggedPoint.x,
deltaY = location.y - _mouseDraggedPoint.y,
origin = CGPointMake(_cachedFrame.origin.x + deltaX, _cachedFrame.origin.y + deltaY);
[theWindow setFrameOrigin:origin];
}
[CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)setFrameSize:(CGSize)newSize
{
[super setFrameSize:newSize];
// reposition sheet if the parent window resizes or moves
var theWindow = [self window],
sheet = [theWindow attachedSheet];
if (sheet)
{
[theWindow _setAttachedSheetFrameOrigin];
[sheet._windowView _adjustShadowViewSize];
}
else if (theWindow && theWindow._isSheet)
[self _adjustShadowViewSize];
}
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
{
if (shouldShowResizeIndicator && CPWindowResizeStyle === CPWindowResizeStyleLegacy)
{
_resizeIndicator = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_resizeIndicator setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[self addSubview:_resizeIndicator];
}
else
{
[_resizeIndicator removeFromSuperview];
_resizeIndicator = nil;
}
[self setNeedsLayout];
}
- (BOOL)showsResizeIndicator
{
return _resizeIndicator !== nil;
}
- (void)setResizeIndicatorOffset:(CGSize)anOffset
{
if (CGSizeEqualToSize(_resizeIndicatorOffset, anOffset))
return;
_resizeIndicatorOffset = anOffset;
if (!_resizeIndicator)
return;
var size = [_resizeIndicator frame].size,
boundsSize = [self frame].size;
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - anOffset.width, boundsSize.height - size.height - anOffset.height)];
}
- (CGSize)resizeIndicatorOffset
{
return _resizeIndicatorOffset;
}
- (void)windowDidChangeDocumentEdited
{
}
- (void)windowDidChangeDocumentSaving
{
}
- (BOOL)showsToolbar
{
var styleMaskWindow = [[self window] styleMask];
return styleMaskWindow & CPBorderlessWindowMask || styleMaskWindow & CPTitledWindowMask || styleMaskWindow & CPHUDBackgroundWindowMask || styleMaskWindow & CPBorderlessBridgeWindowMask;
}
- (CGSize)toolbarOffset
{
return _toolbarOffset;
}
- (CPColor)toolbarLabelColor
{
return [CPColor blackColor];
}
- (float)toolbarMaxY
{
if (!_toolbarView || [_toolbarView isHidden])
return [self toolbarOffset].height;
return CGRectGetMaxY([_toolbarView frame]);
}
- (_CPToolbarView)toolbarView
{
return _toolbarView;
}
- (void)tile
{
var theWindow = [self window],
bounds = [self bounds],
width = CGRectGetWidth(bounds);
if ([[theWindow toolbar] isVisible])
{
var toolbarView = [self toolbarView],
toolbarOffset = [self toolbarOffset];
[toolbarView setFrame:CGRectMake(toolbarOffset.width, toolbarOffset.height, width, CGRectGetHeight([toolbarView frame]))];
}
if ([self showsResizeIndicator])
{
var size = [_resizeIndicator frame].size,
boundsSize = [self bounds].size;
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height)];
}
}
- (void)noteToolbarChanged
{
var theWindow = [self window],
toolbar = [theWindow toolbar],
toolbarView = [toolbar _toolbarView];
if (_toolbarView !== toolbarView)
{
[_toolbarView removeFromSuperview];
if (toolbarView)
{
[toolbarView removeFromSuperview];
[toolbarView FIXME_setIsHUD:_styleMask & CPHUDBackgroundWindowMask];
[self addSubview:toolbarView];
}
_toolbarView = toolbarView;
}
[toolbarView setHidden:![self showsToolbar] || ![toolbar isVisible]];
if (theWindow)
{
var contentRect = [self convertRect:[[theWindow contentView] frame] toView:nil];
contentRect.origin = [theWindow convertBaseToGlobal:contentRect.origin];
[self setAutoresizesSubviews:NO];
[theWindow setFrame:[theWindow frameRectForContentRect:contentRect]];
[self setAutoresizesSubviews:YES];
}
[self tile];
}
- (void)noteKeyWindowStateChanged
{
if ([[self window] isKeyWindow])
[self setThemeState:CPThemeStateKeyWindow];
else
[self unsetThemeState:CPThemeStateKeyWindow];
}
- (void)noteMainWindowStateChanged
{
if ([[self window] isMainWindow])
[self setThemeState:CPThemeStateMainWindow];
else
[self unsetThemeState:CPThemeStateMainWindow];
}
/*
- (void)setAnimatingToolbar:(BOOL)isAnimatingToolbar
{
_isAnimatingToolbar = isAnimatingToolbar;
}
- (BOOL)isAnimatingToolbar
{
return _isAnimatingToolbar;
}
*/
- (void)didAddSubview:(CPView)aView
{
if (!_resizeIndicator || aView === _resizeIndicator)
return;
[self addSubview:_resizeIndicator];
}
- (void)_enableSheet:(BOOL)enable inWindow:(CPWindow)parentWindow
{
if (enable)
{
// Clip the shadow view width to the parent's content view
var myWidth = [self bounds].size.width,
shadowWidth = [self _shadowViewWidthForParentWindow:parentWindow],
shadowHeight = [self currentValueForThemeAttribute:@"shadow-height"];
_sheetShadowView = [[CPView alloc] initWithFrame:CGRectMake(FLOOR((myWidth - shadowWidth) / 2), 0, shadowWidth, shadowHeight)];
[_sheetShadowView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_sheetShadowView];
}
else
{
[_sheetShadowView removeFromSuperview];
_sheetShadowView = nil;
}
[self setNeedsLayout];
}
- (CGRect)_shadowViewWidthForParentWindow:(CPWindow)parentWindow
{
var myWidth = [self bounds].size.width,
parentWidth = [[parentWindow contentView] bounds].size.width;
return MIN(myWidth, parentWidth);
}
- (void)layoutSubviews
{
[super layoutSubviews];
[_sheetShadowView setBackgroundColor:[self valueForThemeAttribute:@"attached-sheet-shadow-color"]];
if (_resizeIndicator)
{
var size = [self valueForThemeAttribute:@"size-indicator"],
boundsSize = [self frame].size;
[_resizeIndicator setFrame:CGRectMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height, size.width, size.height)];
[_resizeIndicator setImage:[self valueForThemeAttribute:@"resize-indicator"]];
}
}
- (void)_adjustShadowViewSize
{
if (!_sheetShadowView)
return;
var myWidth = [self frame].size.width,
shadowFrame = [_sheetShadowView frame],
shadowWidth = [self _shadowViewWidthForParentWindow:_window._parentView];
shadowFrame.origin.x = FLOOR((myWidth - shadowWidth) / 2);
shadowFrame.size.width = shadowWidth;
[_sheetShadowView setFrame:shadowFrame];
}
- (CGSize)_minimumResizeSize
{
// Leave at least 4px so there is something visible.
return CGSizeMake(4, _CPWindowViewMinContentHeight);
}
- (int)bodyOffset
{
return [self frame].origin.y;
}
@end