NSTextField - make selected text bold, italic or underline? - objective-c

I have an NSTextField where the user can write text. I would like to be able to make 3 buttons: bold, italic and underline; these buttons should change the user selection in the textfield to either bold, italic or underline.
Can anyone give me a pointer on how to do this?

The first thing is to enable rich text support, and you can do it either in Interface Builder by checking the "Rich Text" option in the inspector or by code using setAllowsEditingTextAttributes:.
Then it's all about NSAttributedStrings.
The big problem though is that looks like you need to apply changes to the selected text. This is not possible with NSTextFields. Only with NSTextViews.
If you can change it, go ahead and it will make things easier. However, if you do need to stick with NSTextField you may want to access the field editor. Each window has one associated, and it's what process the text behind the scenes.
NSTextView *editor = (NSTextView *)[window fieldEditor:YES forObject:myTextField]
Then you can call NSTextView's method setSelectedTextAttributes: happily.
Read more about the field editor here at Apple and in CocoaDev

Assuming your NSTextfield * is textField, the code below underlines the selection:
NSMutableAttributedString * as = [[[textField attributedStringValue] mutableCopy] autorelease];
[as beginEditing];
[as addAttribute:NSUnderlineStyleAttributeName
value:[NSNumber numberWithInt:NSUnderlineStyleSingle]
range:[[[textField window] fieldEditor:YES forObject:textField] selectedRange]];
[as endEditing];
[textField setAttributedStringValue:as];

Related

Insert a hyperlink in UILabel

i have a response coming in from the api in form of a text I want to scan that text for the word "Planned Parenthood health center" and insert a hyperlink on that word which redirects to plannedparenthood.org/health-center portal.
my approach:
NSString *text = response.content;
text = [text stringByReplacingOccurrencesOfString:#"Planned Parenthood health center"
withString:#"Planned Parenthood health center"];
though the link on the text is getting replaced. It is getting replaced by
Planned Parenthood health center
What's wrong why am I not getting any links there? am I doing something wrong I have also set the user enabled interaction to YES
iOS does not handle this well to be honest probably because it intends you to use UIButtons which are much more easily tappable for users.
To accomplish what you want though, you cannot use a UILabel - you need to use a UITextView and set its attributedText property:
NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:#"Planned Parenthood health center"];
[attributedString addAttribute: NSLinkAttributeName value: #"http://www.plannedparenthood.com" range: NSMakeRange(0, str.length)];
textView.attributedText = attributedString;
Note that the UITextView must be selectable but not editable.
There is a bit of a downside with this method if you have other text in your attributed string that isn't linked. For example, if you have "Please select here in order to go to Planned Parenthood's website" where "here" is the only part of the text that you want linked. In this case, if you tap anywhere else in the text beside the word "here", you'll notice that it will be able to be selected by the user and have the blue highlight.
If using a UITextView is not desired, then you will need to use something custom such as TTTAttributedLabel

Click on UILabel and perform action

I have a simple problem, I have a string like "#my#name#is#umesh#verma" and assign to a UITableview cell label,
cell.detaillabel.text = #"#my#name#is#umesh#verma";
My Problem is how to get each word name when I click on single item.
If I click on #umesh then I get "umesh" word..
More better solution is add custom label which supports touches. For example TTTAttributedLabel supports touches on links.
Main task is get notification when user touch a word and to identify the word.
You can add URLs (with special format) to any word and subscribe to a notification when user click it (as delegate to the label). For example you can create this URL for "word":
touchscheme://word
I haven't checked about how to perform an action when clicking on a UILabel. However, I experienced that with UITextView. You can use "NSLinkAttributeName" to do that.
Basically, from your original string, try to find the range of string that you need to trigger actions. Then add a link value.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:yourString];
[attributedString addAttribute:NSLinkAttributeName value:url range:range];
[textView setAttributedText:attributedString];
Set delegate to your textView and handle the following method
-(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{
// You can retrive your string here or perform an action
return YES;
}
Hope this would be helpful for you.

NSTextView color and font reset after clearing it

I set some default font and color to a NSTextView inside of a NSPanel.
However, when I clear the view with setString:#"", not only does the text disappears, but all the default colors/fonts formatting.
After I do another setString, the text becomes the default font and black again.
Can someone explain why that is and what can I do to remedy it?
UPDATED:
Thanks for the help and clarification of the issue.
I ended up just formatting it again after I setString.
[self.txtLog setFont:[NSFont fontWithName:#"courier" size:12]];
[self.txtLog setTextColor:[NSColor colorWithSRGBRed:65.0/255 green:229.0/255 blue:235.0/255 alpha:1]];
It is because clearing the NSTextView and setting a regular (non-attributed) string removes the formatting, which includes font and color.
Most of the time, I set attributed strings that I format using HTML. I find it to be very convenient. For instance, here are two macro I use to set the color and the font:
#define color(string, color) strAdd5(#"<font color=\"#",(color), #"\">", (string), #"</font>")
#define fontName(string, fontname) strAdd5(#"<span style=\"font-family: ",(fontname), #";\">", (string), #"</span>")
#define html2AttributedString(htmlString) [[[NSAttributedString alloc] initWithHTML:[(htmlString) dataUsingEncoding:NSUTF8StringEncoding]documentAttributes:NULL] autorelease]
Then, all I need is to set the attributed string in the text storage:
[textStorage setAttributedString:html2AttributedString(color(myNSString, #"FF0000"))]
or to use insertText of NSTextView
[textView insertText:html2AttributedString(fontName(myNSString, #"Courier New"))];
And using HTML, you can define everything including centering, and many other properties. But, you have to convert any new lines into < BR / > before converting the text.

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]];

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).