Some Improvements on formating

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@6502 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Fred Kiefer 2000-04-23 22:31:25 +00:00
parent a0f56f73f1
commit bb9c6f7e29

View file

@ -55,11 +55,11 @@
#include <AppKit/NSParagraphStyle.h> #include <AppKit/NSParagraphStyle.h>
#include <AppKit/NSPasteboard.h> #include <AppKit/NSPasteboard.h>
#include <AppKit/NSSpellChecker.h> #include <AppKit/NSSpellChecker.h>
#include <AppKit/NSClipView.h>
#include <AppKit/NSDragging.h> #include <AppKit/NSDragging.h>
#include <AppKit/NSStringDrawing.h> #include <AppKit/NSStringDrawing.h>
#include <AppKit/NSTextStorage.h> #include <AppKit/NSTextStorage.h>
#include <AppKit/NSTextContainer.h>
#include <Foundation/NSNotification.h> #include <Foundation/NSNotification.h>
#include <Foundation/NSArchiver.h> #include <Foundation/NSArchiver.h>
@ -69,22 +69,16 @@
#define HUGE 1e99 #define HUGE 1e99
enum {
NSBackspaceKey = 8,
NSCarriageReturnKey = 13,
NSDeleteKey = 0x7f,
NSBacktabKey = 25
};
static NSCharacterSet *selectionWordGranularitySet; static NSCharacterSet *selectionWordGranularitySet;
static NSCharacterSet *selectionParagraphGranularitySet; static NSCharacterSet *selectionParagraphGranularitySet;
static NSCharacterSet *invSelectionWordGranularitySet;
static NSCharacterSet *invSelectionParagraphGranularitySet;
@interface _GNULineLayoutInfo: NSObject @interface _GNULineLayoutInfo: NSObject
{ {
@public @public
NSRange lineRange; NSRange lineRange;
NSRect lineRect; NSRect lineRect;
float drawingOffset;
unsigned type; unsigned type;
} }
@ -97,17 +91,14 @@ typedef enum
+ (id) lineLayoutWithRange: (NSRange)aRange + (id) lineLayoutWithRange: (NSRange)aRange
rect: (NSRect)aRect rect: (NSRect)aRect
drawingOffset: (float)anOffset
type: (unsigned)aType; type: (unsigned)aType;
- (NSRange) lineRange; - (NSRange) lineRange;
- (NSRect) lineRect; - (NSRect) lineRect;
- (float) drawingOffset;
- (unsigned) type; - (unsigned) type;
- (void) setLineRange: (NSRange)aRange; - (void) setLineRange: (NSRange)aRange;
- (void) setLineRect: (NSRect)aRect; - (void) setLineRect: (NSRect)aRect;
- (void) setDrawingOffset: (float)anOffset;
- (void) setType: (unsigned)aType; - (void) setType: (unsigned)aType;
- (NSString*) description; - (NSString*) description;
@ -115,17 +106,15 @@ typedef enum
@implementation _GNULineLayoutInfo @implementation _GNULineLayoutInfo
+ (id) lineLayoutWithRange: (NSRange)aRange + (_GNULineLayoutInfo *) lineLayoutWithRange: (NSRange)aRange
rect: (NSRect)aRect rect: (NSRect)aRect
drawingOffset: (float)anOffset
type: (unsigned)aType type: (unsigned)aType
{ {
id ret = AUTORELEASE([_GNULineLayoutInfo new]); _GNULineLayoutInfo *ret = AUTORELEASE([_GNULineLayoutInfo new]);
[ret setLineRange: aRange]; ret->lineRange = aRange;
[ret setLineRect: aRect]; ret->lineRect =aRect;
[ret setDrawingOffset: anOffset]; ret->type = aType;
[ret setType: aType];
return ret; return ret;
} }
@ -144,11 +133,6 @@ typedef enum
return lineRect; return lineRect;
} }
- (float) drawingOffset
{
return drawingOffset;
}
- (void) setLineRange: (NSRange)aRange - (void) setLineRange: (NSRange)aRange
{ {
lineRange = aRange; lineRange = aRange;
@ -156,17 +140,9 @@ typedef enum
- (void) setLineRect: (NSRect)aRect - (void) setLineRect: (NSRect)aRect
{ {
//FIXME, line up textEditor with how text in text cell will be placed.
// aRect.origin.y += 2;
lineRect = aRect; lineRect = aRect;
} }
- (void) setDrawingOffset: (float)anOffset
{
drawingOffset = anOffset;
}
- (void) setType: (unsigned)aType - (void) setType: (unsigned)aType
{ {
type = aType; type = aType;
@ -302,7 +278,20 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
} }
- (id) initForText: (NSText*) aTextHolder; - (id) initForText: (NSText*) aTextHolder;
- (NSTextStorage*) textStorage;
- (void) setTextStorage: (NSTextStorage*) aTextStorage; - (void) setTextStorage: (NSTextStorage*) aTextStorage;
- (void)textStorage:(NSTextStorage *)aTextStorage
edited:(unsigned int)mask
range:(NSRange)range
changeInLength:(int)lengthChange
invalidatedRange:(NSRange)invalidatedCharRange;
/*
- (NSRect *) rectArrayForCharacterRange: (NSRange)charRange
withinSelectedCharacterRange: (NSRange)selCharRange
inTextContainer: (NSTextContainer *)aTextContainer
rectCount: (unsigned int *)rectCount;
*/
- (NSSize) _sizeOfRange: (NSRange) range; - (NSSize) _sizeOfRange: (NSRange) range;
- (NSRect) _textBounds; - (NSRect) _textBounds;
@ -318,16 +307,9 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
- (NSRange) characterRangeForLineLayoutRange: (NSRange) aRange; - (NSRange) characterRangeForLineLayoutRange: (NSRange) aRange;
- (void) setNeedsDisplayForLineRange: (NSRange) redrawLineRange; - (void) setNeedsDisplayForLineRange: (NSRange) redrawLineRange;
- (void)textStorage:(NSTextStorage *)aTextStorage
edited:(unsigned int)mask
range:(NSRange)range
changeInLength:(int)lengthChange
invalidatedRange:(NSRange)invalidatedCharRange;
- (int) rebuildLineLayoutInformation;
// override for special layout of text // override for special layout of text
- (int) rebuildLineLayoutInformationStartingAtLine: (int)aLine - (NSRange) rebuildForRange: (NSRange)aRange
delta: (int)insertionDelta delta: (int)insertionDelta;
actualLine: (int)insertionLine;
// low level, override but never invoke (use setNeedsDisplayForLineRange:) // low level, override but never invoke (use setNeedsDisplayForLineRange:)
- (void) drawLinesInLineRange: (NSRange)aRange; - (void) drawLinesInLineRange: (NSRange)aRange;
- (NSRange) drawRectCharacters: (NSRect)rect; - (NSRange) drawRectCharacters: (NSRect)rect;
@ -342,8 +324,22 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
- (void) setTextStorage: (NSTextStorage*)aTextStorage - (void) setTextStorage: (NSTextStorage*)aTextStorage
{ {
unsigned length = [aTextStorage length];
NSRange aRange = NSMakeRange(0, length);
ASSIGN(_textStorage, aTextStorage); ASSIGN(_textStorage, aTextStorage);
[self rebuildLineLayoutInformation]; // force complete re - layout
RELEASE(lineLayoutInformation);
lineLayoutInformation = nil;
[self textStorage: aTextStorage
edited: NSTextStorageEditedCharacters | NSTextStorageEditedAttributes
range: aRange
changeInLength: length
invalidatedRange: aRange];
}
- (NSTextStorage*) textStorage
{
return _textStorage;
} }
- (NSSize) _sizeOfRange: (NSRange)aRange - (NSSize) _sizeOfRange: (NSRange)aRange
@ -375,27 +371,16 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
return NSZeroRect; return NSZeroRect;
} }
- (int) lineLayoutIndexForCharacterIndex: (unsigned)anIndex - (NSRect) frame
{ {
NSEnumerator *lineEnum; NSRect aRect = [_textHolder frame];
_GNULineLayoutInfo *currentInfo;
if ([lineLayoutInformation count] if ([_textHolder isHorizontallyResizable])
&& anIndex >= NSMaxRange ([[lineLayoutInformation lastObject] lineRange])) aRect.size.width = HUGE;
return [lineLayoutInformation count] - 1; if ([_textHolder isVerticallyResizable])
aRect.size.height = HUGE;
// should use a faster search here return aRect;
for ((lineEnum = [lineLayoutInformation objectEnumerator]);
(currentInfo = [lineEnum nextObject]);)
{
NSRange lineRange = [currentInfo lineRange];
if (lineRange.location<= anIndex
&& (anIndex <= NSMaxRange (lineRange)
- ([currentInfo type] == LineLayoutInfoType_Paragraph? 1: 0)))
return [lineLayoutInformation indexOfObject: currentInfo];
}
return 0;
} }
- (NSRange) characterRangeForLineLayoutRange: (NSRange)aRange; - (NSRange) characterRangeForLineLayoutRange: (NSRange)aRange;
@ -418,7 +403,7 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
currentInfo = [lineLayoutInformation objectAtIndex: endLine]; currentInfo = [lineLayoutInformation objectAtIndex: endLine];
endIndex = NSMaxRange([currentInfo lineRange]); endIndex = NSMaxRange([currentInfo lineRange]);
return MakeRangeFromAbs(startIndex, endIndex); return NSMakeRange(startIndex, endIndex - startIndex);
} }
- (NSRange) characterRangeForBoundingRect: (NSRect)boundsRect - (NSRange) characterRangeForBoundingRect: (NSRect)boundsRect
@ -431,61 +416,172 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
return NSMakeRange (0, 0); return NSMakeRange (0, 0);
} }
- (unsigned) characterIndexForPoint: (NSPoint)point - (unsigned) lineLayoutIndexForPoint: (NSPoint)point
{ {
int i; int i;
NSEnumerator *lineEnum; int min = 0;
_GNULineLayoutInfo *currentInfo; int max = MAX(0, [lineLayoutInformation count] - 1);
float y = point.y;
float fmin = NSMinY([[lineLayoutInformation objectAtIndex: 0] lineRect]);
float fmax = NSMaxY([[lineLayoutInformation lastObject] lineRect]);
NSRect rect;
if (point.y >= NSMaxY([[lineLayoutInformation lastObject] lineRect])) if (y >= fmax)
return [_textStorage length]; return max;
point.x = MAX(0,point.x); if (y <= fmin)
point.y = MAX(0,point.y); return min;
for (i = 0, (lineEnum = [lineLayoutInformation objectEnumerator]); // this should give a good starting index for binary search
(currentInfo = [lineEnum nextObject]); i = (int)((max - min) * (y - fmin) / (fmax - fmin)) + min;
i++) while (min < max)
// this loop holds some optimization potential (linear search)
{ {
NSRect rect = [currentInfo lineRect]; _GNULineLayoutInfo *ci = [lineLayoutInformation objectAtIndex: i];
if (NSMaxY(rect)>= point.y rect = [ci lineRect];
&& rect.origin.y<point.y
&& rect.origin.x< point.x
&& point.x >= NSMaxX(rect))
return NSMaxRange ([currentInfo lineRange]);
if (NSPointInRect (point, rect)) if (NSMaxY(rect) < y)
{ {
int retPos = 0; min = i + 1;
NSRange range = [currentInfo lineRange]; i = (max + min) / 2;
continue;
for (retPos = range.location; retPos<= NSMaxRange(range); retPos++) }
// this loop holds some optimization potential (linear search) if (NSMinY(rect) > y)
{ {
if ([self _sizeOfRange: max = i - 1;
NSMakeRange (range.location, i = (max + min) / 2;
retPos - range.location)].width continue;
>= point.x)
return MAX (0, retPos - 1);
}
return range.location;
} }
}
return 0; // As the newline char generates its own lineLayoutinfo box
// there may be two in one line, we have to check for this
if ((NSMinX(rect) > point.x) && (i > 0) &&
([ci type] == LineLayoutInfoType_Paragraph))
{
_GNULineLayoutInfo *bi = [lineLayoutInformation objectAtIndex: i - 1];
rect = [bi lineRect];
if (NSPointInRect(point, rect))
return i - 1;
}
if ((NSMaxX(rect) < point.x) && (i < [lineLayoutInformation count] - 1) &&
([ci type] == LineLayoutInfoType_Text))
{
_GNULineLayoutInfo *bi = [lineLayoutInformation objectAtIndex: i + 1];
rect = [bi lineRect];
if (NSPointInRect(point, rect))
return i + 1;
}
return i;
}
return min;
}
- (unsigned) characterIndexForPoint: (NSPoint)point
{
_GNULineLayoutInfo *currentInfo = [lineLayoutInformation
objectAtIndex:
[self lineLayoutIndexForPoint: point]];
NSRect rect = [currentInfo lineRect];
NSRange range = [currentInfo lineRange];
int i;
int min = range.location;
int max = NSMaxRange(range);
float x = point.x;
float fmin = rect.origin.x;
float fmax = NSMaxX(rect);
float w1, w2;
if (x <= fmin)
return MAX(0, min - 1);
if (x >= fmax)
return MAX(0, max - 1);
if (range.length == 1)
return min;
// this should give a good starting index for binary search
i = (int)((max - min) * (x - fmin) / (fmax - fmin)) + min;
while (min < max)
{
w1 = [self _sizeOfRange:
NSMakeRange (range.location,
i - range.location)].width + fmin;
if (i > range.location)
w2 = [self _sizeOfRange:
NSMakeRange (range.location,
i-1 - range.location)].width + fmin;
else
w2 = fmin;
if (w1 < x)
{
min = i + 1;
i = (max + min) / 2;
continue;
}
if (w2 > x)
{
max = i - 1;
i = (max + min) / 2;
continue;
}
return MAX(0, i-1);
}
return MAX(0, min - 1);
}
- (int) lineLayoutIndexForCharacterIndex: (unsigned)anIndex
{
int i;
int min = 0;
int max = MAX(0, [lineLayoutInformation count] - 1);
unsigned y = anIndex;
unsigned fmin = [[lineLayoutInformation objectAtIndex: 0] lineRange].location;
unsigned fmax = NSMaxRange([[lineLayoutInformation lastObject] lineRange]);
NSRange range;
if (y >= fmax)
return max;
if (y <= fmin)
return min;
// this should give a good starting index for binary search
i = (int)((max - min) * (y - fmin) / (fmax - fmin)) + min;
while (min < max)
{
_GNULineLayoutInfo *ci = [lineLayoutInformation objectAtIndex: i];
range = [ci lineRange];
if (NSMaxRange(range) <= y)
{
min = i + 1;
i = (max + min) / 2;
continue;
}
if (range.location > y)
{
max = i - 1;
i = (max + min) / 2;
continue;
}
// Do we need a special treatment for paragraph infos?
return i;
}
return min;
} }
// rect to the end of line // rect to the end of line
- (NSRect) rectForCharacterIndex: (unsigned)index - (NSRect) rectForCharacterIndex: (unsigned)index
{ {
int i; float maxWidth = [self frame].size.width;
float maxWidth = [_textHolder frame].size.width;
NSEnumerator *lineEnum;
_GNULineLayoutInfo *currentInfo; _GNULineLayoutInfo *currentInfo;
unsigned start;
NSRect rect;
float x;
if (![lineLayoutInformation count]) if (![_textStorage length])
{ {
return NSMakeRect (0, 0, maxWidth, return NSMakeRect (0, 0, maxWidth,
[self _sizeOfRange: NSMakeRange(0,1)].height); [self _sizeOfRange: NSMakeRange(0,1)].height);
@ -504,70 +600,22 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
rect.size.height); rect.size.height);
} }
for (i = 0, (lineEnum = [lineLayoutInformation objectEnumerator]);
(currentInfo = [lineEnum nextObject]); i++)
{
NSRange range = [currentInfo lineRange];
if (NSLocationInRange (index, range))
{
NSRect rect = [currentInfo lineRect];
NSSize stringSize
= [self _sizeOfRange: MakeRangeFromAbs (range.location, index)];
float x = rect.origin.x + stringSize.width;
return NSMakeRect (x, rect.origin.y, NSMaxX (rect) - x, currentInfo = [lineLayoutInformation
rect.size.height); objectAtIndex: [self lineLayoutIndexForCharacterIndex:
} index]];
} start = [currentInfo lineRange].location;
rect = [currentInfo lineRect];
return NSZeroRect; x = rect.origin.x + [self _sizeOfRange: MakeRangeFromAbs(start,
} index)].width;
- (unsigned) lineLayoutIndexForPoint: (NSPoint)point return NSMakeRect (x, rect.origin.y, NSMaxX (rect) - x,
{ rect.size.height);
int i;
NSEnumerator *lineEnum;
_GNULineLayoutInfo *currentInfo;
if (point.y >= NSMaxY ([[lineLayoutInformation lastObject] lineRect]))
return [lineLayoutInformation count] - 1;
point.x = MAX (0, point.x);
point.y = MAX (0, point.y);
for (i = 0, (lineEnum = [lineLayoutInformation objectEnumerator]);
(currentInfo = [lineEnum nextObject]); i++)
{
NSRect rect = [currentInfo lineRect];
if (NSMaxY(rect) > point.y
&& rect.origin.y <= point.y
&& rect.origin.x < point.x
&& point.x >= NSMaxX (rect))
return [lineLayoutInformation indexOfObject: currentInfo];
if (NSPointInRect (point, rect))
{
// this loop holds some optimization potential (linear search)
int retPos = 0;
NSRange range = [currentInfo lineRange];
// this loop holds some optimization potential (linear search)
for (retPos = range.location; retPos<= NSMaxRange (range); retPos++)
{
if ([self _sizeOfRange:
NSMakeRange (range.location,
retPos - range.location)].width
>= point.x)
return [lineLayoutInformation indexOfObject: currentInfo];
}
return [lineLayoutInformation indexOfObject: currentInfo];
}
}
return 0;
} }
- (void) setNeedsDisplayForLineRange: (NSRange)redrawLineRange - (void) setNeedsDisplayForLineRange: (NSRange)redrawLineRange
{ {
NSRect myFrame = [_textHolder frame]; NSRect myFrame = [self frame];
float maxWidth = myFrame.size.width; float maxWidth = myFrame.size.width;
if ([lineLayoutInformation count] if ([lineLayoutInformation count]
@ -622,14 +670,11 @@ static NSRange MakeRangeFromAbs (int a1,int a2) // not the same as NSMakeRange!
changeInLength:(int)delta changeInLength:(int)delta
invalidatedRange:(NSRange)invalidatedCharRange; invalidatedRange:(NSRange)invalidatedCharRange;
{ {
int start = [self lineLayoutIndexForCharacterIndex: aRange.location]; NSRange lineRange;
int count;
int origLineIndex = MAX(0, start - 1);
count = [self rebuildLineLayoutInformationStartingAtLine: origLineIndex lineRange = [self rebuildForRange: aRange
delta: delta delta: delta];
actualLine: start]; [self setNeedsDisplayForLineRange: lineRange];
[self setNeedsDisplayForLineRange: NSMakeRange(origLineIndex, MAX(1, count))];
} }
// internal method <!> range is currently not passed as absolute // internal method <!> range is currently not passed as absolute
@ -644,33 +689,30 @@ verticalDisplacement: (float*)verticalDisplacement
{ {
NSSize advanceSize = [self _sizeOfRange: NSSize advanceSize = [self _sizeOfRange:
NSMakeRange (startingLineCharIndex, 1)]; NSMakeRange (startingLineCharIndex, 1)];
int count = aRange.length,charIndex; int count = aRange.length;
_GNULineLayoutInfo *thisInfo,*ghostInfo = nil; int charIndex;
_GNULineLayoutInfo *ghostInfo = nil;
(*didShift) = NO; (*didShift) = NO;
for (charIndex = aRange.location; --count >= 0; charIndex++) for (charIndex = aRange.location; --count >= 0; charIndex++)
{ {
NSRect currentLineRect;
currentLineRect = NSMakeRect (aPointP ->x, aPointP ->y,
width - aPointP ->x, advanceSize.height);
[anArray addObject: [anArray addObject:
thisInfo = [_GNULineLayoutInfo [_GNULineLayoutInfo
lineLayoutWithRange: lineLayoutWithRange:
NSMakeRange (startingLineCharIndex, 1) NSMakeRange (startingLineCharIndex, 1)
rect: currentLineRect rect: NSMakeRect (aPointP->x, aPointP->y,
drawingOffset: 0 width - aPointP->x, advanceSize.height)
type: LineLayoutInfoType_Paragraph]]; type: LineLayoutInfoType_Paragraph]];
startingLineCharIndex++; startingLineCharIndex++;
aPointP ->x = 0; aPointP->x = 0;
aPointP ->y += advanceSize.height; aPointP->y += advanceSize.height;
if (prevArrayEnum && !(ghostInfo = [prevArrayEnum nextObject])) if (prevArrayEnum && !(ghostInfo = [prevArrayEnum nextObject]))
prevArrayEnum = nil; prevArrayEnum = nil;
if (ghostInfo && ([thisInfo type] != [ghostInfo type])) if (ghostInfo && ([ghostInfo type] != LineLayoutInfoType_Paragraph))
{ {
_GNULineLayoutInfo *prevInfo = [prevArrayEnum previousObject]; _GNULineLayoutInfo *prevInfo = [prevArrayEnum previousObject];
prevArrayEnum = nil; prevArrayEnum = nil;
@ -681,13 +723,11 @@ verticalDisplacement: (float*)verticalDisplacement
} }
// private helper function // private helper function
static unsigned - (unsigned) _relocLayoutArray: (NSArray*)ghostArray
_relocLayoutArray (NSMutableArray *lineLayoutInformation, atLine: (int) aLine
NSArray *ghostArray, offset: (int) relocOffset
int aLine, lineTrift: (int) rebuildLineDrift
int relocOffset, floatTrift: (float) yReloc
int rebuildLineDrift,
float yReloc)
{ {
// lines actually updated (optimized drawing) // lines actually updated (optimized drawing)
unsigned ret = [lineLayoutInformation count] - aLine; unsigned ret = [lineLayoutInformation count] - aLine;
@ -741,35 +781,34 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
// returns count of lines actually updated // returns count of lines actually updated
// <!> detachNewThreadSelector: selector toTarget: target withObject: argument; // <!> detachNewThreadSelector: selector toTarget: target withObject: argument;
- (int) rebuildLineLayoutInformationStartingAtLine: (int)aLine - (NSRange) rebuildForRange: (NSRange)aRange
delta: (int)insertionDelta delta: (int)insertionDelta
actualLine: (int)insertionLineIndex
{ {
NSPoint drawingPoint = NSZeroPoint; int aLine = 0;
NSScanner *pScanner; int insertionLineIndex = 0;
float width = [_textHolder frame].size.width; unsigned oldMax = NSMaxRange(aRange);
unsigned startingIndex = 0; unsigned newMax = oldMax + insertionDelta;
unsigned currentLineIndex; NSPoint drawingPoint = NSZeroPoint;
NSArray *ghostArray; // for optimization detection NSScanner *pScanner;
float width = [self frame].size.width;
unsigned startingIndex = 0;
unsigned currentLineIndex;
// for optimization detection
NSArray *ghostArray;
_GNUSeekableArrayEnumerator *prevArrayEnum; _GNUSeekableArrayEnumerator *prevArrayEnum;
NSCharacterSet *invSelectionWordGranularitySet
= [selectionWordGranularitySet invertedSet];
NSCharacterSet *invSelectionParagraphGranularitySet
= [selectionParagraphGranularitySet invertedSet];
NSString *parsedString; NSString *parsedString;
BOOL isHorizontallyResizable = [_textHolder isHorizontallyResizable];
int lineDriftOffset = 0, rebuildLineDrift = 0; int lineDriftOffset = 0, rebuildLineDrift = 0;
BOOL frameshiftCorrection = NO, nlDidShift = NO, enforceOpti = NO; BOOL frameshiftCorrection = NO, nlDidShift = NO;
float yDisplacement = 0; float yDisplacement = 0;
// sanity check that it is possible to do the layout // sanity check that it is possible to do the layout
if (width == 0.0) if (width == 0.0)
{ {
NSLog(@"NSText formatting with empty frame"); NSLog(@"NSText formatting with empty frame");
return 0; return NSMakeRange(0,0);
} }
if (!lineLayoutInformation) if (lineLayoutInformation == nil)
{ {
lineLayoutInformation = [[NSMutableArray alloc] init]; lineLayoutInformation = [[NSMutableArray alloc] init];
aLine = 0; aLine = 0;
@ -778,6 +817,10 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
} }
else else
{ {
insertionLineIndex = [self lineLayoutIndexForCharacterIndex:
aRange.location];
aLine = MAX(0, insertionLineIndex - 1);
// remember old array for optimization purposes // remember old array for optimization purposes
ghostArray = [lineLayoutInformation ghostArray = [lineLayoutInformation
subarrayWithRange: subarrayWithRange:
@ -788,16 +831,18 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
if (aLine) if (aLine)
{ {
_GNULineLayoutInfo *lastValidLineInfo; _GNULineLayoutInfo *lastValidLineInfo = [lineLayoutInformation
objectAtIndex: aLine - 1];
NSRect aRect = [lastValidLineInfo lineRect];
lastValidLineInfo = [lineLayoutInformation objectAtIndex: aLine - 1];
drawingPoint = [lastValidLineInfo lineRect].origin;
drawingPoint.y += [lastValidLineInfo lineRect].size.height;
startingIndex = NSMaxRange([lastValidLineInfo lineRange]); startingIndex = NSMaxRange([lastValidLineInfo lineRange]);
drawingPoint = aRect.origin;
drawingPoint.y += aRect.size.height;
if ([lastValidLineInfo type] == LineLayoutInfoType_Paragraph) if ([lastValidLineInfo type] == LineLayoutInfoType_Paragraph)
{ {
drawingPoint.x = 0; drawingPoint.x = 0;
} }
// keep paragraph - terminating space on same line as paragraph // keep paragraph - terminating space on same line as paragraph
if ((((int)[lineLayoutInformation count]) - 1) >= aLine) if ((((int)[lineLayoutInformation count]) - 1) >= aLine)
{ {
@ -806,7 +851,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
NSRect anchorRect = [anchorLine lineRect]; NSRect anchorRect = [anchorLine lineRect];
if (anchorRect.origin.x > drawingPoint.x if (anchorRect.origin.x > drawingPoint.x
&& [lastValidLineInfo lineRect].origin.y == anchorRect.origin.y) && aRect.origin.y == anchorRect.origin.y)
{ {
drawingPoint = anchorRect.origin; drawingPoint = anchorRect.origin;
} }
@ -818,6 +863,18 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
NSMakeRange (aLine, [lineLayoutInformation count] - aLine)]; NSMakeRange (aLine, [lineLayoutInformation count] - aLine)];
} }
if (![_textStorage length])
{
// If there is no text add one empty box
[lineLayoutInformation
addObject: [_GNULineLayoutInfo
lineLayoutWithRange: NSMakeRange (0, 0)
rect: NSMakeRect (0, 0, 0, 0)
type: LineLayoutInfoType_Text]];
return NSMakeRange(0,0);
}
currentLineIndex = aLine; currentLineIndex = aLine;
// each paragraph // each paragraph
@ -836,11 +893,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
leadingNlRange leadingNlRange
= scanRange(pScanner, selectionParagraphGranularitySet); = scanRange(pScanner, selectionParagraphGranularitySet);
paragraphRange
= scanRange(pScanner, invSelectionParagraphGranularitySet);
trailingNlRange
= scanRange(pScanner, selectionParagraphGranularitySet);
if (leadingNlRange.length > 0) if (leadingNlRange.length > 0)
{ {
[self addNewlines: leadingNlRange [self addNewlines: leadingNlRange
@ -872,6 +924,8 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
} }
// each line // each line
paragraphRange
= scanRange(pScanner, invSelectionParagraphGranularitySet);
paragraph = [parsedString substringWithRange: paragraphRange]; paragraph = [parsedString substringWithRange: paragraphRange];
lScanner = [NSScanner scannerWithString: paragraph]; lScanner = [NSScanner scannerWithString: paragraph];
[lScanner setCharactersToBeSkipped: nil]; [lScanner setCharactersToBeSkipped: nil];
@ -922,7 +976,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
// handle case where single word is broader than width // handle case where single word is broader than width
// (buckle word) <!> unfinished and untested // (buckle word) <!> unfinished and untested
// for richText (absolute position see above) // for richText (absolute position see above)
if (!isHorizontallyResizable && advanceSize.width >= width) if (advanceSize.width >= width)
{ {
if (isBuckled) if (isBuckled)
{ {
@ -958,8 +1012,8 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
// end of line -> word wrap // end of line -> word wrap
// >= : wichtig för abknicken (isBuckled) // >= : wichtig för abknicken (isBuckled)
if (!isHorizontallyResizable if (currentLineRect.size.width >= width || isBuckled)
&& (currentLineRect.size.width >= width || isBuckled)) { {
_GNULineLayoutInfo *ghostInfo = nil, *thisInfo; _GNULineLayoutInfo *ghostInfo = nil, *thisInfo;
// undo layout of last word // undo layout of last word
@ -977,7 +1031,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
NSMakeRange (startingLineCharIndex, NSMakeRange (startingLineCharIndex,
scannerPosition - localLineStartIndex) scannerPosition - localLineStartIndex)
rect: currentLineRect rect: currentLineRect
drawingOffset: 0
type: LineLayoutInfoType_Text])]; type: LineLayoutInfoType_Text])];
currentLineIndex++; currentLineIndex++;
@ -1035,15 +1088,13 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
if ((currentLineIndex - 1 > insertionLineIndex if ((currentLineIndex - 1 > insertionLineIndex
&& !inBuckling && !isBuckled) && !inBuckling && !isBuckled)
&& (!(lineDriftOffset - insertionDelta) && (!(lineDriftOffset - insertionDelta)
|| (nlDidShift && !lineDriftOffset) || (nlDidShift && !lineDriftOffset)))
|| enforceOpti))
{ {
unsigned erg = _relocLayoutArray (lineLayoutInformation, unsigned erg = [self _relocLayoutArray: ghostArray
ghostArray, atLine: aLine
aLine, offset: insertionDelta
insertionDelta, lineTrift: rebuildLineDrift
rebuildLineDrift, floatTrift: yDisplacement];
yDisplacement);
// y displacement: redisplay all remaining lines // y displacement: redisplay all remaining lines
if (frameshiftCorrection) if (frameshiftCorrection)
@ -1057,7 +1108,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
#if 0 #if 0
NSLog(@"opti for: %d",erg); NSLog(@"opti for: %d",erg);
#endif #endif
return erg; return NSMakeRange(aLine, MAX(1, erg));
} }
} }
// end: optimization stuff-------------------------- // end: optimization stuff--------------------------
@ -1077,7 +1128,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
NSMakeRange (startingLineCharIndex, NSMakeRange (startingLineCharIndex,
scannerPosition - localLineStartIndex) scannerPosition - localLineStartIndex)
rect: currentLineRect rect: currentLineRect
drawingOffset: 0
type: LineLayoutInfoType_Text])]; type: LineLayoutInfoType_Text])];
currentLineIndex++; currentLineIndex++;
startingLineCharIndex = NSMaxRange ([thisInfo lineRange]); startingLineCharIndex = NSMaxRange ([thisInfo lineRange]);
@ -1136,6 +1186,8 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
} }
} }
// add the trailing newlines of current paragraph if any // add the trailing newlines of current paragraph if any
trailingNlRange
= scanRange(pScanner, selectionParagraphGranularitySet);
if (trailingNlRange.length) if (trailingNlRange.length)
{ {
[self addNewlines: trailingNlRange [self addNewlines: trailingNlRange
@ -1165,21 +1217,10 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
} }
// lines actually updated (optimized drawing) // lines actually updated (optimized drawing)
return [lineLayoutInformation count] - aLine; return NSMakeRange(aLine, MAX(1, [lineLayoutInformation count] - aLine));
} }
// end: central line formatting method------------------------------------ // end: central line formatting method------------------------------------
- (int) rebuildLineLayoutInformation
{
// force complete re - layout
RELEASE(lineLayoutInformation);
lineLayoutInformation = nil;
return [self rebuildLineLayoutInformationStartingAtLine: 0
delta: 0
actualLine: 0];
}
// relies on lineLayoutInformation // relies on lineLayoutInformation
- (void) drawLinesInLineRange: (NSRange)aRange; - (void) drawLinesInLineRange: (NSRange)aRange;
{ {
@ -1331,6 +1372,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
[_textStorage beginEditing]; [_textStorage beginEditing];
[_textStorage replaceCharactersInRange: aRange withString: aString]; [_textStorage replaceCharactersInRange: aRange withString: aString];
[_textStorage endEditing]; [_textStorage endEditing];
[self sizeToFit];
} }
- (void) setString: (NSString*)aString - (void) setString: (NSString*)aString
@ -1600,6 +1642,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
NSData *data = nil; NSData *data = nil;
if (font != nil) if (font != nil)
// FIXME: Should use diverent format here
data = [NSArchiver archivedDataWithRootObject: font]; data = [NSArchiver archivedDataWithRootObject: font];
if (data != nil) if (data != nil)
@ -2330,7 +2373,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
{ {
unsigned cursorIndex; unsigned cursorIndex;
NSPoint cursorPoint; NSPoint cursorPoint;
NSRange oldRange = _selected_range;
if (_tf.is_field_editor) if (_tf.is_field_editor)
{ {
@ -2355,16 +2397,12 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
[self setSelectedRange: [self selectionRangeForProposedRange: [self setSelectedRange: [self selectionRangeForProposedRange:
NSMakeRange (cursorIndex, 0) NSMakeRange (cursorIndex, 0)
granularity: NSSelectByCharacter]]; granularity: NSSelectByCharacter]];
// FIXME: We redisplay the line the cursor was on.
[self setNeedsDisplayInRect: [self rectForCharacterIndex:
oldRange.location]];
} }
- (void) moveDown: (id) sender - (void) moveDown: (id) sender
{ {
unsigned cursorIndex; unsigned cursorIndex;
NSRect cursorRect; NSRect cursorRect;
NSRange oldRange = _selected_range;
if (_tf.is_field_editor) if (_tf.is_field_editor)
{ {
@ -2389,9 +2427,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
[self setSelectedRange: [self selectionRangeForProposedRange: [self setSelectedRange: [self selectionRangeForProposedRange:
NSMakeRange (cursorIndex, 0) NSMakeRange (cursorIndex, 0)
granularity: NSSelectByCharacter]]; granularity: NSSelectByCharacter]];
// FIXME: We redisplay the line the cursor was on
[self setNeedsDisplayInRect: [self rectForCharacterIndex:
oldRange.location]];
} }
- (void) moveLeft: (id) sender - (void) moveLeft: (id) sender
@ -2406,9 +2441,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
granularity: NSSelectByCharacter]]; granularity: NSSelectByCharacter]];
_currentCursor.x = [self rectForCharacterIndex: _currentCursor.x = [self rectForCharacterIndex:
_selected_range.location].origin.x; _selected_range.location].origin.x;
// FIXME: We redisplay the line the cursor is on.
[self setNeedsDisplayInRect: [self rectForCharacterIndex:
_selected_range.location + 1]];
} }
- (void) moveRight: (id) sender - (void) moveRight: (id) sender
@ -2424,9 +2456,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
granularity: NSSelectByCharacter]]; granularity: NSSelectByCharacter]];
_currentCursor.x = [self rectForCharacterIndex: _currentCursor.x = [self rectForCharacterIndex:
_selected_range.location].origin.x; _selected_range.location].origin.x;
// FIXME: We redisplay the line the cursor is on.
[self setNeedsDisplayInRect: [self rectForCharacterIndex:
_selected_range.location - 1]];
} }
- (BOOL) acceptsFirstResponder - (BOOL) acceptsFirstResponder
@ -2447,10 +2476,11 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
// Add any clean-up stuff here // Add any clean-up stuff here
if ([self shouldDrawInsertionPoint]) if ([self shouldDrawInsertionPoint])
{ {
[self lockFocus];
[self drawInsertionPointAtIndex: _selected_range.location [self drawInsertionPointAtIndex: _selected_range.location
color: nil turnedOn: NO]; color: nil turnedOn: NO];
[self unlockFocus];
//<!> stop timed entry //<!> stop timed entry
} }
@ -2640,6 +2670,8 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
[_textStorage replaceCharactersInRange: aRange [_textStorage replaceCharactersInRange: aRange
withString: [attrString string]]; withString: [attrString string]];
[_textStorage endEditing]; [_textStorage endEditing];
// ScrollView interaction
[self sizeToFit];
} }
- (unsigned) textLength - (unsigned) textLength
@ -2677,9 +2709,6 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
withString: insertString]; withString: insertString];
} }
// ScrollView interaction
[self sizeToFit];
// move cursor <!> [self selectionRangeForProposedRange: ] // move cursor <!> [self selectionRangeForProposedRange: ]
[self setSelectedRange: [self setSelectedRange:
NSMakeRange (_selected_range.location + [insertString length], 0)]; NSMakeRange (_selected_range.location + [insertString length], 0)];
@ -2734,7 +2763,9 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
if (NSEqualRanges (longestRange, _selected_range)) if (NSEqualRanges (longestRange, _selected_range))
isMultiple = NO; isMultiple = NO;
else else
{
isMultiple = YES; isMultiple = YES;
}
} }
else else
currentFont = _default_font; currentFont = _default_font;
@ -2753,17 +2784,9 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
color: (NSColor*)color color: (NSColor*)color
turnedOn: (BOOL)flag turnedOn: (BOOL)flag
{ {
BOOL didLock = NO;
if (!_window) if (!_window)
return; return;
if ([[self class] focusView] != self)
{
[self lockFocus];
didLock = YES;
}
if (flag) if (flag)
{ {
[color set]; [color set];
@ -2773,12 +2796,11 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
{ {
[[self backgroundColor] set]; [[self backgroundColor] set];
NSRectFill(rect); NSRectFill(rect);
// FIXME: We should redisplay the character the cursor was on.
//[self setNeedsDisplayInRect: rect];
} }
if (didLock) [_window flushWindow];
{
[self unlockFocus];
}
} }
- (NSRange) selectionRangeForProposedRange: (NSRange)proposedCharRange - (NSRange) selectionRangeForProposedRange: (NSRange)proposedCharRange
@ -2855,11 +2877,13 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
+ (void) setSelectionWordGranularitySet: (NSCharacterSet*) aSet + (void) setSelectionWordGranularitySet: (NSCharacterSet*) aSet
{ {
ASSIGN(selectionWordGranularitySet, aSet); ASSIGN(selectionWordGranularitySet, aSet);
ASSIGN(invSelectionWordGranularitySet, [aSet invertedSet]);
} }
+ (void) setSelectionParagraphGranularitySet: (NSCharacterSet*) aSet + (void) setSelectionParagraphGranularitySet: (NSCharacterSet*) aSet
{ {
ASSIGN(selectionParagraphGranularitySet, aSet); ASSIGN(selectionParagraphGranularitySet, aSet);
ASSIGN(invSelectionParagraphGranularitySet, [aSet invertedSet]);
} }
- (NSDictionary*) defaultTypingAttributes - (NSDictionary*) defaultTypingAttributes
@ -2973,6 +2997,7 @@ scanRange(NSScanner *scanner, NSCharacterSet* aSet)
if (data != nil) if (data != nil)
{ {
// FIXME: Should use diverent format here
NSFont *font = [NSUnarchiver unarchiveObjectWithData: data]; NSFont *font = [NSUnarchiver unarchiveObjectWithData: data];
if (font != nil) if (font != nil)