Appending NSAttributedStrings not working as expected - macos

I'm trying to append attributed strings to make chord names like "G#m7" where the # and 7 are superscript. I'm doing it like this:
NSFont* font = [NSFont fontWithName:kGillSans size:24];
NSMutableDictionary* attributeNormal = [[NSMutableDictionary alloc] init];
[attributeNormal setObject:font forKey:NSFontAttributeName];
[attributeNormal setObject:color forKey:NSForegroundColorAttributeName];
NSFont* fontSmall = [NSFont fontWithName:kGillSans size:14];
NSMutableDictionary* attributeSuperScript = [[NSMutableDictionary alloc] init];
[attributeSuperScript setObject:fontSmall forKey:NSFontAttributeName];
[attributeSuperScript setObject:[NSNumber numberWithInteger:5] forKey:NSSuperscriptAttributeName];
[attributeSuperScript setObject:color forKey:NSForegroundColorAttributeName];
NSAttributedString* pitch = [[NSAttributedString alloc] initWithString:#"G" attributes:attributeNormal];
NSAttributedString* accidental = [[NSAttributedString alloc] initWithString:#"#" attributes:attributeSuperScript];
NSAttributedString* quality = [[NSAttributedString alloc] initWithString:#"m" attributes:attributeNormal];
NSAttributedString* seventh = [[NSAttributedString alloc] initWithString:#"7" attributes:attributeSuperScript];
NSMutableAttributedString* fullString = [[NSMutableAttributedString alloc] initWithAttributedString:pitch];
[fullString appendAttributedString:accidental];
[fullString appendAttributedString:quality];
[fullString appendAttributedString:seventh];
I then add this to a CATextLayer for display. Unfortunately, it's not working as expected. The superscripts are not superscript, and the [fullstring size] that is returned with it is way off, resulting in a hard to place layer. I turned the border width on to demonstrate the size issue.
I've experimented with different font sizes and values for the superscript attribute. Any ideas?

Try this:
NSFont* font = [NSFont fontWithName:#"GillSans" size:24];
NSDictionary * attributeNormal = #{NSFontAttributeName: font,
NSForegroundColorAttributeName: [NSColor blackColor]};
NSFont* fontSmall = [NSFont fontWithName:#"GillSans" size:14];
NSDictionary * attributeSuperScript = #{NSFontAttributeName: fontSmall,
NSSuperscriptAttributeName: #(2),
NSForegroundColorAttributeName: [NSColor blackColor]};
NSMutableAttributedString* fullString =
[[NSMutableAttributedString alloc]
initWithAttributedString:[[NSAttributedString alloc]
initWithString:#"G"
attributes:attributeNormal]];
[fullString appendAttributedString:
[[NSAttributedString alloc] initWithString:#"#"
attributes:attributeSuperScript]];
[fullString appendAttributedString:
[[NSAttributedString alloc] initWithString:#"m"
attributes:attributeNormal]];
[fullString appendAttributedString:
[[NSAttributedString alloc] initWithString:#"7"
attributes:attributeSuperScript]];

Related

Looking for simple example to write text into a NSImage using Cocoa

NSImage *myNewIconImage=[[NSImage imageNamed:#"FanImage"] copy];
[myNewIconImage lockFocus];
[#"15" drawAtPoint:NSZeroPoint withAttributes:nil];
[myNewIconImage unlockFocus];
[myNewIconImage setTemplate:YES];
[[NSApplication sharedApplication]] setApplicationIconImage:myNewIconImage];
I am looking for a way to simply write a String onto this image.... and coming up very short. This does not worker me.
The following code will place a mutable attributed string on an NSImage:
NSImageView *imageView = [[NSImageView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW, _wndH )];
[[window contentView] addSubview:imageView];
NSImage *image = [NSImage imageNamed:#"myImage.jpg"];
[image lockFocus];
NSMutableDictionary *attr = [NSMutableDictionary dictionary];
[attr setObject:[NSFont fontWithName:#"Lucida Grande" size:36] forKey:NSFontAttributeName];
[attr setObject: [NSNumber numberWithFloat: 10.0] forKey: NSStrokeWidthAttributeName];
[attr setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName];
NSString *myStr = #"Welcome to Cocoa";
NSMutableAttributedString *s = [[NSMutableAttributedString alloc] initWithString: myStr attributes:attr];
[s drawAtPoint:NSMakePoint(130,130)];
[image unlockFocus];
[imageView setImage:image];

NSMutableAttributedString set font size

Every resource I keep coming across for this is for iOS. I can't seem to get this working properly for Mac OSX. Any idea how to get this to set the font size as well? It currently sets the color and center alignment properly. Thanks
NSMutableAttributedString *libTitle = [[NSMutableAttributedString alloc] initWithString:#"Library"];
[libTitle addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor] range:NSMakeRange(0,[#"Library" length] ) ];
[libTitle setAlignment:NSCenterTextAlignment range:NSMakeRange(0, [#"Library" length])];
[libTitle addAttribute:NSFontSizeAttribute value:[NSFont systemFontOfSize:18.0] range:NSMakeRange(0, [#"Library" length])];
[self.libbtn setAttributedTitle:libTitle];
Try setting your font attributes from the get go, in the init method:
NSFont *systemFont = [NSFont systemFontOfSize:18.0f];
NSDictionary * fontAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:systemFont, NSFontAttributeName, nil];
NSMutableAttributedString *libTitle = [[NSMutableAttributedString alloc] initWithString:#"Library" attributes:fontAttributes];
NSRange rangeOfTitle = NSMakeRange(0,[libTitle length]);
[libTitle addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor] range:rangeOfTitle];
[libTitle setAlignment:NSCenterTextAlignment range:rangeOfTitle];
[self.libbtn setAttributedTitle:libTitle];

Merging RTF Files With Cocoa

How would one do this? I know just merging NSData doesn't work.
Playing with NSAttributedString should work, something like the code shown below
This is a very quick and dirty way to merge many RTF files together
- (void)mergeRTF:(NSURL*)rtf1 :(NSURL*)rtf2 :(NSURL*)merged {
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithUnsignedInteger:NSUTF8StringEncoding]
forKey:NSCharacterEncodingDocumentOption];
NSDictionary *docAttrs = nil;
NSError* error = nil;
NSAttributedString *rtfText1 = [[NSAttributedString alloc] initWithURL:rtf1
options:options
documentAttributes:&docAttrs
error:&error];
NSAttributedString *rtfText2 = [[NSAttributedString alloc] initWithURL:rtf2
options:options
documentAttributes:&docAttrs
error:&error];
NSMutableAttributedString* whole = [[NSMutableAttributedString alloc] initWithAttributedString:rtfText1];
[whole appendAttributedString:rtfText2];
NSData* data = [whole RTFFromRange:NSMakeRange(0, whole.length) documentAttributes:nil];
[data writeToURL:merged atomically:YES];
}

Can set either alignment or font, but not both, for NSTextField

I have a panel nib with an outlet for one of its textfields, which is set in the nib to have centered alignment. When I display the panel, I would like this textfield to be bolded.
Since NSTextField is a subclass of NSControl, it can use the setAttributedStringValue method and take an attributed string. So I incorporated a bold font like this:
NSFont *fontBolded = [NSFont fontWithName:#"Baskerville Bold" size:12.0f];
NSDictionary *dictBoldAttr = [NSDictionary dictionaryWithObject:fontBolded forKey:NSFontAttributeName];
NSString *sHelloUser = NSLocalizedString(#"Hello User", #"Hello User");
NSAttributedString *attrsHelloUser = [[NSAttributedString alloc] initWithString: sHelloUser attributes:dictBoldAttr];
[self.fooController.tfPanelCenteredField setAttributedStringValue:attrsHelloUser];
[attrsHelloUser release];
The bolding shows up OK, but the field is now left-aligned.
I tried adding a setAlignment, but it had no effect:
[self.fooController.tfPanelCenteredField setAlignment:NSCenterTextAlignment];
So I tried adding a centered parapraph style to the attributed string’s attributes:
NSFont *fontBolded = [NSFont fontWithName:#"Baskerville Bold" size:12.0f];
NSMutableParagraphStyle *paragStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragStyle setAlignment:NSCenterTextAlignment];
NSDictionary *dictBoldAttr = [NSDictionary dictionaryWithObjectsAndKeys:paragStyle, NSParagraphStyleAttributeName, fontBolded, NSFontNameAttribute, nil];
NSString *sHelloUser = NSLocalizedString(#"Hello User", #"Hello User");
NSAttributedString *attrsHelloUser = [[NSAttributedString alloc] initWithString: sHelloUser attributes:dictBoldAttr];
[self.fooController.tfPanelCenteredField setAttributedStringValue:attrsHelloUser];
[attrsHelloUser release];
[paragStyle release];
Now the textfield is centered again, but the bolding is gone. It’s as though the attributed string can accept one and only one attribute setting. Am I missing something simple?
You have a typo in your code. NSFontNameAttribute should be NSFontAttributeName.
So your attributes dictionary is:
NSFont *fontBolded = [NSFont fontWithName:#"Baskerville Bold" size:12.0f];
NSMutableParagraphStyle *paragStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragStyle setAlignment:NSCenterTextAlignment];
NSDictionary *dictBoldAttr = [NSDictionary dictionaryWithObjectsAndKeys:
fontBolded, NSFontAttributeName,
paragStyle, NSParagraphStyleAttributeName,
nil];

Is it possible to draw strings with custom paragraph styles in CATextLayer?

I want to draw a list like this:
1. List item 1
2. List item 2
3. List item 3
Here is my code:
NSTextList *list = [[NSTextList alloc] initWithMarkerFormat:#"{decimal}" options:0];
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraph setTextLists:[NSArray arrayWithObject:list]];
[list release];
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:paragraph, NSParagraphStyleAttributeName, nil];
NSString *string = #"List item 1\nList item 2\nList item 3"
NSMutableAttributedString *attrString = [[[NSMutableAttributedString alloc] initWithString:string attributes:attributes] autorelease];
[paragraph release];
Then I set the attrString to the string property of CATextLayer, but paragph style isn't applied to the result.
Yes, it's possible. You can create NSAttributedString by using either initWithHTML* or initWithRTF* method.
If you want to create list programmatically, you can use NSTextTab in tandem with NSTextList. But you have to manually format string:
NSTextList *list = [[NSTextList alloc] initWithMarkerFormat:#"square" options:0];
NSMutableParagraphStyle *paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraph setTextLists:[NSArray arrayWithObject:list]];
NSTextTab *t1 = [[NSTextTab alloc] initWithType:0 location:11.0f];
NSTextTab *t2 = [[NSTextTab alloc] initWithType:0 location:36.0f];
[paragraph setTabStops:[NSArray arrayWithObjects:t1, t2, nil]];
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:paragraph, NSParagraphStyleAttributeName, nil];
NSString *string = #"\t▪\tList item 1\n\t▪\tList item 2\n\t▪\tList item 3";
NSMutableAttributedString *attrString = [[[NSMutableAttributedString alloc] initWithString:string attributes:attributes] autorelease];
[paragraph release];
[list release];
[t1 release];
[t2 release];

Resources