NSTextView - bounding rectange of specified line

Does anyone know how to. …

Given a NSTextView
and a LineNumber (from 0 to max lines in the textview)

Return, the NSRect that encloses that line? Such that it could be used to draw a line around the text, or color behind it?

let r : CGRect = getRectFromLine(tv,ln)

basically I’m looking to figure out what ‘getRectFromLine’ would need to be.

Sorry I only know how to get the content height of a NSTextView.

If you extract a NSAttributeString from the textContainer, you can calculate it’s bounding rect

But I don’t know if that will give you the starting pointing.

If you want to draw a search highlight, there’s an API for that, which I can look up for you if you wish.

Thanks Sam. What I am wanting to do is to draw an underlying filled rect for what ever line # specified.

What I have discovered… even with mono-spaced fonts, the linespacing can be vastly different … for example 40pt Menlo is 46pts, while 40pt Courier is 48pts…
and Courier takes up less vertical space withing that 48pt.

And to make matters worse… to line text in a Canvas (NSView) to text in an NSTextView (both with the same font and size)…

The Canvas needs to be vertically offset by 9.6pts for Menlo, but only 1pt for Courier
These values were derived from tons of experiments, and attempting to find some equation I could apply using metrics from the fonts … to no avail

Does this help any? I had it saved from when I was doing stuff with ObjC, never tried it though.


1 Like

I haven’t tried this myself, but I think you can specify a background color for a chunk of text using a NSAttributedString.

Cool! Thanks for sharing.

I will look closer… but I think this derives the “line” from the caret… I need to do any Line by “linenumber”

Maybe combine it with this?


Edit: that may have the whole solution in it, I’m not sure.

Well this doesn’t give me the bounding rectangle… but it does “select” the desired line…

func selectLine(textView: NSTextView,lineNumberToSelect : Int) -> Int {
    let layoutManager  = textView.layoutManager
    var numberOfLines  = 0
    var index          = 0
    var lineRange      = NSRange()
    let numberOfGlyphs = layoutManager!.numberOfGlyphs
    while index < numberOfGlyphs {
        numberOfLines += 1
        layoutManager!.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        if numberOfLines == lineNumberToSelect {
        index = NSMaxRange(lineRange);

and I should be able to derive the bounds from the Scroll bar positions and the linespacing both of which I know. There is no word-wrap in this editor, so that makes it a simple multiple and add :slight_smile: