Mac OSX: How to stroke text in NSTextField? - objective-c

I've programming an application for the OSX using Objective C. I have an NSTextField that I'm using to display uneditable text. I'm trying to make the font have a thin stroke/outline around it but struggling to do so.
I've tried to use NSTextView instead of NSTextField and implemented an NSAttributedString as so, however the text is not being outlined at all:
NSAttributedString *string = [[NSAttributedString alloc] initWithString:#"Test String" attributes:#{ NSStrokeColorAttributeName : [CIColor blackColor], NSForegroundColorAttributeName : [CIColor blackColor], NSStrokeWidthAttributeName : #-1.0 }];
[quoteText_Label setEditable:YES];
[quoteText_Label insertText: string];
[quoteText_Label setEditable:NO];
Looking at the other question of SO, they're either aimed at iOS, Swift, or are an overkill for the simple implementation I'm attempting to go for: just a simple black stroke around white font.
Thank you

Switch on Rich Text in the XIB and set the attributedStringValue property of the text field. You don't have to do setEditable.
Read the documentation of NSStrokeWidthAttributeName:
NSNumber containing floating point value, as percent of font point size
Default 0, no stroke; positive, stroke alone; negative, stroke and fill (a typical value for outlined text would be 3.0)
A thin black outline around black text is hardly visible.

Values of the color attributes should be NSColor objects. I think, using CIColor is wrong here.

Related

Image and Text locations in UIButton

Im trying to put a UIImage and text into a UIButton, by using UIEdgeInset to locate them.
The problem is, changing one of the edgeinset setting will cause both the image and the text to change the position.
Which means, I put the image to the correct position, then I change the titleEdgeInset values, suddenly not only the text but also the image changed the position.
Any one can help out please?
According the Apple's documentation this won't happen. Did you check to make sure you have negative insets and not positive?
The insets you specify are applied to the title rectangle after that rectangle has been sized to fit the button’s text. Thus, positive inset values may actually clip the title text.
This property is used only for positioning the title during layout.
The button does not use this property to determine
intrinsicContentSize and sizeThatFits:.
I hope this may helps you
#property (strong, nonatomic) IBOutlet UIButton *Imagetext;
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"Click Me"];
NSTextAttachment *ImageAttachment = [[NSTextAttachment alloc] init];
ImageAttachment.image = [UIImage imageNamed:#"add.png"];
NSAttributedString *attributedWithImage = [NSAttributedString attributedStringWithAttachment:ImageAttachment];
[attributedString replaceCharactersInRange:NSMakeRange(6, 0) withAttributedString:attributedWithImage];
// [attributedString appendAttributedString:attributedWithImage];
[self.Imagetext setAttributedTitle:attributedString forState:UIControlStateNormal];

Force Lucida Grande Font in a Yosemite Cocoa app

I have a requirement for some labels in my app to use Lucida Grande. When I specify this font in Xcode it renders correctly in the xib, but when you launch the app in Yosemite it switches back to Helvetica Neue.
How can I get this to work correctly?
As per Ken's advice, setting the font manually in the awakeFromNib() method gives the correct result.
You can either set the font property of the NSTextField
[self.myLabel setFont:[NSFont fontWithName:#"Lucida Grande" size:50.f]];
or use an NSAttributedString
NSDictionary *attributes = #{ NSFontAttributeName : [NSFont fontWithName:#"Lucida Grande" size:50] };
NSAttributedString *text = [[NSAttributedString alloc] initWithString:#"Hello" attributes:attributes];
[self.myLabel setAttributedStringValue:text];
Interestingly, in many cases I have seen fonts with spaces in the font name input with dashes, i.e. #"Lucida-Grande", this actually breaks the output, dashes must be omitted.

Changing the font of the selected text in Objective-C

I'm trying to create a custom “Change font” NSPopupButton for a Mac App (not an iOS App). I can detect a change in font selection:
long fontItemIndex = [fontPopup indexOfSelectedItem];
NSMenuItem *fontItem = [fontPopup itemAtIndex:(int)selectedFontItemIndex];
NSString *fontName = [selectedFontItem title];
Given this NSString of a font name, I cannot seem to find out how to actually change the selected text in my NSTextView textView to this new font.
I'm simply dazzled by the official documentation: it seems convertFont:toFamily: is what I need. When I do this:
NSFont *font = [NSFont fontWithName:fontName size:12.0];
[textView setFont:font];
It sets all text in the text view, not just the selected text. But when I do this:
NSFontManager *fontManager = [NSFontManager sharedFontManager];
[fontManager convertFont:[fontManager selectedFont] toFamily:fontName];
it doesn't do a thing. What am I missing?
Inside a NSTextView is a NSTextStorage (a subclass of NSAttributedString) and you’ll have to modify the attribute named NSFontAttributeName.
First get the range where you want to change the font attribute:
NSRange selection = textView.selectedRange;
Now add the font attribute to the selection:
NSFont *font = [NSFont fontWithName:fontName size:12.0f];
[self.textView.textStorage addAttributes:#{NSFontAttributeName: font}
range:selection];
Depending on the contents of your NSPopUpButton it should be enough to call fontWithName:size: with title as the font name to get the just selected font. But if the method you already do doesn’t work, you’ll probably have to get a specific font from the font family name. availableMembersOfFontFamily: on NSFontManager will give you a list of all available fonts. You can use one of them to initialize a specific font.
Take a look at the setFont:range: method on NSText, the superclass of NSTextView.
(The ranges, of course, come from the selectedRanges property on NSTextView.)
This was all I needed to change all the text in my textview.
[textview setFont:[NSFont fontWithName:#"Courier" size:14]];

NSTextView with shadow

I'm trying to add a nice looking shadow to a NSTextViews string, I have this Code so far:
NSShadow *textShadow = [[NSShadow alloc] init];
textShadow.shadowColor = [[NSColor blackColor]
colorWithAlphaComponent:0.3];
textShadow.shadowOffset = NSMakeSize(5.0, -5.0);
textShadow.shadowBlurRadius = 3;
NSDictionary *d = #{NSShadowAttributeName : textShadow,
NSFontAttributeName : [NSFont fontWithName:#"Arial Black" size:36.0],
NSStrokeWidthAttributeName : [NSNumber numberWithFloat:-3.0],
NSStrokeColorAttributeName : [NSColor whiteColor]};
[tv setTypingAttributes:d];
all in all this brings up a pretty looking Drop shadow on the right and the bottom of the string in the NSTextView but because the internal drawing mechanism of the textview seems to draw the "fill" of the Characters first and then the stroke around it, the Shadow lays above the fill of the text in the upper left of the Chars, which looks very bad as you can see here(would post an Image but not enough reputation right now 8-/ )
Is there a better way to add the shadow or a way to "raise" the fill color of the String so it lays above the shadow or is this kind of a Bug in the Foundation framework?
Thanks and greetings,
Alex.

NSTextField add line spacing

I use NSTextField not NSTextView to receive the user input, but I need to custom the font and textColor and line spacing. I use the code below, it's ok for font and color but I don't know how to set a line spacing.
[self.titleField setTextColor:textColor];
[self.titleField setFont:bold14];
And I also use a NSAttributedString to solve the problem:
NSFont *bold14 = [NSFont boldSystemFontOfSize:14.0];
NSColor *textColor = [NSColor redColor];
NSMutableParagraphStyle *textParagraph = [[NSMutableParagraphStyle alloc] init];
[textParagraph setLineSpacing:10.0];
NSDictionary *attrDic = [NSDictionary dictionaryWithObjectsAndKeys:bold14, NSFontAttributeName, textColor, NSForegroundColorAttributeName, textParagraph, NSParagraphStyleAttributeName, nil];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:title attributes:attrDic];
[self.titleField setAllowsEditingTextAttributes:YES];
[self.titleField setAttributedStringValue:attrString];
the code above is ok to show a attributed string, but when I delete the string in the textfield and start to input, the words come without any attribute.
How can I input a string in NSTextField with custom font, color and line spacing?
It's best to stay with NSTextField's attribute setting methods instead of an NSAttributedString because then it can send the settings to the field editor. Every text field has an NSTextView (most of the time) "Field Editor"; and the field editor is what is doing the editing.
Your NSAttributedString isn't sticking because you're only telling the textfield to temporarily display that one string. When the field editor pops up the text field (cell) passes on its own attributes like textField.font and textField.textColor but never the NSAttributedString's attributes.
It would be best to use an NSTextView to be able to use -setDefaultParagraphStyle because you're editing multiple lines anyways, from what I see. If you can't, because of performance problems or something else, then:
Subclass NSTextFieldCell, because that's what does all the NSTextField work, and override
- (NSText *)setUpFieldEditorAttributes:(NSText *)textObj
(declared in NSCell) to set up attributes for your field editor the way you want it, so you can send it a line height value through -setDefaultParagraphStyle (and font etc.) yourself. (textObj is the field editor to be set up).