gui: implement NSLayoutManager temporary attributes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@32503 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Eric Wasylishen 2011-03-09 05:28:47 +00:00
parent 2223f0009b
commit e39fed5a42
3 changed files with 95 additions and 205 deletions

View file

@ -1,3 +1,8 @@
2011-03-08 Eric Wasylishen <ewasylishen@gmail.com>
* Source/NSLayoutManager.m: Implement temporary attributes
* Header/AppKit/NSLayoutManager.h: Add a _temporaryAttributes ivar
2011-03-07 Fred Kiefer <FredKiefer@gmx.de>
* Source/NSGraphicsContext.m (+saveGraphicsState): Release the

View file

@ -67,6 +67,8 @@ typedef enum {
should release the old value and retain the new one. It is nil originally
and will be released when the NSLayoutManager is deallocated. */
NSMutableDictionary *_typingAttributes;
NSMutableAttributedString *_temporaryAttributes;
}
/* TODO */

View file

@ -133,6 +133,19 @@ first. Remaining cases, highest priority first:
}
@end
/**
* Temporary attributes are implemented using an NSMutableAttributedString
* stored in the _temporaryAttributes ivar. We only care about this attributed
* string's attributes, not its characters, so to save space, _temporaryAttributes
* is initialized with an instance of the following NSMutableString subclass,
* which doesn't store any character data.
*/
@interface GSDummyMutableString : NSMutableString
{
NSUInteger _length;
}
- (id)initWithLength: (NSUInteger)aLength;
@end
/* Helper for searching for the line frag of a glyph. */
#define LINEFRAG_FOR_GLYPH(glyph) \
@ -1918,6 +1931,7 @@ static void GSDrawPatternLine(NSPoint start, NSPoint end, NSInteger pattern, CGF
-(void) dealloc
{
DESTROY(_typingAttributes);
DESTROY(_temporaryAttributes);
[super dealloc];
}
@ -2177,6 +2191,16 @@ this file describes this.
if (!(mask & NSTextStorageEditedCharacters))
lengthChange = 0;
if (_temporaryAttributes != nil && (mask & NSTextStorageEditedCharacters) != 0)
{
NSRange oldRange = NSMakeRange(range.location, range.length - lengthChange);
NSString *replacementString = [[GSDummyMutableString alloc] initWithLength: range.length];
[_temporaryAttributes replaceCharactersInRange: oldRange
withString: replacementString];
[replacementString release];
}
[self invalidateGlyphsForCharacterRange: invalidatedRange
changeInLength: lengthChange
actualCharacterRange: &r];
@ -2607,143 +2631,92 @@ no_soft_invalidation:
@end
@implementation GSDummyMutableString
- (id)initWithLength: (NSUInteger)aLength
{
self = [super init];
if (self != nil)
{
self->_length = aLength;
}
return self;
}
- (NSUInteger)length
{
return _length;
}
- (unichar)characterAtIndex: (NSUInteger)index
{
return 0;
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString
{
_length = (_length - range.length) + [aString length];
}
- (id) copyWithZone: (NSZone*)zone
{
return [self mutableCopyWithZone: zone];
}
- (id) mutableCopyWithZone: (NSZone*)zone
{
return [[GSDummyMutableString allocWithZone: zone] initWithLength: _length];
}
@end
@implementation NSLayoutManager (temporaryattributes)
- (NSMutableAttributedString*) _temporaryAttributes
{
if (_temporaryAttributes == nil)
{
NSString *dummyString = [[GSDummyMutableString alloc] initWithLength: [[self textStorage] length]];
_temporaryAttributes = [[NSMutableAttributedString alloc] initWithString: dummyString];
[dummyString release];
}
return _temporaryAttributes;
}
- (void) setTemporaryAttributes: (NSDictionary *)attrs
forCharacterRange: (NSRange)range
{
// to be implemented
[[self _temporaryAttributes] setAttributes: attrs range: range];
[self invalidateDisplayForCharacterRange: range];
}
- (NSDictionary *) temporaryAttributesAtCharacterIndex: (NSUInteger)index
effectiveRange: (NSRange*)longestRange
{
// to be implemented
return nil;
return [[self _temporaryAttributes] attributesAtIndex: index effectiveRange: longestRange];
}
- (void) addTemporaryAttributes: (NSDictionary *)attrs
forCharacterRange: (NSRange)range
{
NSRange effectiveRange;
NSDictionary *attrDict;
NSMutableDictionary *newDict;
unsigned int tmpLength;
if (!attrs)
{
[NSException raise: NSInvalidArgumentException
format: @"attributes is nil in method -addTemporaryAttributes:forCharacterRange: "
@"in class NSLayoutManager"];
}
tmpLength = [_textStorage length];
if (NSMaxRange(range) > tmpLength)
{
[NSException raise: NSRangeException
format: @"RangeError in method -addTemporaryAttributes:forCharacterRange: "
@"in class NSLayoutManager"];
}
attrDict = [self temporaryAttributesAtCharacterIndex: range.location
effectiveRange: &effectiveRange];
while (effectiveRange.location < NSMaxRange(range))
{
effectiveRange = NSIntersectionRange(range, effectiveRange);
newDict = [attrDict mutableCopy];
[newDict addEntriesFromDictionary: attrs];
[self setTemporaryAttributes: newDict
forCharacterRange: effectiveRange];
RELEASE(newDict);
if (NSMaxRange(effectiveRange) >= NSMaxRange(range))
{
effectiveRange.location = NSMaxRange(range);// stop the loop...
}
else if (NSMaxRange(effectiveRange) < tmpLength)
{
attrDict = [self temporaryAttributesAtCharacterIndex: NSMaxRange(effectiveRange)
effectiveRange: &effectiveRange];
}
}
[[self _temporaryAttributes] addAttributes: attrs range: range];
[self invalidateDisplayForCharacterRange: range];
}
- (void) addTemporaryAttribute: (NSString *)attr
value: (id)value
forCharacterRange: (NSRange)range
{
NSDictionary *dict = [[NSDictionary alloc] initWithObjects: &value
forKeys: &attr
count: 1];
[self addTemporaryAttributes: dict forCharacterRange: range];
RELEASE(dict);
[[self _temporaryAttributes] addAttribute: attr value: value range: range];
[self invalidateDisplayForCharacterRange: range];
}
- (void) removeTemporaryAttribute: (NSString *)attr
forCharacterRange: (NSRange)range
{
NSRange effectiveRange;
NSDictionary *attrDict;
NSMutableDictionary *newDict;
unsigned int tmpLength;
tmpLength = [_textStorage length];
if (NSMaxRange(range) > tmpLength)
{
[NSException raise: NSRangeException
format: @"RangeError in method -removeTemporaryAttribute:forCharacterRange: "
@"in class NSLayoutManager"];
}
attrDict = [self temporaryAttributesAtCharacterIndex: range.location
effectiveRange: &effectiveRange];
while (effectiveRange.location < NSMaxRange(range))
{
effectiveRange = NSIntersectionRange(range, effectiveRange);
newDict = [attrDict mutableCopy];
[newDict removeObjectForKey: attr];
[self setTemporaryAttributes: newDict
forCharacterRange: effectiveRange];
RELEASE(newDict);
if (NSMaxRange(effectiveRange) >= NSMaxRange(range))
{
effectiveRange.location = NSMaxRange(range);// stop the loop...
}
else if (NSMaxRange(effectiveRange) < tmpLength)
{
attrDict = [self temporaryAttributesAtCharacterIndex: NSMaxRange(effectiveRange)
effectiveRange: &effectiveRange];
}
}
[[self _temporaryAttributes] removeAttribute: attr range: range];
[self invalidateDisplayForCharacterRange: range];
}
- (id) temporaryAttribute: (NSString *)attr
atCharacterIndex: (NSUInteger)index
effectiveRange: (NSRange*)range
{
NSDictionary *tmpDictionary;
if (attr == nil)
{
if (range != 0)
{
*range = NSMakeRange(0, [_textStorage length]);
/*
* If attr is nil, then the attribute will not exist in the
* entire text - therefore range of the entire text must be correct
*/
}
return nil;
}
tmpDictionary = [self temporaryAttributesAtCharacterIndex: index
effectiveRange: range];
return [tmpDictionary objectForKey: attr];
return [[self _temporaryAttributes] attribute: attr atIndex: index effectiveRange: range];
}
- (id) temporaryAttribute: (NSString *)attr
@ -2751,113 +2724,23 @@ no_soft_invalidation:
longestEffectiveRange: (NSRange*)longestRange
inRange: (NSRange)range
{
id attrValue;
id tmpAttrValue;
NSRange tmpRange;
if (NSMaxRange(range) > [_textStorage length])
{
[NSException raise: NSRangeException
format: @"RangeError in method -temporaryAttribute:atCharacterIndex:longestEffectiveRange:inRange: in class NSLayoutManager"];
}
if (attr == nil)
return nil;
attrValue = [self temporaryAttribute: attr
atCharacterIndex: index
effectiveRange: longestRange];
if (longestRange == 0)
return attrValue;
while (longestRange->location > range.location)
{
//Check extend range backwards
tmpAttrValue = [self temporaryAttribute: attr
atCharacterIndex: longestRange->location-1
effectiveRange: &tmpRange];
if (tmpAttrValue == attrValue
|| (attrValue != nil && [attrValue isEqual: tmpAttrValue]))
{
longestRange->length = NSMaxRange(*longestRange) - tmpRange.location;
longestRange->location = tmpRange.location;
}
else
{
break;
}
}
while (NSMaxRange(*longestRange) < NSMaxRange(range))
{
//Check extend range forwards
tmpAttrValue = [self temporaryAttribute: attr
atCharacterIndex: longestRange->location-1
effectiveRange: &tmpRange];
if (tmpAttrValue == attrValue
|| (attrValue != nil && [attrValue isEqual: tmpAttrValue]))
{
longestRange->length = NSMaxRange(tmpRange) - longestRange->location;
}
else
{
break;
}
}
*longestRange = NSIntersectionRange(*longestRange,range);//Clip to rangeLimit
return attrValue;
return [[self _temporaryAttributes] attribute: attr atIndex: index longestEffectiveRange: longestRange inRange: range];
}
- (NSDictionary *) temporaryAttributesAtCharacterIndex: (NSUInteger)index
longestEffectiveRange: (NSRange*)longestRange
inRange: (NSRange)range
{
NSDictionary *attrDictionary, *tmpDictionary;
NSRange tmpRange;
return [[self _temporaryAttributes] attributesAtIndex: index longestEffectiveRange: longestRange inRange: range];
}
if (NSMaxRange(range) > [_textStorage length])
{
[NSException raise: NSRangeException
format: @"RangeError in method -temporaryAttributesAtCharacterIndex:longestEffectiveRange:inRange: in class NSLayoutManager"];
}
attrDictionary = [self temporaryAttributesAtCharacterIndex: index
effectiveRange: longestRange];
if (longestRange == 0)
return attrDictionary;
while (longestRange->location > range.location)
{
//Check extend range backwards
tmpDictionary = [self temporaryAttributesAtCharacterIndex: longestRange->location-1
effectiveRange: &tmpRange];
if ([tmpDictionary isEqualToDictionary: attrDictionary])
{
longestRange->length = NSMaxRange(*longestRange) - tmpRange.location;
longestRange->location = tmpRange.location;
}
else
{
break;
}
}
while (NSMaxRange(*longestRange) < NSMaxRange(range))
{
//Check extend range forwards
tmpDictionary = [self temporaryAttributesAtCharacterIndex: NSMaxRange(*longestRange)
effectiveRange: &tmpRange];
if ([tmpDictionary isEqualToDictionary: attrDictionary])
{
longestRange->length = NSMaxRange(tmpRange) - longestRange->location;
}
else
{
break;
}
}
//Clip to range
*longestRange = NSIntersectionRange(*longestRange, range);
return attrDictionary;
/**
* Most of this is implemented in GSLayoutManager
*/
- (void) setTextStorage: (NSTextStorage *)aTextStorage
{
DESTROY(_temporaryAttributes);
[super setTextStorage: aTextStorage];
}
@end