diff --git a/Frameworks/BundleMenu/src/BundleItemMenuItem.h b/Frameworks/BundleMenu/src/BundleItemMenuItem.h new file mode 100644 index 000000000..79068cc61 --- /dev/null +++ b/Frameworks/BundleMenu/src/BundleItemMenuItem.h @@ -0,0 +1,16 @@ +#import + +struct BundleItemMenuItemAlignment +{ + BundleItemMenuItemAlignment () : maxAlignmentWidth(0), maxRightWidth(0) {} + CGFloat maxAlignmentWidth; + CGFloat maxRightWidth; +}; + +@interface BundleItemMenuItem : NSMenuItem +{ + BOOL hasRightPart; +} ++ (BundleItemMenuItem*)menuItemWithBundleItem:(bundles::item_ptr const&)bundleItem alignmentData:(BundleItemMenuItemAlignment&)alignment; +- (void)updateAlignment:(BundleItemMenuItemAlignment&)alignment; +@end diff --git a/Frameworks/BundleMenu/src/BundleItemMenuItem.mm b/Frameworks/BundleMenu/src/BundleItemMenuItem.mm new file mode 100644 index 000000000..b107d70a0 --- /dev/null +++ b/Frameworks/BundleMenu/src/BundleItemMenuItem.mm @@ -0,0 +1,104 @@ +#import "BundleItemMenuItem.h" +#import +#import + +@interface BundleItemMenuItem () +- (BundleItemMenuItem*)initWithBundleItem:(bundles::item_ptr const&)bundleItem alignmentData:(BundleItemMenuItemAlignment&)alignment; +- (void)setAttributedTitleWithTitle:(NSAttributedString*)itemTitle equivLeft:(NSAttributedString*)equivLeft equivRight:(NSAttributedString*)equivRight alignmentData:(BundleItemMenuItemAlignment&)alignment; +@end + +@implementation BundleItemMenuItem ++ (BundleItemMenuItem*)menuItemWithBundleItem:(bundles::item_ptr const&)bundleItem alignmentData:(BundleItemMenuItemAlignment&)alignment +{ + return [[[self alloc] initWithBundleItem:bundleItem alignmentData:alignment] autorelease]; +} + +- (BundleItemMenuItem*)initWithBundleItem:(bundles::item_ptr const&)bundleItem alignmentData:(BundleItemMenuItemAlignment&)alignment +{ + if ((self = [super init])) + { + NSDictionary* fontAttrs = @{ NSFontAttributeName : [NSFont menuFontOfSize:14] /* passing 0 should return the default size, but it doesn’t */ }; + NSDictionary* smallFontAttrs = @{ NSFontAttributeName : [NSFont menuFontOfSize:11] }; + NSAttributedString* title = [[NSAttributedString alloc] initWithString:[NSString stringWithCxxString:bundleItem->name()] attributes:fontAttrs]; + NSAttributedString* equivLeft = nil; + NSAttributedString* equivRight = nil; + + std::string const tabTrigger(bundleItem->value_for_field(bundles::kFieldTabTrigger)); + std::string const keyEquiv(bundleItem->value_for_field(bundles::kFieldKeyEquivalent)); + + if(tabTrigger != NULL_STR) + { + equivLeft = [[[NSAttributedString alloc] initWithString:[NSString stringWithCxxString:(" "+tabTrigger+"\u21E5 ")] attributes:smallFontAttrs] autorelease]; + } + else if(keyEquiv != NULL_STR) + { + size_t keyStart = 0; + std::string const glyphStr(ns::glyphs_for_event_string(keyEquiv, &keyStart)); + + equivLeft = [[[NSAttributedString alloc] initWithString:[NSString stringWithCxxString:glyphStr.substr(0, keyStart)] attributes:fontAttrs] autorelease]; + equivRight = [[[NSAttributedString alloc] initWithString:[NSString stringWithCxxString:glyphStr.substr(keyStart)] attributes:fontAttrs] autorelease]; + } + + [self setAttributedTitleWithTitle:title equivLeft:equivLeft equivRight:equivRight alignmentData:alignment]; + } + + return self; +} + +- (void)setAttributedTitleWithTitle:(NSAttributedString*)itemTitle equivLeft:(NSAttributedString*)equivLeft equivRight:(NSAttributedString*)equivRight alignmentData:(BundleItemMenuItemAlignment&)alignment +{ + NSMutableAttributedString* title = [[[NSMutableAttributedString alloc] initWithAttributedString:itemTitle] autorelease]; + [title beginEditing]; + + CGFloat alignmentWidth = [itemTitle size].width; + CGFloat rightWidth = [equivRight size].width; + CGFloat leftWidth = [equivLeft size].width; + + if(equivLeft) + { + [title appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\t"] autorelease]]; + [title appendAttributedString:equivLeft]; + + alignmentWidth += leftWidth + 20; + + if(equivRight) + { + [title appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\t"] autorelease]]; + [title appendAttributedString:equivRight]; + hasRightPart = YES; + } + } + + if(alignmentWidth > alignment.maxAlignmentWidth) + alignment.maxAlignmentWidth = alignmentWidth; + + if(rightWidth > alignment.maxRightWidth) + alignment.maxRightWidth = rightWidth; + + [title endEditing]; + [self setAttributedTitle:title]; +} + +- (void)updateAlignment:(BundleItemMenuItemAlignment&)alignment +{ + NSMutableParagraphStyle* pStyle = [[NSMutableParagraphStyle new] autorelease]; + if(hasRightPart) + { + [pStyle setTabStops:@[ + [[[NSTextTab alloc] initWithType:NSRightTabStopType location:alignment.maxAlignmentWidth] autorelease], + [[[NSTextTab alloc] initWithType:NSLeftTabStopType location:alignment.maxAlignmentWidth + 0.01] autorelease] + ]]; + } + else + { + [pStyle setTabStops:@[ + [[[NSTextTab alloc] initWithType:NSRightTabStopType location:alignment.maxAlignmentWidth + alignment.maxRightWidth] autorelease] + ]]; + } + + NSMutableAttributedString* title = [[self attributedTitle] mutableCopy]; + [title addAttribute:NSParagraphStyleAttributeName value:pStyle range:NSMakeRange(0, [title length])]; + + [self setAttributedTitle:title]; +} +@end diff --git a/Frameworks/BundleMenu/src/BundleMenuDelegate.mm b/Frameworks/BundleMenu/src/BundleMenuDelegate.mm index 1403b250b..3462b0977 100644 --- a/Frameworks/BundleMenu/src/BundleMenuDelegate.mm +++ b/Frameworks/BundleMenu/src/BundleMenuDelegate.mm @@ -1,4 +1,5 @@ #import "BundleMenuDelegate.h" +#import "BundleItemMenuItem.h" #import #import #import @@ -33,6 +34,9 @@ - (void)menuNeedsUpdate:(NSMenu*)aMenu D(DBF_BundleMenu, bug("\n");); [aMenu removeAllItems]; [subdelegates removeAllObjects]; + + BundleItemMenuItemAlignment alignmentData; + NSMutableArray* menuItems = [NSMutableArray array]; citerate(item, umbrellaItem->menu()) { @@ -56,14 +60,18 @@ - (void)menuNeedsUpdate:(NSMenu*)aMenu default: { - NSMenuItem* menuItem = [aMenu addItemWithTitle:[NSString stringWithCxxString:(*item)->name()] action:@selector(doBundleItem:) keyEquivalent:@""]; - [menuItem setKeyEquivalentCxxString:(*item)->value_for_field(bundles::kFieldKeyEquivalent)]; - [menuItem setTabTriggerCxxString:(*item)->value_for_field(bundles::kFieldTabTrigger)]; + BundleItemMenuItem* menuItem = [BundleItemMenuItem menuItemWithBundleItem:*item alignmentData:alignmentData]; [menuItem setRepresentedObject:[NSString stringWithCxxString:(*item)->uuid()]]; + [aMenu addItem:menuItem]; + + [menuItems addObject:menuItem]; } break; } } + + for(BundleItemMenuItem* menuItem in menuItems) + [menuItem updateAlignment:alignmentData]; } - (void)menuWillOpen:(NSMenu*)aMenu