Calculating lineFragment for NSTextContainer

  • Hi,

    for the

    - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect {

    call I'd like to calculate the proposedRect in case there are bezierPaths limitations of custom shapes.

    So I thought there'd be a way to not only clipRect to shade out a piece of a path, but also a way to get that spare-piece from the NSBezierPath instance. Is there?

    I wanted to split up the bounds rect of the path to circumvent with the text into stripes of the height of proposedRect passed into the call, then considering the offset from top, if any, then pick the stripe I need and see what the minimum bounds would be if the bezierpath stripe was an own bezier path on its own. Or is there another way?

    Thanks
    Alex
  • On 19/06/2012, at 7:02 PM, Alexander Reichstadt wrote:

    > Hi,
    >
    > for the
    >
    > - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect {
    >
    > call I'd like to calculate the proposedRect in case there are bezierPaths limitations of custom shapes.
    >
    > So I thought there'd be a way to not only clipRect to shade out a piece of a path, but also a way to get that spare-piece from the NSBezierPath instance. Is there?

    No, not built-in anyway.

    > I wanted to split up the bounds rect of the path to circumvent with the text into stripes of the height of proposedRect passed into the call, then considering the offset from top, if any, then pick the stripe I need and see what the minimum bounds would be if the bezierpath stripe was an own bezier path on its own. Or is there another way?

    I'm guessing you're trying to run text into an arbitrary path defined by a bezier.

    If that's the case, I think your understanding of what the text system wants from you here is a bit off. Basically, it tells you where it proposes to lay the text down, and you can modify that to constrain it to lay it down differently. So, for the proposedRect, you need to work out where that intersects the edges of your path and pull the sides of that rect in until they lie within the path. THERE IS NO BUILT-IN WAY TO DO THIS! But it's not that hard. For the points representing the corners of the rect, you can find out whether they are inside or outside the path with [NSBezierPath containsPoint:], then use a binary approximation to shrink the rect until it is "just inside" the path. In <remainingRect>, you return the bit of the rect you are NOT using, in the direction of the text sweep. The text system uses that to understand what part of the text it can't use this time round and so will take that into account for the next fragment. You'll be called again with the remainder rect as the proposedRect, so if your path shape is such that more text could fit on the same line  but horizontally displaced, you have an opportunity to calculate that as well. This system allows any path shape to work, even paths that are disjoint, or that have holes.

    If the object is to run text around the outside of a path, it's the same idea, you just return the rects outside instead.

    This method is called repeatedly until all the text is laid out - so you don't usually precalculate a series of strips and figure out which one to return - you just have to focus on the single strip being considered right now. There is no method to intersect a rect with a bezier and return another bezier (arbitrary bezier path set operations would be wonderful, but they ain't happening, even after years of asking for it).

    --Graham
  • Hi,

    sorry for the delay and thanks for the response, I moved house. Anyway, this all worked fine and now the text while being edited is taking crossing paths into consideration and writes around them the way I wanted to. But it discards the layout whenever I end editing. I first thought this was due to a call of removeLayoutManager, but also after I removed this line it keeps on ignoring all layout efforts and just writes across all paths.

    - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect

    …is stopped being called after editing ended. Why? How can I freeze the layout in the view for after editing ended?

    Alex

    Am 20.06.2012 um 01:41 schrieb Graham Cox:

    >
    > On 19/06/2012, at 7:02 PM, Alexander Reichstadt wrote:
    >
    >> Hi,
    >>
    >> for the
    >>
    >> - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect {
    >>
    >> call I'd like to calculate the proposedRect in case there are bezierPaths limitations of custom shapes.
    >>
    >> So I thought there'd be a way to not only clipRect to shade out a piece of a path, but also a way to get that spare-piece from the NSBezierPath instance. Is there?
    >
    > No, not built-in anyway.
    >
    >> I wanted to split up the bounds rect of the path to circumvent with the text into stripes of the height of proposedRect passed into the call, then considering the offset from top, if any, then pick the stripe I need and see what the minimum bounds would be if the bezierpath stripe was an own bezier path on its own. Or is there another way?
    >
    >
    > I'm guessing you're trying to run text into an arbitrary path defined by a bezier.
    >
    > If that's the case, I think your understanding of what the text system wants from you here is a bit off. Basically, it tells you where it proposes to lay the text down, and you can modify that to constrain it to lay it down differently. So, for the proposedRect, you need to work out where that intersects the edges of your path and pull the sides of that rect in until they lie within the path. THERE IS NO BUILT-IN WAY TO DO THIS! But it's not that hard. For the points representing the corners of the rect, you can find out whether they are inside or outside the path with [NSBezierPath containsPoint:], then use a binary approximation to shrink the rect until it is "just inside" the path. In <remainingRect>, you return the bit of the rect you are NOT using, in the direction of the text sweep. The text system uses that to understand what part of the text it can't use this time round and so will take that into account for the next fragment. You'll be called again with the remainder rect as the proposedRect, so if your path shape is such that more text could fit on the same line  but horizontally displaced, you have an opportunity to calculate that as well. This system allows any path shape to work, even paths that are disjoint, or that have holes.
    >
    > If the object is to run text around the outside of a path, it's the same idea, you just return the rects outside instead.
    >
    > This method is called repeatedly until all the text is laid out - so you don't usually precalculate a series of strips and figure out which one to return - you just have to focus on the single strip being considered right now. There is no method to intersect a rect with a bezier and return another bezier (arbitrary bezier path set operations would be wonderful, but they ain't happening, even after years of asking for it).
    >
    > --Graham
    >
    >
  • Oh, it dawns me that this is due to adding an NSTextView instance that is being removed when editing ends. This was in a sample project. Never mind.

    Am 12.07.2012 um 12:09 schrieb Alexander Reichstadt:

    > Hi,
    >
    > sorry for the delay and thanks for the response, I moved house. Anyway, this all worked fine and now the text while being edited is taking crossing paths into consideration and writes around them the way I wanted to. But it discards the layout whenever I end editing. I first thought this was due to a call of removeLayoutManager, but also after I removed this line it keeps on ignoring all layout efforts and just writes across all paths.
    >
    > - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect
    >
    > …is stopped being called after editing ended. Why? How can I freeze the layout in the view for after editing ended?
    >
    > Alex
    >
    >
    > Am 20.06.2012 um 01:41 schrieb Graham Cox:
    >
    >>
    >> On 19/06/2012, at 7:02 PM, Alexander Reichstadt wrote:
    >>
    >>> Hi,
    >>>
    >>> for the
    >>>
    >>> - (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect sweepDirection:(NSLineSweepDirection)sweepDirection movementDirection:(NSLineMovementDirection)movementDirection remainingRect:(NSRect *)remainingRect {
    >>>
    >>> call I'd like to calculate the proposedRect in case there are bezierPaths limitations of custom shapes.
    >>>
    >>> So I thought there'd be a way to not only clipRect to shade out a piece of a path, but also a way to get that spare-piece from the NSBezierPath instance. Is there?
    >>
    >> No, not built-in anyway.
    >>
    >>> I wanted to split up the bounds rect of the path to circumvent with the text into stripes of the height of proposedRect passed into the call, then considering the offset from top, if any, then pick the stripe I need and see what the minimum bounds would be if the bezierpath stripe was an own bezier path on its own. Or is there another way?
    >>
    >>
    >> I'm guessing you're trying to run text into an arbitrary path defined by a bezier.
    >>
    >> If that's the case, I think your understanding of what the text system wants from you here is a bit off. Basically, it tells you where it proposes to lay the text down, and you can modify that to constrain it to lay it down differently. So, for the proposedRect, you need to work out where that intersects the edges of your path and pull the sides of that rect in until they lie within the path. THERE IS NO BUILT-IN WAY TO DO THIS! But it's not that hard. For the points representing the corners of the rect, you can find out whether they are inside or outside the path with [NSBezierPath containsPoint:], then use a binary approximation to shrink the rect until it is "just inside" the path. In <remainingRect>, you return the bit of the rect you are NOT using, in the direction of the text sweep. The text system uses that to understand what part of the text it can't use this time round and so will take that into account for the next fragment. You'll be called again with the remainder rect as the proposedRect, so if your path shape is such that more text could fit on the same line  but horizontally displaced, you have an opportunity to calculate that as well. This system allows any path shape to work, even paths that are disjoint, or that have holes.
    >>
    >> If the object is to run text around the outside of a path, it's the same idea, you just return the rects outside instead.
    >>
    >> This method is called repeatedly until all the text is laid out - so you don't usually precalculate a series of strips and figure out which one to return - you just have to focus on the single strip being considered right now. There is no method to intersect a rect with a bezier and return another bezier (arbitrary bezier path set operations would be wonderful, but they ain't happening, even after years of asking for it).
    >>
    >> --Graham
    >>
    >>

previous month june 2012 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  
Go to today