NSMenuItem with attributedTitle not working in macOS 10.12.2 Sierra

471 views Asked by At

I create a menu of file names and modification dates. I align these using an attributed string with a tab stop set to fit the longest file name. This works fine on macOS 10.8-10.11.

This is what the menu should look like - on macOS 10.11 and 10.12.1:

macOS10.11 menu

On Sierra 10.12.2 it now looks like this:

macOS10.12 menu

The code is the same on all platforms:

#define FILEICONSIZE         16.0
#define FILEDATELEADINGSPACE 16.0

...

- (void)rebuildMenu:(NSMenu *)menu fromFiles:(NSMutableArray <FileRepresentation *> *)files
{
    NSMenuItem *item = [menu itemWithTitle:NSLocalizedString(@"Open iCloud", nil)];
    NSMenu *icloudFilesMenu = item.submenu;
    if (!icloudFilesMenu)
        return;

    static NSImage *icon;
    if (!icon) {
        icon = [NSImage imageNamed:@"SSDoc"];
        icon.size = NSMakeSize(FILEICONSIZE, FILEICONSIZE);
    }

    [icloudFilesMenu removeAllItems];

    NSDictionary *stdAttributes = @{ NSFontAttributeName: [NSFont menuBarFontOfSize:0] };
    NSDictionary *ttAttributes  = @{ NSFontAttributeName: [NSFont toolTipsFontOfSize:0] };

    // get max width of filename
    CGFloat maxWidth = 0;
    for (FileRepresentation *f in files) {
        NSMutableAttributedString *attribTitle;

        attribTitle = [[[NSAttributedString alloc] initWithString:f.fileName attributes:stdAttributes] mutableCopy];
        [attribTitle addAttribute:NSParagraphStyleAttributeName
                            value:[NSParagraphStyle defaultParagraphStyle]
                            range:NSMakeRange(0, f.fileName.length)];
        NSRect rect = [attribTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
                                                options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading];
        if (rect.size.width > maxWidth)
            maxWidth = rect.size.width;
    }
    maxWidth += FILEDATELEADINGSPACE;
    NSMutableParagraphStyle *tabbedStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    tabbedStyle.tabStops = @[[[NSTextTab alloc] initWithTextAlignment:NSLeftTextAlignment location:maxWidth options:@{}]];

    // build file menu
    for (FileRepresentation *f in files) {
        NSMutableAttributedString *attribTitle;
        NSString *fname;

        fname = [f.fileName stringByAppendingString:@"\t"];
        item = [[NSMenuItem alloc] initWithTitle:fname action:@selector(openFile:) keyEquivalent:@""];

        attribTitle = [[[NSAttributedString alloc] initWithString:fname attributes:stdAttributes] mutableCopy];
        [attribTitle addAttribute:NSParagraphStyleAttributeName
                            value:tabbedStyle
                            range:NSMakeRange(0, fname.length)];

        // append file date in tool tip font
        if (f.modDate) {
            NSAttributedString *attribfDate;
            NSString *fdate = [((AppController *)[(NSApplication *)NSApp delegate]).fileDateFormatter stringFromDate:f.modDate];
            attribfDate = [[NSAttributedString alloc] initWithString:fdate attributes:ttAttributes];
            [attribTitle appendAttributedString:attribfDate];
        }

        item.attributedTitle = attribTitle;
        item.target = self;
        item.enabled = YES;
        item.representedObject = f.url;
        item.image = icon;

        [icloudFilesMenu addItem:item];
    }
}

Any thoughts?

1

There are 1 answers

0
Harry On BEST ANSWER

I found that setting NSParagraphStyle's firstLineHeadIndent or headIndent property to a number greater than 0 would trick it into working again.

tabbedStyle.tabStops   = ... 
tabbedStyle.headIndent = DBL_EPSILON; // A tiny number so the indent is not noticeable