mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
The new options are: 1. Resizable Horizontally 2. Resizable Vertically 3. Max Size Also two options from the Text Container is recognized: 1. Tracks text view width 2. Tracks text view height The last two are needed to allow the text view to recalculate the size of its content if the frame size is changed.
274 lines
7.2 KiB
Plaintext
274 lines
7.2 KiB
Plaintext
/*
|
|
* CPTextContainer.j
|
|
* AppKit
|
|
*
|
|
* Created by Emmanuel Maillard on 27/02/2010.
|
|
* Copyright Emmanuel Maillard 2010.
|
|
*
|
|
* 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/CPGeometry.j>
|
|
@import "CPLayoutManager.j"
|
|
|
|
@class CPTextView
|
|
@class CPLayoutManager
|
|
|
|
/*
|
|
@global
|
|
@group CPLineSweepDirection
|
|
*/
|
|
CPLineSweepLeft = 0;
|
|
/*
|
|
@global
|
|
@group CPLineSweepDirection
|
|
*/
|
|
CPLineSweepRight = 1;
|
|
/*
|
|
@global
|
|
@group CPLineSweepDirection
|
|
*/
|
|
CPLineSweepDown = 2;
|
|
/*
|
|
@global
|
|
@group CPLineSweepDirection
|
|
*/
|
|
CPLineSweepUp = 3;
|
|
|
|
/*
|
|
@global
|
|
@group CPLineMovementDirection
|
|
*/
|
|
CPLineDoesntMoves = 0;
|
|
/*
|
|
@global
|
|
@group CPLineMovementDirection
|
|
*/
|
|
CPLineMovesLeft = 1;
|
|
/*
|
|
@global
|
|
@group CPLineMovementDirection
|
|
*/
|
|
CPLineMovesRight = 2;
|
|
/*
|
|
@global
|
|
@group CPLineMovementDirection
|
|
*/
|
|
CPLineMovesDown = 3;
|
|
/*
|
|
@global
|
|
@group CPLineMovementDirection
|
|
*/
|
|
CPLineMovesUp = 4;
|
|
|
|
/*!
|
|
@ingroup appkit
|
|
@class CPTextContainer
|
|
*/
|
|
@implementation CPTextContainer : CPObject
|
|
{
|
|
float _lineFragmentPadding @accessors(property=lineFragmentPadding);
|
|
CGSize _size @accessors(property=containerSize);
|
|
CPLayoutManager _layoutManager @accessors(property=layoutManager);
|
|
CPTextView _textView @accessors(property=textView);
|
|
BOOL _inResizing;
|
|
BOOL _widthTracksTextView;
|
|
BOOL _heightTracksTextView;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Init methods
|
|
|
|
- (id)initWithContainerSize:(CGSize)aSize
|
|
{
|
|
self = [super init];
|
|
|
|
if (self)
|
|
{
|
|
_size = aSize;
|
|
[self _init];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
return [self initWithContainerSize:CPMakeSize(1e7, 1e7)];
|
|
}
|
|
|
|
- (void)_init
|
|
{
|
|
_lineFragmentPadding = 0.0;
|
|
|
|
_layoutManager = [[CPLayoutManager alloc] init];
|
|
[_layoutManager addTextContainer:self];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Setter methods
|
|
|
|
- (void)setContainerSize:(CGSize)someSize
|
|
{
|
|
var oldSize = _size;
|
|
|
|
_size = CGSizeMakeCopy(someSize);
|
|
|
|
if (oldSize.width != _size.width)
|
|
{
|
|
_inResizing = YES;
|
|
[_layoutManager invalidateLayoutForCharacterRange:CPMakeRange(0, [[_layoutManager textStorage] length])
|
|
isSoft:NO
|
|
actualCharacterRange:NULL];
|
|
|
|
[_layoutManager _validateLayoutAndGlyphs];
|
|
[_textView sizeToFit]; // this is necessary to adopt the height of CPTextView in case of rewrapping
|
|
_inResizing = NO;
|
|
}
|
|
}
|
|
|
|
// Controls whether the receiver adjusts the width of its bounding rectangle when its text view is resized.
|
|
- (BOOL)widthTracksTextView
|
|
{
|
|
return _widthTracksTextView;
|
|
}
|
|
|
|
- (void)setWidthTracksTextView:(BOOL)flag
|
|
{
|
|
_widthTracksTextView = flag;
|
|
[_textView setPostsFrameChangedNotifications:flag];
|
|
|
|
if (flag && _textView)
|
|
{
|
|
[[CPNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(textViewFrameChanged:)
|
|
name:CPViewFrameDidChangeNotification
|
|
object:_textView];
|
|
}
|
|
else
|
|
{
|
|
[[CPNotificationCenter defaultCenter] removeObserver:self
|
|
name:CPViewFrameDidChangeNotification
|
|
object:_textView];
|
|
}
|
|
}
|
|
|
|
- (void)textViewFrameChanged:(CPNotification)aNotification
|
|
{
|
|
var newSize = CGSizeMake([_textView frame].size.width, _size.height);
|
|
|
|
[self setContainerSize:newSize];
|
|
}
|
|
|
|
- (void)setTextView:(CPTextView)aTextView
|
|
{
|
|
if (_textView)
|
|
{
|
|
[self setWidthTracksTextView:NO]; // We only support width
|
|
[_textView setTextContainer:nil];
|
|
}
|
|
|
|
_textView = aTextView;
|
|
|
|
if (_textView)
|
|
{
|
|
[self setWidthTracksTextView:_widthTracksTextView]; // We only support width
|
|
[_textView setTextContainer:self];
|
|
}
|
|
|
|
[_layoutManager textContainerChangedTextView:self];
|
|
}
|
|
|
|
- (BOOL)containsPoint:(CGPoint)aPoint
|
|
{
|
|
return CGRectContainsPoint(CGRectMake(0, 0, _size.width, _size.height), aPoint);
|
|
}
|
|
|
|
- (BOOL)isSimpleRectangularTextContainer
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect
|
|
sweepDirection:(CPLineSweepDirection)sweep
|
|
movementDirection:(CPLineMovementDirection)movement
|
|
remainingRect:(CGRectPointer)remainingRect
|
|
{
|
|
var resultRect = CGRectCreateCopy(proposedRect);
|
|
|
|
if (sweep != CPLineSweepRight || movement != CPLineMovesDown)
|
|
{
|
|
CPLog.trace(@"FIXME: unsupported sweep (" + sweep + ") or movement (" + movement + ")");
|
|
return CGRectMakeZero();
|
|
}
|
|
|
|
if (resultRect.origin.x + resultRect.size.width > _size.width)
|
|
resultRect.size.width = _size.width - resultRect.origin.x;
|
|
|
|
if (resultRect.size.width < 0)
|
|
resultRect = CGRectMakeZero();
|
|
|
|
if (remainingRect)
|
|
{
|
|
remainingRect.origin.x = resultRect.origin.x + resultRect.size.width;
|
|
remainingRect.origin.y = resultRect.origin.y;
|
|
remainingRect.size.height = resultRect.size.height;
|
|
remainingRect.size.width = _size.width - (resultRect.origin.x + resultRect.size.width);
|
|
}
|
|
|
|
return resultRect;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
var CPTextContainerSizeKey = @"CPTextContainerSizeKey",
|
|
CPTextContainerLayoutManagerKey = @"CPTextContainerLayoutManagerKey",
|
|
CPTextContainerWidthTracksTextViewKey = @"CPTextContainerWidthTracksTextViewKey",
|
|
CPTextContainerHeightTracksTextViewKey = @"CPTextContainerHeightTracksTextViewKey";
|
|
|
|
@implementation CPTextContainer (CPCoding)
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
self = [super init];
|
|
|
|
if (self)
|
|
{
|
|
[self _init];
|
|
|
|
_size = [aCoder decodeSizeForKey:CPTextContainerSizeKey];
|
|
|
|
_layoutManager = [aCoder decodeObjectForKey:CPTextContainerLayoutManagerKey];
|
|
[_layoutManager addTextContainer:self];
|
|
|
|
_widthTracksTextView = [aCoder decodeBoolForKey:CPTextContainerWidthTracksTextViewKey];
|
|
_heightTracksTextView = [aCoder decodeBoolForKey:CPTextContainerHeightTracksTextViewKey];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
[aCoder encodeSize:_size forKey:CPTextContainerSizeKey];
|
|
[aCoder encodeObject:_layoutManager forKey:CPTextContainerLayoutManagerKey];
|
|
[aCoder encodeBool:_widthTracksTextView forKey:CPTextContainerWidthTracksTextViewKey];
|
|
[aCoder encodeBool:_heightTracksTextView forKey:CPTextContainerHeightTracksTextViewKey];
|
|
}
|
|
|
|
@end
|