Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attributed string hyperlink not showing proper cursor

I'm following an example from Apple to create a hyperlink in a NSTextField (via an attributed string), and though the hyperlink itself works, there is an issue with the cursor. Namely, when you hover over the hyperlink, it displays the normal I-beam cursor until you click it. After clicked once, it displays the proper pointing-hand cursor.

I've searched for a while and there doesn't seem to be an easy answer to this issue, which is confusing because hyperlinks seem as if they would be pretty common. People have suggested using hyperlinked NSButtons (how do you get underline on hover, then?) and NSTextViews previously, but that seems sort of hack-y. What's the proper way to do hyperlinks in OSX programming?

Note: I stumbled across this article which shows a way of doing this with textviews and "category". Is this the proper way to do things? I want to be writing maintainable and clean code.

Thank you!

like image 682
Connor Avatar asked Mar 20 '23 05:03

Connor


2 Answers

Building on Apple's example and @stevesliva's answer, here's what I came up with:

import Cocoa

extension NSAttributedString {

    /// Return an attributed string that looks like a hyperlink
    ///
    /// Based on code at <https://developer.apple.com/library/mac/qa/qa1487/_index.html>
    ///
    /// - parameters:
    ///    - string: text to be turned into a hyperlink
    ///    - URL: destination of the hyperlink
    /// - returns: `NSAttributedString`
    static func hyperlinkFromString(string: String, withURL URL: NSURL) -> NSAttributedString {

        let attrString = NSMutableAttributedString(string: string)
        let range = NSMakeRange(0, attrString.length)

        attrString.beginEditing()

        attrString.addAttribute(NSLinkAttributeName,
            value: URL.absoluteString,
            range: range)

        attrString.addAttribute(NSForegroundColorAttributeName,
            value: NSColor.blueColor(),
            range: range)

        attrString.addAttribute(NSUnderlineStyleAttributeName,
            value: NSNumber(int: Int32(NSUnderlineStyle.StyleSingle.rawValue)),
            range: range)

        attrString.fixAttributesInRange(range)

        attrString.endEditing()

        return attrString
    }
}

/// Subclass of NSTextField used to display hyperlinks
class HyperlinkTextField: NSTextField {
    /// Set content to be a hyperlink
    ///
    /// Based on code at <https://developer.apple.com/library/mac/qa/qa1487/_index.html>
    ///
    /// - parameters:
    ///    - title: text displayed in field
    ///    - URL: destination of hyperlink
    func setHyperlinkWithTitle(title: String, URL: NSURL) {
        allowsEditingTextAttributes = true
        selectable = true
        attributedStringValue = NSAttributedString.hyperlinkFromString(title,
            withURL: URL)
    }

    /// Always display a pointing-hand cursor
    override func resetCursorRects() {
        addCursorRect(bounds, cursor: NSCursor.pointingHandCursor())
    }
}
like image 112
Kristopher Johnson Avatar answered Apr 01 '23 13:04

Kristopher Johnson


Good question! Hyperlinks in OSX controls, while functional, seem a little clunky.

I believe it's because the NSTextField doesn't have the focus until the first click.

The likely solution is to use this related question's answer(s). I was going to copy and paste some code, but the dscussion there is useful. The bottommost answer about how to subclass the view is likely the most robust.

The NSCursor class methods contain a list of the other possible cursor types.

like image 38
stevesliva Avatar answered Apr 01 '23 12:04

stevesliva