mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-30 13:20:38 +00:00
A load of changes.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@4724 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
6d69b992d2
commit
6bceaa0b50
12 changed files with 1035 additions and 49 deletions
|
@ -7,6 +7,8 @@
|
|||
|
||||
Author: Jonathan Gapen <jagapen@smithlab.chem.wisc.edu>
|
||||
Date: July 1999
|
||||
Author: Michael Hanni <mhanni@sprintmail.com>
|
||||
Date: August 1999
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
|
@ -27,14 +29,271 @@
|
|||
*/
|
||||
#include <AppKit/NSLayoutManager.h>
|
||||
|
||||
// _GSRunSearchKey is an internal class which serves as the foundation for
|
||||
// all our searching. This may not be an elegant way to go about this, so
|
||||
// if someone wants to optimize this out, please do.
|
||||
|
||||
@interface _GSRunSearchKey : NSObject
|
||||
{
|
||||
@public
|
||||
NSRange glyphRange;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation _GSRunSearchKey
|
||||
- (id)init
|
||||
{
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSGlyphLocation : _GSRunSearchKey
|
||||
{
|
||||
@public
|
||||
NSPoint point;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSGlyphLocation
|
||||
- (id)init
|
||||
{
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSLineLayoutInfo : _GSRunSearchKey
|
||||
{
|
||||
@public
|
||||
NSRect lineFragmentRect;
|
||||
NSRect usedRect;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSLineLayoutInfo
|
||||
- (id)init
|
||||
{
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSTextContainerLayoutInfo : _GSRunSearchKey
|
||||
{
|
||||
@public
|
||||
NSTextContainer *textContainer;
|
||||
NSString *testString;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSTextContainerLayoutInfo
|
||||
- (id)init
|
||||
{
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
#define GSI_ARRAY_TYPES GSUNION_OBJ
|
||||
|
||||
#ifdef GSIArray
|
||||
#undef GSIArray
|
||||
#endif
|
||||
#include <base/GSIArray.h>
|
||||
|
||||
static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
|
||||
{
|
||||
if (((_GSRunSearchKey *)(i0.obj))->glyphRange.location
|
||||
< ((_GSRunSearchKey *)(i1.obj))->glyphRange.location)
|
||||
return NSOrderedAscending;
|
||||
else if (((_GSRunSearchKey *)(i0.obj))->glyphRange.location
|
||||
>= NSMaxRange(((_GSRunSearchKey *)(i1.obj))->glyphRange))
|
||||
return NSOrderedDescending;
|
||||
else
|
||||
return NSOrderedSame;
|
||||
}
|
||||
|
||||
@interface GSRunStorage : NSObject
|
||||
{
|
||||
unsigned int _count;
|
||||
void *_runs;
|
||||
}
|
||||
- (void)insertObject:(id)anObject;
|
||||
- (void)insertObject:(id)anObject atIndex:(unsigned)theIndex;
|
||||
- (id)objectAtIndex:(unsigned)theIndex;
|
||||
- (unsigned)indexOfObject:(id)anObject;
|
||||
- (unsigned)indexOfObjectContainingLocation:(unsigned)aLocation;
|
||||
- (id)objectContainingLocation:(unsigned)aLocation;
|
||||
- (int)count;
|
||||
@end
|
||||
|
||||
@implementation GSRunStorage
|
||||
- (id)init
|
||||
{
|
||||
NSZone *z;
|
||||
|
||||
[super init];
|
||||
|
||||
z = [self zone];
|
||||
|
||||
_runs = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity((GSIArray)_runs, z, 8);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject
|
||||
{
|
||||
_GSRunSearchKey *aKey = [_GSRunSearchKey new];
|
||||
_GSRunSearchKey *aObject = (_GSRunSearchKey *)anObject;
|
||||
int position;
|
||||
|
||||
aKey->glyphRange.location = aObject->glyphRange.location;
|
||||
|
||||
position = GSIArrayInsertionPosition(_runs, (GSIArrayItem)aKey, aSort);
|
||||
|
||||
NSLog(@"key: %d aObject: %d position: %d", aKey->glyphRange.location,
|
||||
aObject->glyphRange.location, position);
|
||||
|
||||
if (position > 0)
|
||||
{
|
||||
_GSRunSearchKey *anKey = GSIArrayItemAtIndex(_runs, (unsigned)position - 1).obj;
|
||||
|
||||
if (anKey->glyphRange.location == aObject->glyphRange.location)
|
||||
{
|
||||
// GSIArrayInsertSorted(_runs, (GSIArrayItem)anObject, aSort);
|
||||
NSLog(@"=========> duplicated item.");
|
||||
GSIArraySetItemAtIndex(_runs, (GSIArrayItem)anObject, position-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"=========> not duplicated item.");
|
||||
GSIArrayInsertItem(_runs, (GSIArrayItem)anObject, position);
|
||||
}
|
||||
}
|
||||
else if (position == 0)
|
||||
{
|
||||
NSLog(@"=========> first item (zero index).");
|
||||
GSIArrayInsertItem(_runs, (GSIArrayItem)anObject, position);
|
||||
// GSIArrayInsertSorted(_runs, (GSIArrayItem)anObject, aSort);
|
||||
// [self insertObject:anObject atIndex:position];
|
||||
}
|
||||
else
|
||||
NSLog(@"dead. VERY DEAD DEAD DEAD DEAD.");
|
||||
|
||||
NSLog(@"==> %d item(s)", GSIArrayCount(_runs));
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject
|
||||
atIndex:(unsigned)theIndex
|
||||
{
|
||||
NSLog(@"insertObject:atIndex: called. %d item(s)", GSIArrayCount(_runs));
|
||||
GSIArrayInsertSorted(_runs, (GSIArrayItem)anObject, aSort);
|
||||
// GSIArrayInsertItem(_runs, (GSIArrayItem)anObject, theIndex);
|
||||
NSLog(@"insertObject:atIndex: ended. %d item(s)", GSIArrayCount(_runs));
|
||||
}
|
||||
|
||||
- (void)removeObjectAtIndex:(int)theIndex
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(_runs, theIndex);
|
||||
}
|
||||
|
||||
- (id)objectAtIndex:(unsigned)theIndex
|
||||
{
|
||||
return GSIArrayItemAtIndex(_runs, (unsigned)theIndex).obj;
|
||||
}
|
||||
|
||||
- (unsigned)indexOfObject:(id)anObject
|
||||
{
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (unsigned)indexOfObjectContainingLocation:(unsigned)aLocation
|
||||
{
|
||||
_GSRunSearchKey *aKey = [_GSRunSearchKey new];
|
||||
int position;
|
||||
|
||||
aKey->glyphRange.location = aLocation;
|
||||
|
||||
position = GSIArrayInsertionPosition(_runs, (GSIArrayItem)aKey, aSort);
|
||||
|
||||
if (position >= 0 && position - 1 >= 0)
|
||||
{
|
||||
aKey = GSIArrayItemAtIndex(_runs, (unsigned)position - 1).obj;
|
||||
|
||||
if (NSLocationInRange(aLocation, aKey->glyphRange))
|
||||
{
|
||||
return (position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (id)objectContainingLocation:(unsigned)aLocation
|
||||
{
|
||||
_GSRunSearchKey *aKey = [_GSRunSearchKey new];
|
||||
int position;
|
||||
|
||||
aKey->glyphRange.location = aLocation;
|
||||
|
||||
position = GSIArrayInsertionPosition(_runs, (GSIArrayItem)aKey, aSort);
|
||||
|
||||
if (position >= 0 && position - 1 >= 0)
|
||||
{
|
||||
aKey = GSIArrayItemAtIndex(_runs, (unsigned)position - 1).obj;
|
||||
|
||||
if (NSLocationInRange(aLocation, aKey->glyphRange))
|
||||
{
|
||||
return aKey;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)lastObject
|
||||
{
|
||||
return GSIArrayItemAtIndex(_runs, GSIArrayCount(_runs) - 1).obj;
|
||||
}
|
||||
|
||||
- (int)count
|
||||
{
|
||||
return GSIArrayCount(_runs);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSLayoutManager
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
_backgroundLayout = YES;
|
||||
_delegate = nil;
|
||||
_textContainers = [[NSMutableArray alloc] initWithCapacity: 2];
|
||||
|
||||
containerRuns = [GSRunStorage new];
|
||||
fragmentRuns = [GSRunStorage new];
|
||||
locationRuns = [GSRunStorage new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -135,6 +394,23 @@
|
|||
{
|
||||
NSLog(@"NSLayoutManager was just notified that a change in the text
|
||||
storage occured.");
|
||||
|
||||
/*
|
||||
if (mask == NSTextStorageEditedCharacters)
|
||||
{
|
||||
aLayoutHole = [[NSLayoutHole alloc]
|
||||
initWithCharacterRange:invalidatedRange isSoft:NO];
|
||||
}
|
||||
else if (mask == NSTextStorageEditedAttributes)
|
||||
{
|
||||
}
|
||||
else if (mask == NSTextStorageEditedCharacters | NSTextStorageEditedAttributes)
|
||||
{
|
||||
}
|
||||
*/
|
||||
// invalidation should occure here.
|
||||
|
||||
[self _doLayout];
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -220,6 +496,9 @@ storage occured.");
|
|||
//
|
||||
// Setting glyph attributes
|
||||
//
|
||||
|
||||
// Each NSGlyph has an attribute field, yes?
|
||||
|
||||
- (void)setIntAttribute: (int)attribute
|
||||
value: (int)anInt
|
||||
forGlyphAtIndex: (unsigned)glyphIndex
|
||||
|
@ -238,26 +517,55 @@ storage occured.");
|
|||
- (void)setTextContainer: (NSTextContainer *)aTextContainer
|
||||
forGlyphRange: (NSRange)glyphRange
|
||||
{
|
||||
GSTextContainerLayoutInfo *theLine = [GSTextContainerLayoutInfo new];
|
||||
|
||||
theLine->glyphRange = glyphRange;
|
||||
ASSIGN(theLine->textContainer, aTextContainer);
|
||||
|
||||
[containerRuns insertObject:theLine];
|
||||
}
|
||||
|
||||
- (NSRange)glyphRangeForTextContainer: (NSTextContainer *)aTextContainer
|
||||
{
|
||||
NSSize tcSize = [aTextContainer containerSize];
|
||||
int i;
|
||||
|
||||
|
||||
NSLog(@"glyphRangeForTextContainer: called. There are %d
|
||||
textContainer(s) in containerRuns.", [containerRuns count]);
|
||||
|
||||
return NSMakeRange(0, 0);
|
||||
for (i=0;i<[containerRuns count];i++)
|
||||
{
|
||||
GSTextContainerLayoutInfo *aNewLine = [containerRuns objectAtIndex:i];
|
||||
|
||||
NSLog(@"glyphRangeForTextContainer: (%d, %d)",
|
||||
aNewLine->glyphRange.location,
|
||||
aNewLine->glyphRange.length);
|
||||
|
||||
if ([aNewLine->textContainer isEqual:aTextContainer])
|
||||
{
|
||||
NSLog(@"glyphRangeForWantedTextContainer: (%d, %d)",
|
||||
aNewLine->glyphRange.location,
|
||||
aNewLine->glyphRange.length);
|
||||
|
||||
return aNewLine->glyphRange;
|
||||
}
|
||||
}
|
||||
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
|
||||
- (NSTextContainer *)textContainerForGlyphAtIndex: (unsigned)glyphIndex
|
||||
effectiveRange: (NSRange *)effectiveRange
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
GSTextContainerLayoutInfo *theLine = [containerRuns objectContainingLocation:glyphIndex];
|
||||
|
||||
- (NSRect)usedRectForTextContainer: (NSTextContainer *)aTextContainer
|
||||
{
|
||||
return NSZeroRect;
|
||||
if(theLine)
|
||||
{
|
||||
(NSRange *)effectiveRange = &theLine->glyphRange;
|
||||
return theLine->textContainer;
|
||||
}
|
||||
|
||||
(NSRange *)effectiveRange = NULL;
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -267,17 +575,42 @@ storage occured.");
|
|||
forGlyphRange: (NSRange)glyphRange
|
||||
usedRect: (NSRect)usedRect
|
||||
{
|
||||
GSLineLayoutInfo *aNewLine = [GSLineLayoutInfo new];
|
||||
|
||||
aNewLine->glyphRange = glyphRange;
|
||||
aNewLine->lineFragmentRect = fragmentRect;
|
||||
aNewLine->usedRect = usedRect;
|
||||
|
||||
[fragmentRuns insertObject:aNewLine];
|
||||
}
|
||||
|
||||
- (NSRect)lineFragmentRectForGlyphAtIndex: (unsigned)glyphIndex
|
||||
effectiveRange: (NSRange *)lineFragmentRange
|
||||
{
|
||||
GSLineLayoutInfo *theLine = [fragmentRuns objectContainingLocation:glyphIndex];
|
||||
|
||||
if (theLine)
|
||||
{
|
||||
(NSRange *)lineFragmentRange = &theLine->glyphRange;
|
||||
return theLine->lineFragmentRect;
|
||||
}
|
||||
|
||||
(NSRange *)lineFragmentRange = NULL;
|
||||
return NSZeroRect;
|
||||
}
|
||||
|
||||
- (NSRect)lineFragmentUsedRectForGlyphAtIndex: (unsigned)glyphIndex
|
||||
effectiveRange: (NSRange *)lineFragmentRange
|
||||
{
|
||||
GSLineLayoutInfo *theLine = [fragmentRuns objectContainingLocation:glyphIndex];
|
||||
|
||||
if (theLine)
|
||||
{
|
||||
(NSRange *)lineFragmentRange = &theLine->glyphRange;
|
||||
return theLine->usedRect;
|
||||
}
|
||||
|
||||
(NSRange *)lineFragmentRange = NULL;
|
||||
return NSZeroRect;
|
||||
}
|
||||
|
||||
|
@ -315,9 +648,16 @@ storage occured.");
|
|||
//
|
||||
// Layout of glyphs
|
||||
//
|
||||
|
||||
- (void)setLocation: (NSPoint)aPoint
|
||||
forStartOfGlyphRange: (NSRange)glyphRange
|
||||
{
|
||||
GSGlyphLocation *aNewLine = [GSGlyphLocation new];
|
||||
|
||||
aNewLine->glyphRange = glyphRange;
|
||||
aNewLine->point = aPoint;
|
||||
|
||||
[locationRuns insertObject:aNewLine];
|
||||
}
|
||||
|
||||
- (NSPoint)locationForGlyphAtIndex: (unsigned)glyphIndex
|
||||
|
@ -327,7 +667,14 @@ storage occured.");
|
|||
|
||||
- (NSRange)rangeOfNominallySpacedGlyphsContainingIndex: (unsigned)glyphIndex
|
||||
{
|
||||
return NSMakeRange(0, 0);
|
||||
GSLineLayoutInfo *theLine = [locationRuns objectContainingLocation:glyphIndex];
|
||||
|
||||
if (theLine)
|
||||
{
|
||||
return theLine->glyphRange;
|
||||
}
|
||||
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
|
||||
- (NSRect *)rectArrayForCharacterRange: (NSRange)charRange
|
||||
|
@ -335,7 +682,43 @@ storage occured.");
|
|||
inTextContainer: (NSTextContainer *)aTextContainer
|
||||
rectCount: (unsigned *)rectCount
|
||||
{
|
||||
return NULL;
|
||||
/*
|
||||
GSLineLayoutInfo *theLine = [GSLineLayoutInfo new];
|
||||
int position, lastPosition;
|
||||
int i, j = 0;
|
||||
|
||||
theLine->glyphRange.location = charRange.location;
|
||||
|
||||
position = GSIArrayInsertionPosition(lineFragments, (GSIArrayItem)theLine, aSort);
|
||||
|
||||
if (position < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
theLine->glyphRange.location = charRange.location + charRange.length;
|
||||
|
||||
lastPosition = GSIArrayInsertionPosition(lineFragments, (GSIArrayItem)theLine, aSort);
|
||||
|
||||
if (lastPosition > 0)
|
||||
{
|
||||
_cachedRectArray = NSZoneRealloc([self zone], _cachedRectArray,
|
||||
(lastPosition - position) * sizeof(NSRect));
|
||||
|
||||
_cachedRectArrayCapacity = lastPosition - position;
|
||||
|
||||
for (i = position - 1; i < lastPosition - 1; i++)
|
||||
{
|
||||
GSLineLayoutInfo *aLine = GSIArrayItemAtIndex(lineFragments, i).obj;
|
||||
|
||||
_cachedRectArray[j] = aLine->lineFragmentRect;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
(*rectCount) = (position - 1 + lastPosition - 1);
|
||||
return _cachedRectArray;
|
||||
*/
|
||||
}
|
||||
|
||||
- (NSRect *)rectArrayForGlyphRange: (NSRange)glyphRange
|
||||
|
@ -343,12 +726,41 @@ storage occured.");
|
|||
inTextContainer: (NSTextContainer *)aTextContainer
|
||||
rectCount: (unsigned *)rectCount
|
||||
{
|
||||
return NULL;
|
||||
return _cachedRectArray;
|
||||
}
|
||||
|
||||
- (NSRect)boundingRectForGlyphRange: (NSRange)glyphRange
|
||||
inTextContainer: (NSTextContainer *)aTextContainer
|
||||
{
|
||||
|
||||
/* Returns a single bounding rectangle enclosing all glyphs and other
|
||||
marks drawn in aTextContainer for glyphRange, including glyphs that draw
|
||||
outside their line fragment rectangles and text attributes such as
|
||||
underlining. This method is useful for determining the area that needs to
|
||||
be redrawn when a range of glyphs changes. */
|
||||
/*
|
||||
unsigned rectCount;
|
||||
NSRect *rects = [self rectArrayForCharacterRange: [self glyphRangeForTextContainer:aTextContainer]
|
||||
withinSelectedCharacterRange: NSMakeRange(0,0)
|
||||
inTextContainer: aTextContainer
|
||||
rectCount: &rectCount];
|
||||
// NSPoint aOrigin = [aTextContainer originPoint];
|
||||
NSRect rRect = NSZeroRect;
|
||||
int i;
|
||||
|
||||
for (i=0;i<rectCount;i++)
|
||||
{
|
||||
NSRect aRect = rects[i];
|
||||
|
||||
if (aRect.origin.y == rRect.size.height)
|
||||
rRect.size.height += aRect.size.width;
|
||||
|
||||
if (rRect.size.width == aRect.origin.x)
|
||||
rRect.size.width += aRect.size.width;
|
||||
}
|
||||
|
||||
return rRect;
|
||||
*/
|
||||
return NSZeroRect;
|
||||
}
|
||||
|
||||
|
@ -425,6 +837,11 @@ fractionOfDistanceThroughGlyph: (float *)partialFraction
|
|||
{
|
||||
}
|
||||
|
||||
- (unsigned int)firstUnlaidCharacterIndex
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Using screen fonts
|
||||
//
|
||||
|
@ -490,6 +907,54 @@ fractionOfDistanceThroughGlyph: (float *)partialFraction
|
|||
- (void)drawGlyphsForGlyphRange: (NSRange)glyphRange
|
||||
atPoint: (NSPoint)containerOrigin
|
||||
{
|
||||
int firstPosition, lastPosition, i;
|
||||
|
||||
for (i=0;i<[fragmentRuns count];i++)
|
||||
{
|
||||
GSLineLayoutInfo *info = [fragmentRuns objectAtIndex:i];
|
||||
|
||||
/*
|
||||
NSLog(@"i: %d glyphRange: (%d, %d) lineFragmentRect: (%f, %f) (%f, %f)",
|
||||
i,
|
||||
info->glyphRange.location,
|
||||
info->glyphRange.length,
|
||||
info->lineFragmentRect.origin.x,
|
||||
info->lineFragmentRect.origin.y,
|
||||
info->lineFragmentRect.size.width,
|
||||
info->lineFragmentRect.size.height);
|
||||
*/
|
||||
}
|
||||
|
||||
firstPosition = [fragmentRuns indexOfObjectContainingLocation:glyphRange.location];
|
||||
lastPosition = [fragmentRuns
|
||||
indexOfObjectContainingLocation:(glyphRange.location+glyphRange.length-2)];
|
||||
|
||||
NSLog(@"glyphRange: (%d, %d) position1: %d position2: %d",
|
||||
glyphRange.location, glyphRange.length, firstPosition, lastPosition);
|
||||
|
||||
if (firstPosition >= 0)
|
||||
{
|
||||
if (lastPosition == -1)
|
||||
{
|
||||
lastPosition = [fragmentRuns count]; // FIXME
|
||||
NSLog(@"fixed lastPosition: %d", lastPosition);
|
||||
}
|
||||
|
||||
for (i = firstPosition; i < lastPosition; i++)
|
||||
{
|
||||
GSLineLayoutInfo *aLine = [fragmentRuns objectAtIndex:i];
|
||||
/*
|
||||
NSLog(@"drawRange: (%d, %d) inRect (%f, %f) (%f, %f)",
|
||||
aLine->glyphRange.location,
|
||||
aLine->glyphRange.length,
|
||||
aLine->lineFragmentRect.origin.x,
|
||||
aLine->lineFragmentRect.origin.y,
|
||||
aLine->lineFragmentRect.size.width,
|
||||
aLine->lineFragmentRect.size.height);
|
||||
*/
|
||||
[_textStorage drawRange:aLine->glyphRange inRect:aLine->lineFragmentRect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawUnderlineForGlyphRange: (NSRange)glyphRange
|
||||
|
@ -523,3 +988,238 @@ fractionOfDistanceThroughGlyph: (float *)partialFraction
|
|||
}
|
||||
|
||||
@end /* NSLayoutManager */
|
||||
|
||||
/* Thew methods laid out here are not correct, however the code they
|
||||
contain for the most part is. Therefore, my country and a handsome gift of
|
||||
Ghiradelli chocolate to he who puts all the pieces together :) */
|
||||
|
||||
@interface _GNUTextScanner:NSObject
|
||||
{ NSString *string;
|
||||
NSCharacterSet *set,*iSet;
|
||||
unsigned stringLength;
|
||||
NSRange activeRange;
|
||||
}
|
||||
+(_GNUTextScanner*) scannerWithString:(NSString*) aStr set:(NSCharacterSet*) aSet invertedSet:(NSCharacterSet*) anInvSet;
|
||||
-(void) setString:(NSString*) aString set:(NSCharacterSet*) aSet invertedSet:(NSCharacterSet*) anInvSet;
|
||||
-(NSRange) _scanCharactersInverted:(BOOL) inverted;
|
||||
-(NSRange) scanSetCharacters;
|
||||
-(NSRange) scanNonSetCharacters;
|
||||
-(BOOL) isAtEnd;
|
||||
-(unsigned) scanLocation;
|
||||
-(void) setScanLocation:(unsigned) aLoc;
|
||||
@end
|
||||
|
||||
@implementation NSLayoutManager (Private)
|
||||
- (int)_rebuildLayoutForTextContainer:(NSTextContainer *)aContainer
|
||||
startingAtGlyphIndex:(int)glyphIndex
|
||||
{
|
||||
NSSize cSize = [aContainer containerSize];
|
||||
float i = 0.0;
|
||||
NSMutableArray *lines = [NSMutableArray new];
|
||||
int indexToAdd;
|
||||
_GNUTextScanner *lineScanner;
|
||||
_GNUTextScanner *paragraphScanner;
|
||||
BOOL lastLineForContainerReached = NO;
|
||||
NSString *aString;
|
||||
int previousScanLocation;
|
||||
int endScanLocation;
|
||||
int startIndex;
|
||||
NSRect firstProposedRect;
|
||||
NSRect secondProposedRect;
|
||||
NSFont *default_font = [NSFont systemFontOfSize: 12.0];
|
||||
int widthOfString;
|
||||
NSSize rSize;
|
||||
NSCharacterSet *selectionParagraphGranularitySet = [NSCharacterSet characterSetWithCharactersInString:@"\n"];
|
||||
NSCharacterSet *selectionWordGranularitySet = [NSCharacterSet characterSetWithCharactersInString:@" "];
|
||||
NSCharacterSet *invSelectionWordGranularitySet = [selectionWordGranularitySet invertedSet];
|
||||
NSCharacterSet *invSelectionParagraphGranularitySet = [selectionParagraphGranularitySet invertedSet];
|
||||
NSRange paragraphRange;
|
||||
NSRange leadingSpacesRange;
|
||||
NSRange currentStringRange;
|
||||
NSRange trailingSpacesRange;
|
||||
NSRange leadingNlRange;
|
||||
NSSize lSize;
|
||||
float lineWidth = 0.0;
|
||||
float ourLines = 0.0;
|
||||
|
||||
NSLog(@"rebuilding Layout at index: %d.\n", glyphIndex);
|
||||
|
||||
// 1.) figure out how many glyphs we can fit in our container by
|
||||
// breaking up glyphs from the first unlaid out glyph and breaking it
|
||||
// into lines.
|
||||
//
|
||||
// 2.)
|
||||
// a.) set the range for the container
|
||||
// b.) for each line in step 1 we need to set a lineFragmentRect and
|
||||
// an origin point.
|
||||
|
||||
|
||||
// Here we go at part 1.
|
||||
|
||||
startIndex = glyphIndex;
|
||||
|
||||
// lineScanner = [NSScanner scannerWithString:[_textStorage string]];
|
||||
|
||||
paragraphScanner = [_GNUTextScanner scannerWithString:[_textStorage string]
|
||||
set:selectionParagraphGranularitySet invertedSet:invSelectionParagraphGranularitySet];
|
||||
|
||||
[paragraphScanner setScanLocation:startIndex];
|
||||
|
||||
NSLog(@"length of textStorage: %d", [[_textStorage string] length]);
|
||||
|
||||
// NSLog(@"buffer: %@", [_textStorage string]);
|
||||
|
||||
// This scanner eats one word at a time, we should have it imbeded in
|
||||
// another scanner that snacks on paragraphs (i.e. lines that end with
|
||||
// \n). Look in NSText.
|
||||
|
||||
while (![paragraphScanner isAtEnd])
|
||||
{
|
||||
// leadingNlRange=[paragraphScanner scanSetCharacters];
|
||||
paragraphRange = [paragraphScanner scanNonSetCharacters];
|
||||
leadingNlRange=[paragraphScanner scanSetCharacters];
|
||||
|
||||
if (leadingNlRange.length)
|
||||
currentStringRange = NSUnionRange (leadingNlRange,paragraphRange);
|
||||
|
||||
NSLog(@"paragraphRange: (%d, %d)", paragraphRange.location, paragraphRange.length);
|
||||
|
||||
NSLog(@"======> begin paragraph");
|
||||
|
||||
lineScanner = [_GNUTextScanner scannerWithString:[[_textStorage string] substringWithRange:paragraphRange]
|
||||
set:selectionWordGranularitySet invertedSet:invSelectionWordGranularitySet];
|
||||
|
||||
while(![lineScanner isAtEnd])
|
||||
{
|
||||
previousScanLocation = [lineScanner scanLocation];
|
||||
// snack next word
|
||||
leadingSpacesRange = [lineScanner scanSetCharacters]; // leading spaces: only first time
|
||||
currentStringRange = [lineScanner scanNonSetCharacters];
|
||||
trailingSpacesRange= [lineScanner scanSetCharacters];
|
||||
|
||||
if (leadingSpacesRange.length)
|
||||
currentStringRange = NSUnionRange (leadingSpacesRange,currentStringRange);
|
||||
if (trailingSpacesRange.length)
|
||||
currentStringRange = NSUnionRange (trailingSpacesRange,currentStringRange);
|
||||
|
||||
lSize = [_textStorage sizeRange:currentStringRange];
|
||||
|
||||
if (lineWidth + lSize.width < cSize.width)
|
||||
{
|
||||
if ([lineScanner isAtEnd])
|
||||
{
|
||||
NSLog(@"we are at end before finishing a line: %d.\n", [lineScanner scanLocation]);
|
||||
[lines addObject:[NSNumber numberWithInt:(int)[lineScanner scanLocation] + paragraphRange.location]];
|
||||
}
|
||||
|
||||
lineWidth += lSize.width;
|
||||
NSLog(@"lineWidth: %f", lineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ourLines > cSize.height)
|
||||
{
|
||||
lastLineForContainerReached = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
[lineScanner setScanLocation:previousScanLocation];
|
||||
indexToAdd = previousScanLocation + paragraphRange.location;
|
||||
ourLines += 14.0;
|
||||
lineWidth = 0;
|
||||
|
||||
NSLog(@"indexToAdd: %d\tourLines: %f", indexToAdd, ourLines);
|
||||
|
||||
[lines addObject:[NSNumber numberWithInt:indexToAdd]];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastLineForContainerReached)
|
||||
break;
|
||||
}
|
||||
|
||||
endScanLocation = [lineScanner scanLocation] + paragraphRange.location;
|
||||
|
||||
NSLog(@"endScanLocation: %d", endScanLocation);
|
||||
|
||||
// set this container for that glyphrange
|
||||
|
||||
[self setTextContainer:aContainer
|
||||
forGlyphRange:NSMakeRange(startIndex, endScanLocation - startIndex)];
|
||||
|
||||
NSLog(@"ok, move on to step 2.");
|
||||
|
||||
// step 2. break the lines up and assign rects to them.
|
||||
|
||||
for (i=0;i<[lines count];i++)
|
||||
{
|
||||
NSRect aRect, *bRect;
|
||||
float padding = [aContainer lineFragmentPadding];
|
||||
NSRange ourRange;
|
||||
|
||||
NSLog(@"\t\t===> %d", [[lines objectAtIndex:i] intValue]);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
ourRange = NSMakeRange (startIndex,
|
||||
[[lines objectAtIndex:i] intValue] - startIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ourRange = NSMakeRange ([[lines objectAtIndex:i-1] intValue],
|
||||
[[lines objectAtIndex:i] intValue] - [[lines objectAtIndex:i-1]
|
||||
intValue]);
|
||||
}
|
||||
|
||||
firstProposedRect = NSMakeRect (0, i * 14, cSize.width, 14);
|
||||
|
||||
// ask our textContainer to fix our lineFragment.
|
||||
|
||||
secondProposedRect = [aContainer lineFragmentRectForProposedRect:firstProposedRect
|
||||
sweepDirection: NULL
|
||||
movementDirection: NULL
|
||||
remainingRect: &bRect];
|
||||
|
||||
// set the line fragmentRect for this range.
|
||||
|
||||
[self setLineFragmentRect: secondProposedRect
|
||||
forGlyphRange: ourRange
|
||||
usedRect: aRect];
|
||||
|
||||
// set the location for this string to be 'show'ed.
|
||||
|
||||
[self setLocation:NSMakePoint(secondProposedRect.origin.x + padding,
|
||||
secondProposedRect.origin.y + padding)
|
||||
forStartOfGlyphRange: ourRange];
|
||||
}
|
||||
|
||||
// bloody hack.
|
||||
// if (moreText)
|
||||
// [delegate layoutManager:self
|
||||
// didCompleteLayoutForTextContainer:[textContainers objectAtIndex:i]
|
||||
// atEnd:NO];
|
||||
// else
|
||||
// [delegate layoutManager:self
|
||||
// didCompleteLayoutForTextContainer:[textContainers objectAtIndex:i]
|
||||
// atEnd:YES];
|
||||
|
||||
[lines release];
|
||||
|
||||
return endScanLocation;
|
||||
}
|
||||
|
||||
- (void)_doLayout
|
||||
{
|
||||
int i;
|
||||
BOOL moreText;
|
||||
int gIndex = 0;
|
||||
|
||||
NSLog(@"doLayout called.\n");
|
||||
|
||||
for (i=0;i<[_textContainers count];i++)
|
||||
{
|
||||
gIndex = [self _rebuildLayoutForTextContainer:[_textContainers objectAtIndex:i]
|
||||
startingAtGlyphIndex:gIndex];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue