Files
cappuccino/AppKit/CPClipView.j
T
Alexandre Wilhelm 92cdb27e23 Fixed: documentVisibleRect in CPScrollView does not return the expected result
Previously, the method documentVisibleRect did not return the expected result. An issue happened when using this method on a scaled view. The converted rect was converted in the wrong context.

Unit test in Tests/AppKit/CPScrollViewTest.j

Fixed #2356
2015-05-19 14:30:09 -07:00

228 lines
6.4 KiB
Plaintext

/*
* CPClipView.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 "CPView.j"
@class CPScrollView
/*!
@ingroup appkit
@class CPClipView
CPClipView allows you to define a clip rect and display only that portion of its containing view.
It is used to hold the document view in a CPScrollView.
*/
@implementation CPClipView : CPView
{
CPView _documentView;
}
/*!
Sets the document view to be \c aView.
@param aView the new document view. It's frame origin will be changed to \c (0,0) after calling this method.
*/
- (void)setDocumentView:(CPView)aView
{
if (_documentView == aView)
return;
if (_documentView)
[_documentView removeFromSuperview];
_documentView = aView;
if (_documentView)
[self addSubview:_documentView];
}
/*!
Returns the document view.
*/
- (id)documentView
{
return _documentView;
}
/*!
Returns a new point that may be adjusted from \c aPoint
to make sure it lies within the document view.
@param aPoint
@return the adjusted point
*/
- (CGPoint)constrainScrollPoint:(CGPoint)aPoint
{
if (!_documentView)
return CGPointMakeZero();
var documentFrame = [_documentView frame];
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(CGRectGetWidth(documentFrame) - CGRectGetWidth(_bounds), 0.0)));
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(CGRectGetHeight(documentFrame) - CGRectGetHeight(_bounds), 0.0)));
return aPoint;
}
- (void)setBoundsOrigin:(CGPoint)aPoint
{
if (CGPointEqualToPoint(_bounds.origin, aPoint))
return;
[super setBoundsOrigin:aPoint];
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
/*!
Scrolls the clip view to the specified point. The method
sets its bounds origin to \c aPoint.
*/
- (void)scrollToPoint:(CGPoint)aPoint
{
[self setBoundsOrigin:[self constrainScrollPoint:aPoint]];
}
/*!
Handles a CPViewBoundsDidChangeNotification.
@param aNotification the notification event
*/
- (void)viewBoundsChanged:(CPNotification)aNotification
{
[self _constrainScrollPoint];
}
/*!
Handles a CPViewFrameDidChangeNotification.
@param aNotification the notification event
*/
- (void)viewFrameChanged:(CPNotification)aNotification
{
[self _constrainScrollPoint];
}
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
{
[super resizeSubviewsWithOldSize:aSize];
[self _constrainScrollPoint];
}
- (void)_constrainScrollPoint
{
var oldScrollPoint = [self bounds].origin;
// Call scrollToPoint: because the current scroll point may no longer make
// sense given the new frame of the document view.
[self scrollToPoint:oldScrollPoint];
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// the scroll points are not equal (meaning scrollToPoint: didn't early bail).
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
return;
// ... and we're in a scroll view of course.
var superview = [self superview],
// This is hack to avoid having to import CPScrollView.
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
- (BOOL)autoscroll:(CPEvent)anEvent
{
var bounds = [self bounds],
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
superview = [self superview],
deltaX = 0,
deltaY = 0;
if (CGRectContainsPoint(bounds, eventLocation))
return NO;
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(bounds))
deltaY = CGRectGetMinY(bounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(bounds))
deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
if (deltaY < -bounds.size.height)
deltaY = -bounds.size.height;
if (deltaY > bounds.size.height)
deltaY = bounds.size.height;
}
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(bounds))
deltaX = CGRectGetMinX(bounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(bounds))
deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
if (deltaX < -bounds.size.width)
deltaX = -bounds.size.width;
if (deltaX > bounds.size.width)
deltaX = bounds.size.width;
}
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
- (CGRect)documentVisibleRect
{
return [_documentView visibleRect];
}
@end
var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
@implementation CPClipView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
// Don't call setDocumentView: here. It calls addSubview:, but it's A) not necessary since the
// view hierarchy is fully encoded and B) dangerous if the subview is not fully decoded.
_documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
}
@end