Reputation: 12579
I was looking for a height measuring string procedure, and I found this one on another stack overflow question. And it works perfectly for my NSTableViewColumns which have Word Wrap as line breaks My question is, what if I change the line break to character wrap instead, how can I update this code?
- (NSSize)sizeForWidth:(float)width
height:(float)height {
NSSize answer = NSZeroSize ;
gNSStringGeometricsTypesetterBehavior = NSTypesetterBehavior_10_2_WithCompatibility;
if ([self length] > 0) {
// Checking for empty string is necessary since Layout Manager will give the nominal
// height of one line if length is 0. Our API specifies 0.0 for an empty string.
NSSize size = NSMakeSize(width, height) ;
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:size] ;
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self] ;
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init] ;
[layoutManager addTextContainer:textContainer] ;
[textStorage addLayoutManager:layoutManager] ;
[layoutManager setHyphenationFactor:0.0] ;
if (gNSStringGeometricsTypesetterBehavior != NSTypesetterLatestBehavior) {
[layoutManager setTypesetterBehavior:gNSStringGeometricsTypesetterBehavior] ;
}
// NSLayoutManager is lazy, so we need the following kludge to force layout:
[layoutManager glyphRangeForTextContainer:textContainer] ;
answer = [layoutManager usedRectForTextContainer:textContainer].size ;
[textStorage release] ;
[textContainer release] ;
[layoutManager release] ;
// In case we changed it above, set typesetterBehavior back
// to the default value.
gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
}
return answer ;
}
Upvotes: 1
Views: 1342
Reputation: 299683
This feels like you're reinventing [NSAttributedString boundingRectWithSize:options:]
(or just size
). Am I missing something in your implementation? NSLayoutManager
is for dealing with laying out rapidly-changing strings (such as in a text view). Most of the time it's overkill. You're intentionally bypassing its optimizations (in your line noting that NSLayoutManager
is lazy, by which you mean optimized :D)
In either case, to change the wrapping behavior, you need to modify the NSAttributedString
itself. Wrapping is part of the paragraph style. Something like this (untested; might not compile):
// Lazy here. I'm assuming the entire string has the same style
NSMutableParagraphStyle *style = [[self attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL] mutableCopy];
[style setLineBreakMode:NSLineBreakByCharWrapping];
NSAttributedString *charWrappedString = [self mutableCopy];
[charWrappedString setAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, [self length]];
NSRect boundingRect = [self boundingRectWithSize:NSMakeSize(width, height) options:0];
NSSize size = boundRect.size;
[style release];
[charWrappedString release];
return size;
Styles are a little tricky because they include several things in them, but you have to set them all together. So if there were different styles in the attributed string, you have to loop over the string, processing each effectiveRange
. (You'd want to read the docs to understand the tradeoff between attributesAtIndex:effectiveRange:
and attributesAtIndex:longestEffectiveRange:inRange:
.)
Upvotes: 2