3

Context:

In Interface Builder I have a non-editable label (NSTextField). The contents of the label is created using Cocoa Bindings. The value of the binding is an NSAttributedString (created using a talue transformer). See image:

Binding

The value transformer essentially specifies the font for specific characters, as per Markdown formatting (i.e. Italic and Bold). Such that String --> NSAttributedString. The label's attributedStringValue is changed appropriately

Issue:

When selecting the label in the UI. The font resets to what is specified in IB, and not what was set as the NSAttributedString. If you don't select the text then everything looks good.

Before clicking on the label:

enter image description here

After clicking/selected the label:

enter image description here

Attempted Solutions:

  • I've tried subclassing NSTextField but there's nothing really to override that enables me to disable any font changes when the text is selected.
  • I've tried disabling rich text. This actually helps a lot by not changing the normal text, but it still strips the formatting from the bold and italic text
  • Most similar issues out there are with NSTextViews not NSTextFields
Community
  • 1
  • 1
Wesley McCloy
  • 355
  • 4
  • 12

3 Answers3

11

You need to set allowsEditingTextAttributes = true

For example:

class ViewController: NSViewController {

dynamic var markdownText : String?

@IBOutlet weak var label: NSTextField!

override func viewDidLoad() {

    super.viewDidLoad()

    label.allowsEditingTextAttributes = true
}
}

Then you can select text as in my example:

enter image description here

Here is the code:https://github.com/emankovski/BindingFormattedText

Eugene Mankovski
  • 1,180
  • 10
  • 16
  • This in part solves my issue! Thanks! I now have an other problem where my font size is set in IB and when selecting the text, the font size gets reset. I think my solution will be to have a Markdown value transformer for each required font size. If there's a way to get the font size from IB then let me know! – Wesley McCloy Aug 17 '16 at 17:58
  • 1
    I would create base markdown value transformer with all the logic. Then create as many subclasses as needed just overriding base class member to get font size. Then your transformers will be really small. Just one or two lines of code. – Eugene Mankovski Aug 17 '16 at 20:41
2

I believe I found the solution to this issue, which seems unsolved based on the original poster's comments above.

I had an NSTextField that was selectable but not editable. The text was set by creating NSAttributedString with font and text color attributes, and passing this to the NSTextField's setAttributedStringValue method.

The problem as that the line spacing of the text was wrong until I clicked a text field and then clicked a different text field, as shown in the GIF below. Once the clicking was done, the text displayed properly.

enter demonstration of the problem

Upon examining the text attributes of the NSTextField before and after editing, I noticed that NSOriginalFont was set to .AppleSystemUIFont 12pt instead of my font, which was Helvetica Neue 11pt.

BEFORE

NSFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";
NSOriginalFont = "\".AppleSystemUIFont 12.00 pt. P [] (0x600000d8f0f0) fobj=0x10361b1a0, spc=3.39\"";

AFTER:

NSFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";
NSOriginalFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";

I solved the problem by setting the NSAttributedString's font attribute not only NSFontAttributeName (i.e., @"NSFont") but also @"NSOriginalFont".

[controlText removeAttribute:NSFontAttributeName range:(NSMakeRange(0, len))];
[controlText addAttribute:NSFontAttributeName value:font range:(NSMakeRange(0, len))];
[controlText removeAttribute:@"NSOriginalFont" range:(NSMakeRange(0, len))];
[controlText addAttribute:@"NSOriginalFont" value:font range:(NSMakeRange(0, len))];
Mark Coniglio
  • 351
  • 1
  • 10
0

Swift 5 solution

First you need to set this property for your NSTextField

cell.textField?.allowsEditingTextAttributes = true

Then, where you are creating the NSAttributedString, do this first

// Default font and color, to be used where no attritubes are set
let default_font = NSFont(name: "Courier New", size: 14)
let default_color = NSColor.white
let entire_str_range = NSMakeRange(0, text.string.count)

mutable_attr_str.removeAttribute(NSAttributedString.Key.font, range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key.font, value: default_font!, range: entire_str_range)

mutable_attr_str.removeAttribute(NSAttributedString.Key.foregroundColor, range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key.foregroundColor, value: default_color, range: entire_str_range)

mutable_attr_str.removeAttribute(NSAttributedString.Key(rawValue: "NSOriginalFont"), range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key(rawValue: "NSOriginalFont"), value: default_font!, range: entire_str_range)

Then set up your NSAttributedString however you like. When clicked, it should keep your additional attributes, and the parts of the string with no attributes will default to the above font and color.

Sean Mayes
  • 158
  • 10