Responding to myself, here:
> 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? I still have no idea what the answer is. > 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? Answers: 2) Yes. 2a) No. 2b) It *think* so. > 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? Answer: yes it's possible to get in an infinite loop. There seems to be no solution other than not using locationForGlyphAtIndex. So rather than using the location of the first non-whitespace character to determine indentation, the answer is to calculate the width of the indentation "manually". I took a look at how Xcode does it, and it actually does this as well. So here's what I've got: - (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 { AGSourceTextStorage * textStorage = (AGSourceTextStorage *)self.layoutManager.textStorage; if (![textStorage isKindOfClass:[AGSourceTextStorage class]]) { [NSException raise:@"" format:@"AGSourceTypesetter's text storage is not an AGSourceTextStorage"]; } if (textStorage.indentWrappedLines) { NSString * string = textStorage.string; 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) { NSUInteger lineNumber = [textStorage lineNumberAtCharacterLocation:characterIndex]; CGFloat indentation = [textStorage indentationForWrappedLineNumber:lineNumber]; // TODO: Do we need to do anything special for lineFragmentPadding *here*? // ... // Modify the proposed rect to create that indentation CGFloat maxX = NSMaxX(proposedRect); proposedRect.origin.x = indentation; proposedRect.size.width = maxX - indentation; } } // After having possibly indented the proposed rect, let the standard class do its thing. [super getLineFragmentRect:lineFragmentRect usedRect:lineFragmentUsedRect remainingRect:remainingRect forStartingGlyphAtIndex:startingGlyphIndex proposedRect:proposedRect lineSpacing:lineSpacing paragraphSpacingBefore:paragraphSpacingBefore paragraphSpacingAfter:paragraphSpacingAfter]; } indentationForWrappedLineNumber in the text storage class counts the number of spaces at the beginning of the line, and multiplies that by a standard width for a space which was precalculated. Seems to work, and it's reassuring to know that Xcode also apparently thinks this is a good solution and I think some smart folks work on that. ;-) -- 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