NSString -boundingRectWithSize:, is this supposed to work with automatic word wrapping?

  • I'm trying to get to grips with non-trivial string drawing for the
    first time.

    I have a restricted area in which to render a short multi-word string
    (which I'd like it justified vertically in the middle of the bounding
    area with any required line wrapping done according to the word
    wrapping rule I have set up in the paragraph style attributes).

    A perusal of the docs suggest the following approaches:
    1. NSString's -boundingRectWithSize:options:attributes, setting the
    constraining area, followed by a justification of the returned
    rectangle within this area according to taste (i.e. to get my
    vertically centered position).  Then, naturally, NSString's drawInRect
    to actually render the string.
    2. Using NSLayoutManager (per the "Calculating Text Height" section of
    the Text Layout Programming Guide) to get the
    'usedRectForTextContainer', then proceed with justification of the
    returned rectangle and drawing as (1).

    My initial efforts have been focussed on approach (1) as, at face
    value at least, the documentation and the API seem to suggest it does
    what I need.  However, try as I might (so far) I cannot get this to
    work.  It appears that this method ought to differ from the simpler -
    sizeWithAttributes by taking into consideration the provided size as
    constraints for rendering the text, and then returning the bounds that
    actual text would have if rendered with all the attributes/typesetting
    rules.  Indeed, I would have expected -boundingRectWithSize to have
    been implemented in terms of the much more verbose method of (2).

    Instead, method (1) appears to always result in a single line of text
    that violates the horizontal bounds of the size that I set - despite
    there clearly being opportunity in the text I'm supplying to break
    lines with the default line breaking style to avoid this.  I have
    tried asserting my own paragraph style with appropriate values, but
    nothing seems to get -boundingRectWithSize to consider breaking the
    text into multiple lines.

    Experimentation indicates that -boundingRectWithSize does something I
    didn't expect: notably returning a Y-negative origin.  This leads me
    to suspect that it is intended to do something entirely different from
    the determination of the bounding rectangle of some text within
    constrained space.  However, it's not at all clear from the
    documentation what this function actual is.

    So, while I'm about to go off and write my sizing code in terms of
    method (2), I'm curious what -boundingRectWithSize is _supposed_ to
    do, and there remains a nagging doubt that it would do what I want if
    I was driving it properly.

    Can anyone enlighten me to the simplest/right way to size the area of
    text that will be word-wrapped?  And assuming -boundingRectWithSize is
    not intended to handle text that will be automatically set into
    multiple lines, what it is _supposed_ to be doing that -
    sizeWithAttributes does not?  Perhaps it is just for the determination
    of base-line positioned rendering of a single line of text?

    -- Lwe
  • Luke,

    Unlike other methods declared in the NSStringDrawing category, -
    drawWithRect:options:attributes: and -
    boundingRectWithSize:options:attributes: work in single-line, baseline
    rendering configuration by default.

    NSStringDrawingUsesLineFragmentOrigin flag switches them to behave in
    multiline configuration.

    The following sample code snippet should do what you're trying to do.

    - (void)drawRect:(NSRect)rect {
        NSRect bounds = NSInsetRect([self bounds], 10.0, 10.0);
        NSSize stringSize;

        [[NSColor whiteColor] set];
        NSRectFill(rect);

        [[NSColor redColor] set];
        [NSBezierPath strokeRect:bounds];

        stringSize = [string boundingRectWithSize:bounds.size
    options:NSStringDrawingUsesLineFragmentOrigin|
    NSStringDrawingDisableScreenFontSubstitution attributes:nil].size;

        if (stringSize.height < NSHeight(bounds)) bounds =
    NSInsetRect(bounds, 0.0, (NSHeight(bounds) - stringSize.height) / 2);

        [string drawWithRect:bounds
    options:NSStringDrawingUsesLineFragmentOrigin|
    NSStringDrawingDisableScreenFontSubstitution|
    NSStringDrawingTruncatesLastVisibleLine attributes:nil];
    }

    Aki

    On 2008/01/15, at 15:47, Luke Evans wrote:

    > I'm trying to get to grips with non-trivial string drawing for the
    > first time.
    >
    > I have a restricted area in which to render a short multi-word
    > string (which I'd like it justified vertically in the middle of the
    > bounding area with any required line wrapping done according to the
    > word wrapping rule I have set up in the paragraph style attributes).
    >
    > A perusal of the docs suggest the following approaches:
    > 1. NSString's -boundingRectWithSize:options:attributes, setting the
    > constraining area, followed by a justification of the returned
    > rectangle within this area according to taste (i.e. to get my
    > vertically centered position).  Then, naturally, NSString's
    > drawInRect to actually render the string.
    > 2. Using NSLayoutManager (per the "Calculating Text Height" section
    > of the Text Layout Programming Guide) to get the
    > 'usedRectForTextContainer', then proceed with justification of the
    > returned rectangle and drawing as (1).
    >
    > My initial efforts have been focussed on approach (1) as, at face
    > value at least, the documentation and the API seem to suggest it
    > does what I need.  However, try as I might (so far) I cannot get
    > this to work.  It appears that this method ought to differ from the
    > simpler -sizeWithAttributes by taking into consideration the
    > provided size as constraints for rendering the text, and then
    > returning the bounds that actual text would have if rendered with
    > all the attributes/typesetting rules.  Indeed, I would have expected
    > -boundingRectWithSize to have been implemented in terms of the much
    > more verbose method of (2).
    >
    > Instead, method (1) appears to always result in a single line of
    > text that violates the horizontal bounds of the size that I set -
    > despite there clearly being opportunity in the text I'm supplying to
    > break lines with the default line breaking style to avoid this.  I
    > have tried asserting my own paragraph style with appropriate values,
    > but nothing seems to get -boundingRectWithSize to consider breaking
    > the text into multiple lines.
    >
    > Experimentation indicates that -boundingRectWithSize does something
    > I didn't expect: notably returning a Y-negative origin.  This leads
    > me to suspect that it is intended to do something entirely different
    > from the determination of the bounding rectangle of some text within
    > constrained space.  However, it's not at all clear from the
    > documentation what this function actual is.
    >
    > So, while I'm about to go off and write my sizing code in terms of
    > method (2), I'm curious what -boundingRectWithSize is _supposed_ to
    > do, and there remains a nagging doubt that it would do what I want
    > if I was driving it properly.
    >
    > Can anyone enlighten me to the simplest/right way to size the area
    > of text that will be word-wrapped?  And assuming -
    > boundingRectWithSize is not intended to handle text that will be
    > automatically set into multiple lines, what it is _supposed_ to be
    > doing that -sizeWithAttributes does not?  Perhaps it is just for the
    > determination of base-line positioned rendering of a single line of
    > text?
    >
    > -- Lwe
  • Hi Aki,

    Perfect.

    Of course, now I've searched for NSStringDrawingUsesLineFragmentOrigin
    in the docs, I see there's a discussion of it on the -
    drawWithRect:options:attributes: method.  This is missing from the the
    -boundingRectWithSize:options:attributes (though you can get to the
    former note by following a couple of "see also" links - or by being
    more diligent in reading around the context of the method at hand than
    I was!).

    Thanks a lot for shedding the light.

    -- Lwe

    On 15-Jan-08, at 5:31 PM, Aki Inoue wrote:

    > Luke,
    >
    > Unlike other methods declared in the NSStringDrawing category, -
    > drawWithRect:options:attributes: and -
    > boundingRectWithSize:options:attributes: work in single-line,
    > baseline rendering configuration by default.
    >
    > NSStringDrawingUsesLineFragmentOrigin flag switches them to behave
    > in multiline configuration.
    >
    >
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today