Re: finding text to be drawn in NSTextView drawRect
Re: finding text to be drawn in NSTextView drawRect
- Subject: Re: finding text to be drawn in NSTextView drawRect
- From: Douglas Davidson <email@hidden>
- Date: Thu, 23 May 2002 10:03:38 -0700
On Wednesday, May 22, 2002, at 10:31 PM, Scott Royston wrote:
I'm currently trying to figure out the range of text that needs to be
redrawn (in drawRect) in an NSTextView.
It's turning out to be a pain, and I'm hoping I'm doing it the hard
way. Here's what I currently have hacked together:
You are doing it the hard way. Don't use characterIndexForPoint:; it's
for input management only. Instead, talk to the layout manager.
Now, NSTextView normally figures out for itself what range of text is
supposed to be redrawn; ordinarily if you want a text view to redraw a
certain rect, you just call setNeedsDisplayInRect: and let the text view
figure it out. You should let the text view do its thing if at all
possible.
However, there are legitimate reasons for wanting to know the range of
text corresponding to a given rect, so I'll discuss how to do that. As
usual, the layout manager has the information necessary. There are two
possibilities here, depending on whether you are willing to cause layout
or not. NSTextView itself has a mechanism for keeping track of when
additional layout might be necessary, which is one of the reasons you
should let it handle this sort of thing itself. If you don't know,
probably you should allow layout to happen.
If textView points to the text view, textContainer to the text
container, and layoutManager to the layout manager, and rect is the rect
of interest in view coordinates, it might look something like this. I
don't know whether you need the glyph range or the character range, so
I'll get both:
NSRange glyphRange, characterRange;
// first transform to text container coordinates
NSPoint containerOrigin = [textView textContainerOrigin];
rect.origin.x -= containerOrigin.x;
rect.origin.y -= containerOrigin.y;
// next, compute glyph range
glyphRange = [layoutManager glyphRangeForBoundingRect:rect
inTextContainer:textContainer];
// finally, compute character range
characterRange = [layoutManager
characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
Now, you should be aware that the resulting range may include glyphs
that do not lie within the rect. For example, if your rect is a thin
vertical one down the middle of the page, the resulting range will
include almost all of the glyphs on the page--because that's the only
way to get a single range that covers the whole rect.
Also, it may well be that you want a glyph range that contains only full
lines; there are many cases in which text drawing is best done by the
line rather than by some portion of the line. To extend your range to
integral line boundaries, you would do something like this:
NSRange lineGlyphRange;
// first, extend to beginning of first line
(void)[layoutManager
lineFragmentRectForGlyphAtIndex:glyphRange.location
effectiveGlyphRange:&lineGlyphRange];
glyphRange = NSUnionRange(glyphRange, lineGlyphRange);
// next, extend to end of last line
if (glyphRange.length > 0) {
(void)[layoutManager
lineFragmentRectForGlyphAtIndex:NSMaxRange(glyphRange)-1
effectiveGlyphRange:&lineGlyphRange];
glyphRange = NSUnionRange(glyphRange, lineGlyphRange);
}
Douglas Davidson
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.