views:

49

answers:

2

What I want to do: layout text using NSLayoutManager and set its NSTextContainer to the width of the widest string (glyph-wise) in an array of strings.

What my problem is: The methods for determining the total 'glyph-width' seem to be incorrect because when I render the text it wraps.

I did an experiment using a 32 character string with the Monaco 12 point font and the length is reported as 224.0, but the text will only stop wrapping if the length is set to 234.0.

This code demonstrates what I said above and shows a vertical line on the right of the computed glyph-width.

- (void)drawRect:(NSRect)rect {
    NSRect bounds = [self bounds];

    [[NSColor whiteColor] drawSwatchInRect: bounds];
    [[NSColor blackColor] setStroke];
    [[NSBezierPath bezierPathWithRect: bounds] stroke];

    NSMutableParagraphStyle *thisParagraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
    [thisParagraphStyle setLineBreakMode: NSLineBreakByCharWrapping];
    [thisParagraphStyle setAlignment: NSLeftTextAlignment];

    NSFont *fontUsed = [NSFont fontWithName: @"Monaco" size: 12];

    NSDictionary *glyphAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                     fontUsed, NSFontAttributeName,
                                     thisParagraphStyle, NSParagraphStyleAttributeName,
                                     [NSColor blackColor], NSForegroundColorAttributeName,
                                     NULL];

    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:@"00112233445566778899001122334455\n00112233445566778899001122334455\n00112233445566778899001122334455\n00112233445566778899001122334455\n"];

    [textStorage setAttributes: glyphAttributes range:  NSMakeRange(0, [textStorage length])];

    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];

    NSSize textContainerSize;
    textContainerSize.width = [@"00112233445566778899001122334455" sizeWithAttributes: glyphAttributes].width;
    textContainerSize.height = bounds.size.height;

    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: textContainerSize];
    [layoutManager addTextContainer:textContainer];

    [textContainer release];
    [textStorage addLayoutManager:layoutManager];
    [layoutManager release];
    NSRange glyphRange = [layoutManager glyphRangeForTextContainer: textContainer];

    [layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: NSMakePoint(0.0 , 0.0)];
    [textStorage release];
    [thisParagraphStyle release];

    // Indicate right text boundary from computed width
    NSBezierPath *rightTextBoundary = [NSBezierPath bezierPath];
    [rightTextBoundary moveToPoint: NSMakePoint(textContainerSize.width, 0.0)];
    [rightTextBoundary lineToPoint: NSMakePoint(textContainerSize.width, bounds.size.height-1)];
    [rightTextBoundary stroke];

    NSLog(@"View width: %f", bounds.size.width);
    NSLog(@"Calculated width1: %f", textContainerSize.width);
    NSLog(@"Calculated width2: %f\n\n", [@"00112233445566778899001122334455" boundingRectWithSize: NSMakeSize(FLT_MAX, FLT_MAX)
                                                                         options: NSStringDrawingUsesDeviceMetrics
                                                                      attributes: glyphAttributes].size.width);
}

- (BOOL) isFlipped {
    return YES;
}
A: 

Have you accounted for the text container's -lineFragmentPadding?

Joshua Nozzi
A: 

Have you taken a look at this category for NSString and NSAttributedString NS(Attributed)String+Geometrics?

If it's not exactly what you're looking for you could perhaps see some of what they are doing to calculate the size.

skabob11