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

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

Related

Appending NSAttributedStrings not working as expected

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

Save Array to plist

I'm trying to store some items into a pList. Here is the array loop:
for (id obj in items)
NSLog(#"obj: %#", obj);
Output NSLog:
2013-03-27 13:00:40.072 mycode[47436:c07] obj: Red
2013-03-27 13:00:40.073 mycode[47436:c07] obj: Blue
2013-03-27 13:00:40.073 mycode[47436:c07] obj: Green
// The arrayWithObjects works. But I don't know how to (loop?) through my items for saving into the plist file...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: path]) {
NSLog(#"%#", path);
NSMutableDictionary *plist = [[NSDictionary dictionaryWithContentsOfFile:path] mutableCopy];
NSMutableArray *newArray = [[[NSMutableArray alloc] init] autorelease];
newArray = [NSArray arrayWithObjects:#"Red", #"Green", #"Blue" nil]; // <--- WORKS!
newArray = [NSArray arrayWithObjects:items, nil]; // <-- ?
[plist setObject:newArray forKey:#"Hi"];
[plist writeToFile:path atomically:YES];
[plist release];
} else {
NSLog(#"File not found");
}
[filemgr release];
Maybe this piece of code helps you.
NSMutableArray *newArray = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray *targetArray = [[[NSMutableArray alloc] init] autorelease];
newArray = [NSArray arrayWithObjects:#"Red", #"Green", #"Blue" nil];
for(int i=0;i<newArray.count;i++)
{
[targetArray addObject:[newArray objectAtIndex:i]];
}
[plist setObject:targetArray forKey:#"Hi"];
[plist writeToFile:path atomically:YES];
or another method
NSMutableArray *targetArray = [[[NSMutableArray alloc] init] autorelease];
for (id obj in items)
{
[targetArray addObject:items];
}
[plist setObject:targetArray forKey:#"Hi"];
[plist writeToFile:path atomically:YES];
Hope this helps !!!

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

How to solve: Why is coreData(NSFetchedResultsController) sorting differently in iOS5 and iOS4

i have a tableview which is populated with NSFetchedResultsController.
On didSelectRowAtIndexPathi am updating the current row. The sorting here should not change. The difference in the selected row is, that i mark it as read. No title changes or something.
In iOS4 the row gets updated and still leave on his current place, it does not move to the end of section. Thats the right way.
in iOS5 the row gets also updated but it moves to the end of the Section. I want to prevent that. How can i do that? And why is that happening?
See my code:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"EntitySetsCardsInbox" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *inboxPred = [NSPredicate predicateWithFormat:#"archived == 0 AND cardId != 0"];
[fetchRequest setPredicate:inboxPred];
if (sortString == nil) {
//sortString = [[NSString alloc] initWithString:#"sortingOrder"];
sortString = [[NSString alloc] initWithString:#"colorOrder"];
sortAsc = NO;
}
if ([sortString isEqualToString:#"cardTitle"]) {
NSSortDescriptor *sortDescriptor2 = [[[NSSortDescriptor alloc] initWithKey:sortString ascending:sortAsc selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:sortDescriptor2, nil] autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
XLog(#"sortDescriptors: %#", sortDescriptors);
} else {
NSSortDescriptor *sortDescriptor2 = [[[NSSortDescriptor alloc] initWithKey:sortString ascending:sortAsc] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:sortDescriptor2, nil] autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
XLog(#"sortDescriptors: %#", sortDescriptors);
}
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[...]
}
i think your sortdescriptor is changing when you updating your rows. add one more sortdescriptor to fix the list with it and check it again. in my case i have a very similar issue and it solved my problem. maybe yours, too.

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

Resources