2

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?

MichaelR
  • 1,681
  • 15
  • 28
  • Under which macOS, are you running the debugger with what Xcode version? – El Tomato Dec 19 '16 at 22:20
  • The date doesn't have the tab stops style? – Willeke Dec 20 '16 at 01:17
  • HI @ElTomato the screenshots were not made using the debugger - but normally running processes. Using Xcode 8.2 – MichaelR Dec 20 '16 at 07:27
  • @Willeke - thank you - good suggestion. I tried applying the tabbed style to the entire attributed string - and unfortunately the result is just the same (ok on 10.11 not on 10.12). If you NSLog the attributed string in each case - it is exactly the same - so it appears to be a change to the rendering engine on 10.12. – MichaelR Dec 20 '16 at 08:40
  • macOS 10.12.1 works ok. – Willeke Dec 24 '16 at 01:12
  • Thanks @Willeke, I'm seeing the issue on 10.12.2 - maybe it is a very recent issue. Will also check 10.12.1 – MichaelR Dec 24 '16 at 10:41
  • Confirmed it it ok in 10.12.1 and not in 10.12.2. WIll update bug report to Apple. – MichaelR Dec 24 '16 at 20:06
  • @MichaelRourke I've see the same problem in my app. The tabbing style doesn't work in 10.12.2. – Harry Jan 04 '17 at 03:39

1 Answers1

3

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
Harry
  • 5,566
  • 6
  • 27
  • 21