mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
468 lines
14 KiB
Plaintext
468 lines
14 KiB
Plaintext
/*
|
|
* CPScrollView.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"
|
|
import "CPClipView.j"
|
|
import "CPScroller.j"
|
|
|
|
#include "CoreGraphics/CGGeometry.h"
|
|
|
|
|
|
@implementation CPScrollView : CPView
|
|
{
|
|
CPClipView _contentView;
|
|
|
|
BOOL _hasVerticalScroller;
|
|
BOOL _hasHorizontalScroller;
|
|
BOOL _autohidesScrollers;
|
|
|
|
CPScroller _verticalScroller;
|
|
CPScroller _horizontalScroller;
|
|
|
|
int _recursionCount;
|
|
|
|
float _verticalLineScroll;
|
|
float _verticalPageScroll;
|
|
float _horizontalLineScroll;
|
|
float _horizontalPageScroll;
|
|
}
|
|
|
|
- (id)initWithFrame:(CPRect)aFrame
|
|
{
|
|
self = [super initWithFrame:aFrame];
|
|
|
|
if (self)
|
|
{
|
|
_verticalLineScroll = 10.0;
|
|
_verticalPageScroll = 10.0;
|
|
|
|
_horizontalLineScroll = 10.0;
|
|
_horizontalPageScroll = 10.0;
|
|
|
|
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
|
|
|
|
[self addSubview:_contentView];
|
|
|
|
[self setHasVerticalScroller:YES];
|
|
[self setHasHorizontalScroller:YES];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
// Determining component sizes
|
|
- (CPRect)contentSize
|
|
{
|
|
return [_contentView frame].size;
|
|
}
|
|
|
|
- (id)documentView
|
|
{
|
|
return [_contentView documentView];
|
|
}
|
|
|
|
- (void)setContentView:(CPClipView)aContentView
|
|
{
|
|
if (!aContentView)
|
|
return;
|
|
|
|
var documentView = [aContentView documentView];
|
|
|
|
if (documentView)
|
|
[documentView removeFromSuperview];
|
|
|
|
[_contentView removeFromSuperview];
|
|
|
|
var size = [self contentSize];
|
|
|
|
_contentView = aContentView;
|
|
|
|
[_contentView setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
|
|
[_contentView setDocumentView:documentView];
|
|
|
|
[self addSubview:_contentView];
|
|
}
|
|
|
|
- (CPClipView)contentView
|
|
{
|
|
return _contentView;
|
|
}
|
|
|
|
- (void)setDocumentView:(CPView)aView
|
|
{
|
|
[_contentView setDocumentView:aView];
|
|
[self reflectScrolledClipView:_contentView];
|
|
}
|
|
|
|
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
|
{
|
|
if(_contentView != aClipView)
|
|
return;
|
|
|
|
if (_recursionCount > 5)
|
|
return;
|
|
|
|
++_recursionCount;
|
|
|
|
var documentView = [self documentView];
|
|
|
|
if (!documentView)
|
|
{
|
|
if (_autohidesScrollers)
|
|
{
|
|
[_verticalScroller setHidden:YES];
|
|
[_horizontalScroller setHidden:YES];
|
|
}
|
|
else
|
|
{
|
|
[_verticalScroller setEnabled:NO];
|
|
[_horizontalScroller setEnabled:NO];
|
|
}
|
|
|
|
[_contentView setFrame:[self bounds]];
|
|
|
|
--_recursionCount;
|
|
|
|
return;
|
|
}
|
|
|
|
var documentFrame = [documentView frame],
|
|
contentViewFrame = [self bounds],
|
|
scrollPoint = [_contentView bounds].origin,
|
|
difference = _CGSizeMake(CPRectGetWidth(documentFrame) - CPRectGetWidth(contentViewFrame), CPRectGetHeight(documentFrame) - CPRectGetHeight(contentViewFrame)),
|
|
shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > 0.0) && _hasVerticalScroller,
|
|
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > 0.0) && _hasHorizontalScroller,
|
|
wasShowingVerticalScroller = ![_verticalScroller isHidden],
|
|
wasShowingHorizontalScroller = ![_horizontalScroller isHidden],
|
|
verticalScrollerWidth = [CPScroller scrollerWidthForControlSize:[_verticalScroller controlSize]],
|
|
horizontalScrollerHeight = [CPScroller scrollerWidthForControlSize:[_horizontalScroller controlSize]];
|
|
|
|
if (_autohidesScrollers)
|
|
{
|
|
if (shouldShowVerticalScroller)
|
|
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > -verticalScrollerWidth) && _hasHorizontalScroller;
|
|
if (shouldShowHorizontalScroller)
|
|
shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > -horizontalScrollerHeight) && _hasVerticalScroller;
|
|
}
|
|
|
|
[_verticalScroller setHidden:!shouldShowVerticalScroller];
|
|
[_verticalScroller setEnabled:!_autohidesScrollers && difference.height < 0];
|
|
|
|
[_horizontalScroller setHidden:!shouldShowHorizontalScroller];
|
|
[_horizontalScroller setEnabled:!_autohidesScrollers && difference.width < 0];
|
|
|
|
if (shouldShowVerticalScroller)
|
|
{
|
|
var verticalScrollerHeight = CPRectGetHeight(contentViewFrame);
|
|
|
|
if (shouldShowHorizontalScroller)
|
|
verticalScrollerHeight -= horizontalScrollerHeight;
|
|
|
|
difference.width += verticalScrollerWidth;
|
|
contentViewFrame.size.width -= verticalScrollerWidth;
|
|
|
|
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height
|
|
knobProportion:CPRectGetHeight(contentViewFrame) / CPRectGetHeight(documentFrame)];
|
|
[_verticalScroller setFrame:CPRectMake(CPRectGetMaxX(contentViewFrame), 0.0, verticalScrollerWidth, verticalScrollerHeight)];
|
|
}
|
|
else if (wasShowingVerticalScroller)
|
|
[_verticalScroller setFloatValue:0.0 knobProportion:1.0];
|
|
|
|
if (shouldShowHorizontalScroller)
|
|
{
|
|
difference.height += horizontalScrollerHeight;
|
|
contentViewFrame.size.height -= horizontalScrollerHeight;
|
|
|
|
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width
|
|
knobProportion:CPRectGetWidth(contentViewFrame) / CPRectGetWidth(documentFrame)];
|
|
[_horizontalScroller setFrame:CPRectMake(0.0, CPRectGetMaxY(contentViewFrame), CPRectGetWidth(contentViewFrame), horizontalScrollerHeight)];
|
|
}
|
|
else if (wasShowingHorizontalScroller)
|
|
[_horizontalScroller setFloatValue:0.0 knobProportion:1.0];
|
|
|
|
[_contentView setFrame:contentViewFrame];
|
|
|
|
// The reason we have to do this is because this is called on a frame size change, so when the frame changes,
|
|
// so does the the float value, so we have to update the clip view accordingly.
|
|
if (_hasVerticalScroller && (shouldShowVerticalScroller || wasShowingVerticalScroller))
|
|
{
|
|
//[self _verticalScrollerDidScroll:_verticalScroller];
|
|
var value = [_verticalScroller floatValue],
|
|
contentBounds = [_contentView bounds];
|
|
|
|
contentBounds.origin.y = value * (_CGRectGetHeight([[_contentView documentView] frame]) - _CGRectGetHeight(contentBounds));
|
|
|
|
[_contentView scrollToPoint:contentBounds.origin];
|
|
}
|
|
if (_hasHorizontalScroller && (shouldShowHorizontalScroller || wasShowingHorizontalScroller))
|
|
{
|
|
//[self _horizontalScrollerDidScroll:_horizontalScroller];
|
|
|
|
var value = [_horizontalScroller floatValue],
|
|
contentBounds = [_contentView bounds];
|
|
|
|
contentBounds.origin.x = value * (_CGRectGetWidth([[_contentView documentView] frame]) - _CGRectGetWidth(contentBounds));
|
|
|
|
[_contentView scrollToPoint:contentBounds.origin];
|
|
}
|
|
|
|
--_recursionCount;
|
|
}
|
|
|
|
// Managing Scrollers
|
|
|
|
- (void)setHorizontalScroller:(CPScroller)aScroller
|
|
{
|
|
if (_horizontalScroller == aScroller)
|
|
return;
|
|
|
|
[_horizontalScroller removeFromSuperview];
|
|
[_horizontalScroller setTarget:nil];
|
|
[_horizontalScroller setAction:nil];
|
|
|
|
_horizontalScroller = aScroller;
|
|
|
|
[_horizontalScroller setTarget:self];
|
|
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
|
|
[self addSubview:_horizontalScroller];
|
|
}
|
|
|
|
- (CPScroller)horizontalScroller
|
|
{
|
|
return _horizontalScroller;
|
|
}
|
|
|
|
- (void)setHasHorizontalScroller:(BOOL)hasHorizontalScroller
|
|
{
|
|
_hasHorizontalScroller = hasHorizontalScroller;
|
|
|
|
if (_hasHorizontalScroller && !_horizontalScroller)
|
|
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CPRectMake(0.0, 0.0, CPRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
|
else if (!hasHorizontalScroller && _horizontalScroller)
|
|
[_horizontalScroller setHidden:YES];
|
|
}
|
|
|
|
- (BOOL)hasHorizontalScroller
|
|
{
|
|
return _hasHorizontalScroller;
|
|
}
|
|
|
|
- (void)setVerticalScroller:(CPScroller)aScroller
|
|
{
|
|
if (_verticalScroller == aScroller)
|
|
return;
|
|
|
|
[_verticalScroller removeFromSuperview];
|
|
[_verticalScroller setTarget:nil];
|
|
[_verticalScroller setAction:nil];
|
|
|
|
_verticalScroller = aScroller;
|
|
|
|
[_verticalScroller setTarget:self];
|
|
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
|
|
[self addSubview:_verticalScroller];
|
|
}
|
|
|
|
- (CPScroller)verticalScroller
|
|
{
|
|
return _verticalScroller;
|
|
}
|
|
|
|
- (void)setHasVerticalScroller:(BOOL)hasVerticalScroller
|
|
{
|
|
_hasVerticalScroller = hasVerticalScroller;
|
|
|
|
if (_hasVerticalScroller && !_verticalScroller)
|
|
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:CPRectMake(0.0, 0.0, [CPScroller scrollerWidth], CPRectGetHeight([self bounds]))]];
|
|
else if (!hasVerticalScroller && _verticalScroller)
|
|
[_verticalScroller setHidden:YES];
|
|
}
|
|
|
|
- (BOOL)hasHorizontalScroller
|
|
{
|
|
return _hasHorizontalScroller;
|
|
}
|
|
|
|
- (void)setAutohidesScrollers:(BOOL)autohidesScrollers
|
|
{
|
|
_autohidesScrollers = autohidesScrollers;
|
|
}
|
|
|
|
- (BOOL)autohidesScrollers
|
|
{
|
|
return _autohidesScrollers;
|
|
}
|
|
/*
|
|
- (void)setFrameSize:(CPRect)aSize
|
|
{
|
|
[super setFrameSize:aSize];
|
|
|
|
[self reflectScrolledClipView:_contentView];
|
|
}*/
|
|
|
|
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
|
{
|
|
var value = [aScroller floatValue],
|
|
documentFrame = [[_contentView documentView] frame];
|
|
contentBounds = [_contentView bounds];
|
|
|
|
switch ([_verticalScroller hitPart])
|
|
{
|
|
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
|
|
break;
|
|
|
|
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
|
|
break;
|
|
|
|
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
|
break;
|
|
|
|
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
|
break;
|
|
|
|
case CPScrollerKnobSlot:
|
|
case CPScrollerKnob:
|
|
default: contentBounds.origin.y = value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
|
|
}
|
|
|
|
[_contentView scrollToPoint:contentBounds.origin];
|
|
}
|
|
|
|
- (void)_horizontalScrollerDidScroll:(CPScroller)aScroller
|
|
{
|
|
var value = [aScroller floatValue],
|
|
documentFrame = [[self documentView] frame],
|
|
contentBounds = [_contentView bounds];
|
|
|
|
switch ([_horizontalScroller hitPart])
|
|
{
|
|
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
|
|
break;
|
|
|
|
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
|
|
break;
|
|
|
|
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
|
break;
|
|
|
|
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
|
break;
|
|
|
|
case CPScrollerKnobSlot:
|
|
case CPScrollerKnob:
|
|
default: contentBounds.origin.x = value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds));
|
|
}
|
|
|
|
[_contentView scrollToPoint:contentBounds.origin];
|
|
}
|
|
|
|
- (void)tile
|
|
{
|
|
// yuck.
|
|
// RESIZE: tile->setHidden AND refl
|
|
// Outside Change: refl->tile->setHidden AND refl
|
|
// scroll: refl.
|
|
}
|
|
|
|
-(void)resizeSubviewsWithOldSize:(CPSize)aSize
|
|
{
|
|
[self reflectScrolledClipView:_contentView];
|
|
}
|
|
|
|
// Setting Scrolling Behavior
|
|
|
|
- (void)setLineScroll:(float)aLineScroll
|
|
{
|
|
[self setHorizonalLineScroll:aLineScroll];
|
|
[self setVerticalLineScroll:aLineScroll];
|
|
}
|
|
|
|
- (float)lineScroll
|
|
{
|
|
return [self horizontalLineScroll];
|
|
}
|
|
|
|
- (void)setHorizontalLineScroll:(float)aLineScroll
|
|
{
|
|
_horizontalLineScroll = aLineScroll;
|
|
}
|
|
|
|
- (float)horizontalLineScroll
|
|
{
|
|
return _horizontalLineScroll;
|
|
}
|
|
|
|
- (void)setVerticalLineScroll:(float)aLineScroll
|
|
{
|
|
_verticalLineScroll = aLineScroll;
|
|
}
|
|
|
|
- (float)verticalLineScroll
|
|
{
|
|
return _verticalLineScroll;
|
|
}
|
|
|
|
- (void)setPageScroll:(float)aPageScroll
|
|
{
|
|
[self setHorizontalPageScroll:aPageScroll];
|
|
[self setVerticalPageScroll:aPageScroll];
|
|
}
|
|
|
|
- (float)pageScroll
|
|
{
|
|
return [self horizontalPageScroll];
|
|
}
|
|
|
|
- (void)setHorizontalPageScroll:(float)aPageScroll
|
|
{
|
|
_horizontalPageScroll = aPageScroll;
|
|
}
|
|
|
|
- (float)horizontalPageScroll
|
|
{
|
|
return _horizontalPageScroll;
|
|
}
|
|
|
|
- (void)setVerticalPageScroll:(float)aPageScroll
|
|
{
|
|
_verticalPageScroll = aPageScroll;
|
|
}
|
|
|
|
- (float)verticalPageScroll
|
|
{
|
|
return _verticalPageScroll;
|
|
}
|
|
|
|
- (void)scrollWheel:(CPEvent)anEvent
|
|
{
|
|
var value = [_verticalScroller floatValue],
|
|
documentFrame = [[self documentView] frame],
|
|
contentBounds = [_contentView bounds];
|
|
|
|
contentBounds.origin.x += [anEvent deltaX] * _horizontalLineScroll;
|
|
contentBounds.origin.y += [anEvent deltaY] * _verticalLineScroll;
|
|
|
|
[_contentView scrollToPoint:contentBounds.origin];
|
|
}
|
|
|
|
@end
|