K307
K307

Reputation: 105

How to detect line breaks in TextView in AppKit?

General idea: highlight groups of characters in a text paragraph in NSScrollView (that contains NSTextView). I am getting bounding rectangle of the chosen characters from NSLayoutManager.boundingRect() and create CAShapeLayer with its coordinates/size in place of the characters.

The problem is that if the character range in question spans two lines, the bounding rectangle would cover both of them in height and width, so I need to do it for every line of the text in the text view.

Issue in question: string properties in NSTextView, NSTextStorage and NSTextContainer return strings without line breaks ("\n"). How can I:

1) find the actual text value of the text view with line breaks?

2) use other techniques to iterate through lines of a text view?

3) use other libraries to accomplish my general idea?

Code of my View Controller:


import Cocoa

class ViewController: NSViewController {


    @IBOutlet weak var textView: NSTextView!
    @IBOutlet weak var shapeView: NSView!


    override func viewDidLoad() {
        super.viewDidLoad()

        shapeView.wantsLayer = true

        textView.string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

    }


    @IBAction func checkButtonPressed(sender: NSButton) {

        let range = NSMakeRange(2, 5) //Creating a makeshift range for testing purposes
        let layoutManager = textView.layoutManager
        var textRect = NSRect()

        //Accessing bounding rectangle of the chosen characters
        textRect = (layoutManager?.boundingRect(forGlyphRange: range, in: textView.textContainer!))!

        //Creating a parent layer and assigning it as the main layer of the shape view
        let parentShapeLayer = CAShapeLayer()
        shapeView.layer = parentShapeLayer

        //Creating an actual rectangle - CAShapeLayer
        let shapeLayer = CAShapeLayer()
        parentShapeLayer.addSublayer(shapeLayer)
        parentShapeLayer.isGeometryFlipped = true
        shapeLayer.frame = textRect
        shapeLayer.backgroundColor = NSColor.yellow.cgColor

        if let string = textView.textStorage?.string {

            for var char in string {
                if (char == "\n") {
                    print(char) //Does not print anything
                }
            }
        }

    }


    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

P.S. I know that NSLayoutManager has method drawBackground() and I was not able to find what context it needs, but it is a different question.

Upvotes: 3

Views: 452

Answers (1)

K307
K307

Reputation: 105

I have found a conceptual workaround: I resorted to drawing rectangles for individual characters, rather than groups of characters, so line break detection was avoided. Not optimal, but works.

Upvotes: 1

Related Questions