I'm subclassing NSATSTypesetter to add custom line wrapping behavior which 
indents wrapped lines relative to the starting line's indentation (like Xcode).

To do this, I'm overriding - 
getLineFragmentRect:usedRect:remainingRect:forStartingGlyphAtIndex:... and for 
wrapped lines am modifying the proposed rect's x origin to add indentation 
before passing the parameters up to super to let it handle the rest of the 
fragment generation.



Questions:

1) When I dump rich text into the text view, this method is called *twice* for 
each starting glyph index, and the proposed rect for the second call is the 
proposed rect I modify during the first call. For plain text it's only called 
once for each line. Any explanations for what's going on?

2) Is simply modifying the proposed rect's origin the right approach?
        a) Does the proposed rect ever include lineFragmentPadding
        b) Is the proposed rect always a bazillion points wide?


Basically, I'm wondering if I need to add to the x value, or if I should simply 
set it to the indentation I want.
        proposedRect.origin.x += indent;  Versus   proposedRect.origin.x = 
indent;

I've already noticed a problem with the former when pasting in rich text since 
for a single line, getLineFragmentRect: is called with the normal proposedRect, 
I add to it, then it gets calls again with the proposed I passed to super, and 
I add to it again which of course is wrong (and also leads to some very strange 
and broken layout). So it appears I must simply *set* the x value, but I don't 
know if I need to take lineFragment padding and the width into account.


3) Is it always going to be safe to ask the layout manage 
locationForGlyphAtIndex: for a glyph index < startingGlyphIndex or is there any 
possibility of an infinite loop?





Here's a simple implementation I'm starting with:

- (void)getLineFragmentRect:(NSRectPointer)lineFragmentRect 
usedRect:(NSRectPointer)lineFragmentUsedRect 
remainingRect:(NSRectPointer)remainingRect 
forStartingGlyphAtIndex:(NSUInteger)startingGlyphIndex 
proposedRect:(NSRect)proposedRect lineSpacing:(CGFloat)lineSpacing 
paragraphSpacingBefore:(CGFloat)paragraphSpacingBefore 
paragraphSpacingAfter:(CGFloat)paragraphSpacingAfter
{
        NSString * string = self.layoutManager.textStorage.string;
        NSUInteger stringLength = string.length;
        NSUInteger characterIndex = [self.layoutManager 
characterIndexForGlyphAtIndex:startingGlyphIndex];
        NSRange lineRange = [string 
lineRangeForRange:NSMakeRange(characterIndex, 0)];
        
        
        // Find the line range for the line of text this glyph is a part of
        characterIndex = [self.layoutManager 
characterIndexForGlyphAtIndex:startingGlyphIndex];
        lineRange = [string lineRangeForRange:NSMakeRange(characterIndex, 0)];
        
        
        // If the startingGlyphIndex's character is *after* the beginning of 
the line
        // of text it's on, then the lineFragmentRect being asked for must be 
part
        // of a wrapped line - which we want to indent.
        if (characterIndex > lineRange.location) {
                NSCharacterSet * cs = [NSCharacterSet whitespaceCharacterSet];
                CGFloat indentation = 0.0;
                
                // Find the indentation of the first non-whitespace
                // character in the line.
                for (NSUInteger i = 0; lineRange.location + i < stringLength; 
i++) {
                        unichar c = [string characterAtIndex:lineRange.location 
+ i];
                        if (![cs characterIsMember:c]) {
                                NSUInteger glyphIndex = [self.layoutManager 
glyphIndexForCharacterAtIndex:lineRange.location + i];
                                indentation = [self.layoutManager 
locationForGlyphAtIndex:glyphIndex].x;
                                break;
                        }
                }
                
                // NOTE: Do we need to do anything special for 
lineFragmentPadding *here*?
                // ...
                
                // Increase the indentation from the first line
                indentation += 28; // 4 spaces width (to be calculated for real 
later)
                
                // Modify the proposed rect to create that indentation
                CGFloat maxX = NSMaxX(proposedRect);
                proposedRect.origin.x = indentation;
                proposedRect.size.width = maxX - indentation;
        }
        
        
        [super getLineFragmentRect:lineFragmentRect 
usedRect:lineFragmentUsedRect remainingRect:remainingRect 
forStartingGlyphAtIndex:startingGlyphIndex proposedRect:proposedRect 
lineSpacing:lineSpacing paragraphSpacingBefore:paragraphSpacingBefore 
paragraphSpacingAfter:paragraphSpacingAfter];
}



--
Seth Willits




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to